#!/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/>."""
from math import exp
from lib.EoS.cubic import Cubic
[docs]
class SRK(Cubic):
r"""Equation of state of Soave-Redlich-Kwong (1972)
.. math::
\begin{array}[t]{l}
P = \frac{RT}{V-b}-\frac{a}{V\left(V+b\right)}\\
a = 0.42747\frac{R^2T_c^2}{P_c}\alpha\\
b = 0.08664\frac{RT_c}{P_c}\\
\alpha^{0.5} = 1 + m\left(1-Tr^{0.5}\right)\\
m = 0.48 + 1.574\omega - 0.176\omega^2\\
\end{array}
In supercritical states, the α temperature dependence can use different
extrapolation correlation:
* Boston-Mathias expression, [3]_
.. math::
\begin{array}[t]{l}
\alpha = \exp\left(c\left(1-T_r^d\right)\right)\\
d = 1+\frac{m}{2}\\
c = \frac{m}{d}\\
\end{array}
* Nasrifar-Bolland expression, [4]_
.. math::
\begin{array}[t]{l}
\alpha = \frac{b_1}{T_r} + \frac{b_2}{T_r^2} + \frac{b_3}{T_r^3}\\
b_1 = 0.25\left(12 - 11m + m^2\right)\\
b_2 = 0.5\left(-6 + 9m - m^2\right)\\
b_3 = 0.25\left(4 - 7m + m^2\right)\\
\end{array}
Parameters
----------
alpha : int
Correlation index for alpha expresion at supercritical temperatures:
* 0 - Original
* 1 - Boston
* 2 - Nasrifar
Examples
--------
Example 4.3 from [2]_, Propane saturated at 300K
>>> from lib.mezcla import Mezcla
>>> mix = Mezcla(5, ids=[4], caudalMolar=1, fraccionMolar=[1])
>>> eq = SRK(300, 9.9742e5, mix)
>>> '%0.1f' % (eq.Vl.ccmol)
'98.4'
>>> eq = SRK(300, 42.477e5, mix)
>>> '%0.1f' % (eq.Vg.ccmol)
'95.1'
Helmholtz energy formulation example for supplementary documentatión from
[4]_, the critical parameter are override for the valued used in paper to
get the values of test with high precision
>>> from lib.mezcla import Mezcla
>>> from lib import unidades
>>> from lib.compuestos import Componente
>>> ch4 = Componente(2)
>>> ch4.Tc, ch4.Pc, ch4.f_acent = 190.564, 4599200, 0.011
>>> o2 = Componente(47)
>>> o2.Tc, o2.Pc, o2.f_acent = 154.581, 5042800, 0.022
>>> ar = Componente(98)
>>> ar.Tc, ar.Pc, ar.f_acent = 150.687, 4863000, -0.002
>>> mix = Mezcla(5, customCmp=[ch4, o2, ar], caudalMolar=1,
... fraccionMolar=[0.5, 0.3, 0.2])
>>> eq = SRK(800, 36451227.52066596, mix, R=8.3144598)
>>> fir = eq._phir(800, 5000, eq.yi)
>>> delta = 5000
>>> tau = 1/800
>>> print("fir: %0.14f" % (fir["fir"]))
fir: 0.11586323513845
>>> print("fird: %0.14f" % (fir["fird"]*delta))
fird: 0.12741566551477
>>> print("firt: %0.15f" % (fir["firt"]*tau))
firt: -0.082603152680518
>>> print("firdd: %0.15f" % (fir["firdd"]*delta**2))
firdd: 0.024895937945147
>>> print("firdt: %0.15f" % (fir["firdt"]*delta*tau))
firdt: -0.077752734990782
>>> print("firtt: %0.14f" % (fir["firtt"]*tau**2))
firtt: -0.10404751064185
>>> print("firddd: %0.16f" % (fir["firddd"]*delta**3))
firddd: 0.0060986538256190
>>> print("firddt: %0.16f" % (fir["firddt"]*delta**2*tau))
firddt: 0.0089488831000362
>>> print("firdtt: %0.15f" % (fir["firdtt"]*delta*tau**2))
firdtt: -0.097937890490398
>>> print("firttt: %0.14f" % (fir["firttt"]*tau**3))
firttt: 0.15607126596277
"""
__title__ = "Soave-Redlich-Kwong (1972)"
__status__ = "SRK72"
__doi__ = (
{"autor": "Soave, G.",
"title": "Equilibrium Constants from a modified Redlich-Kwong "
"Equation of State",
"ref": "Chem. Eng. Sci. 27 (1972) 1197-1203",
"doi": "10.1016/0009-2509(72)80096-4"},
{"autor": "Poling, B.E, Prausnitz, J.M, O'Connell, J.P",
"title": "The Properties of Gases and Liquids 5th Edition",
"ref": "McGraw-Hill, New York, 2001",
"doi": ""},
{"autor": "Boston, J.F., Mathias, P.M.",
"title": "Phase Equilibria in a Third-Generation Process Simulator",
"ref": "Presented at: 'Phase Equilibria and Fluid Properties in the "
"Chemical Industries', Berlin, March 17-21, 1980.",
"doi": ""},
{"autor": "Nasrifar, Kh., Bolland, O.",
"title": "Square-Well Potential and a New α Function for the Soave-"
"Redlich-Kwong Equation of State",
"ref": "Ind. Eng. Chem. Res. 43(21) (2004) 6901-6909",
"doi": "10.1021/ie049545i"})
[docs]
def _cubicDefinition(self, T):
"""Definition of coefficients for generic cubic equation of state"""
# Schmidt-Wenzel factorization of terms
self.u = 1
self.w = 0
ao = []
ai = []
bi = []
mi = []
for cmp in self.componente:
a0, b = self._lib(cmp)
alfa = self._alfa(cmp, T)
m = self._m(cmp)
ao.append(a0)
ai.append(a0*alfa)
bi.append(b)
mi.append(m)
self.ao = ao
self.ai = ai
self.bi = bi
self.mi = mi
[docs]
def _lib(self, cmp):
ao = 0.42747*self.R**2*cmp.Tc**2/cmp.Pc # Eq 5
b = 0.08664*self.R*cmp.Tc/cmp.Pc # Eq 6
return ao, b
[docs]
def _GEOS(self, xi):
am, bm = self._mixture("SRK", xi, [self.ai, self.bi])
delta = bm
epsilon = 0
return am, bm, delta, epsilon
[docs]
def _alfa(self, cmp, T):
"""α parameter calculation procedure, separate of general procedure
to let define derived equation where only change this term.
This method use the original alpha formulation for temperatures below
the critical temperature and can choose by configuration between:
* Boston-Mathias formulation
* Nasrifar-Bolland formulation
Parameters
----------
cmp : componente.Componente
Componente instance
T : float
Temperature, [K]
Returns
-------
alpha : float
alpha parameter of equation, [-]
"""
Tr = T/cmp.Tc
m = self._m(cmp)
if Tr > 1:
alfa = self.kwargs.get("alpha", 0)
if alfa == 0:
alfa = (1+m*(1-Tr**0.5))**2 # Eq 13
elif alfa == 1:
# Use the Boston-Mathias supercritical extrapolation, ref [3]_
d = 1+m/2 # Eq 10
c = m/d # Eq 11
alfa = exp(c*(1-Tr**d)) # Eq 9
elif alfa == 2:
# Use the Nasrifar-Bolland supercritical extrapolation, ref [4]
b1 = 0.25*(12-11*m+m**2) # Eq 17
b2 = 0.5*(-6+9*m-m**2) # Eq 18
b3 = 0.25*(4-7*m+m**2) # Eq 19
alfa = b1/Tr + b2/Tr**2 + b3/Tr**3 # Eq 16
else:
alfa = (1+m*(1-Tr**0.5))**2 # Eq 13
return alfa
[docs]
def _m(self, cmp):
"""Calculate the intermediate parameter for alpha expression"""
# Eq 15
return 0.48 + 1.574*cmp.f_acent - 0.176*cmp.f_acent**2
[docs]
def _da(self, tau, x):
"""Calculate the derivatives of α, this procedure is used for Helmholtz
energy formulation of EoS for calculation of properties, alternate alfa
formulation must define this procedure for any change of formulation
"""
Tr, rhor = self._Tr()
# Eq 64-67
Di = []
Dt = []
Dtt = []
Dttt = []
for cmp in self.componente:
Di.append(1-(Tr/cmp.Tc)**0.5/tau**0.5)
Dt.append((Tr/cmp.Tc)**0.5/2/tau**1.5)
Dtt.append(-3*(Tr/cmp.Tc)**0.5/4/tau**2.5)
Dttt.append(15*(Tr/cmp.Tc)**0.5/8/tau**3.5)
# Eq 63
Bi = []
for c1, d in zip(self.mi, Di):
Bi.append(1+c1*d)
# Eq 69-71
Bt = []
Btt = []
Bttt = []
for c1, d, dt, dtt, dttt in zip(self.mi, Di, Dt, Dtt, Dttt):
Bt.append(c1*dt)
Btt.append(c1*d*dtt*d**-1)
Bttt.append(c1*d**2*dttt*d**-2)
# Eq 73-75
dait = []
daitt = []
daittt = []
for a, B, bt, btt, bttt in zip(self.ao, Bi, Bt, Btt, Bttt):
dait.append(2*a*B*bt)
daitt.append(2*a*(B*btt+bt**2))
daittt.append(2*a*(B*bttt+3*bt*btt))
# Eq 52
uij = []
for aii in self.ai:
uiji = []
for ajj in self.ai:
uiji.append(aii*ajj)
uij.append(uiji)
# Eq 59-61
duijt = []
duijtt = []
duijttt = []
for aii, diit, diitt, diittt in zip(self.ai, dait, daitt, daittt):
duijit = []
duijitt = []
duijittt = []
for ajj, djjt, djjtt, djjttt in zip(self.ai, dait, daitt, daittt):
duijit.append(aii*djjt + ajj*diit)
duijitt.append(aii*djjtt + 2*diit*djjt + ajj*diitt)
duijittt.append(
aii*djjttt + 3*diit*djjtt + 3*diitt*djjt + ajj*diittt)
duijt.append(duijit)
duijtt.append(duijitt)
duijttt.append(duijittt)
# Eq 54-56
daijt = []
daijtt = []
daijttt = []
for uiji, duijit, duijitt, duijittt, kiji in zip(
uij, duijt, duijtt, duijttt, self.kij):
daijit = []
daijitt = []
daijittt = []
for u, ut, utt, uttt, k in zip(
uiji, duijit, duijitt, duijittt, kiji):
daijit.append((1-k)/2/u**0.5*ut)
daijitt.append((1-k)/4/u**1.5*(2*u*utt-ut**2))
daijittt.append(
(1-k)/8/u**2.5*(4*u**2*uttt - 6*u*ut*utt + 3*ut**3))
daijt.append(daijit)
daijtt.append(daijitt)
daijttt.append(daijittt)
# Eq 51
damt = 0
damtt = 0
damttt = 0
for xi, daijit, daijitt, daijittt in zip(x, daijt, daijtt, daijttt):
for xj, dat, datt, dattt in zip(x, daijit, daijitt, daijittt):
damt += xi*xj*dat
damtt += xi*xj*datt
damttt += xi*xj*dattt
# Eq 126
aij = []
for a_i in self.ai:
aiji = []
for a_j in self.ai:
aiji.append((a_i*a_j)**0.5)
aij.append(aiji)
daxi = []
for i, (xi, aiji) in enumerate(zip(x, aij)):
daxij = 0
for xj, a in zip(x, aiji):
daxij += 2*xj*a
daxi.append(daxij)
kw = {}
kw["dat"] = damt
kw["datt"] = damtt
kw["dattt"] = damttt
kw["daxi"] = daxi
return kw
if __name__ == "__main__":
from lib.mezcla import Mezcla
from lib import unidades
# # mix = Mezcla(5, ids=[4], caudalMolar=1, fraccionMolar=[1])
# # eq = SRK(300, 9.9742e5, mix, alpha=1)
# # print('%0.1f' % (eq.Vl.ccmol))
# # eq = SRK(300, 42.477e5, mix)
# # print('%0.1f' % (eq.Vg.ccmol))
# mix = Mezcla(5, ids=[46, 2], caudalMolar=1, fraccionMolar=[0.2152, 0.7848])
# eq = SRK(144.26, 2.0684e6, mix)
# print(eq.rhoL.kmolm3)
# # Ejemplo 6.6, Wallas, pag 340
# mezcla = Mezcla(2, ids=[1, 2, 40, 41], caudalUnitarioMolar=[0.3177, 0.5894, 0.0715, 0.0214])
# P = unidades.Pressure(500, "psi")
# T = unidades.Temperature(120, "F")
# eq = SRK(T, P, mezcla)
# print(T)
# print(eq.x)
# print([x*(1-eq.x)*5597 for x in eq.xi])
# print([y*eq.x*5597 for y in eq.yi])
# print(eq.Ki)
# Example 6.6 wallas
# P = unidades.Pressure(20, "atm")
# mix = Mezcla(5, ids=[23, 5], caudalMolar=1, fraccionMolar=[0.607, 0.393])
# eq1 = SRK(300, P, mix)
# eq2 = SRK(400, P, mix)
# print(eq1._Dew_T(P))
# print(eq2._Dew_T(P))
# eq = SRK(500, P, mezcla)
# print(eq._Dew_T(P))
# Example 2.3, pag 27 Separation Process Principles, Seader, Henley
import numpy as np
from lib.EoS.Cubic.PR import PR
T = unidades.Temperature(120, "F")
P = unidades.Pressure(485, "psi")
mix = Mezcla(5, caudalMolar=5597, ids=[1, 2, 40, 41],
fraccionMolar=[0.3177, 0.5894, 0.0715, 0.0214])
st = SRK(T, P, mix, alpha=1)
st2 = PR(T, P, mix, alpha=1)
print(st.x*5597, st2.x*5597)
print(np.r_[st.yi]*st.x*5597)
print(np.r_[st.xi]*(1-st.x)*5597)
print(st.Ki, st2.Ki)