Delete preos.py
Browse files
preos.py
DELETED
|
@@ -1,225 +0,0 @@
|
|
| 1 |
-
import numpy as np
|
| 2 |
-
import matplotlib.pyplot as plt
|
| 3 |
-
from scipy.optimize import newton
|
| 4 |
-
|
| 5 |
-
R = 8.314e-5 # universal gas constant, m3-bar/K-mol
|
| 6 |
-
class Molecule:
|
| 7 |
-
"""
|
| 8 |
-
Store molecule info here
|
| 9 |
-
"""
|
| 10 |
-
def __init__(self, name, Tc, Pc, omega):
|
| 11 |
-
"""
|
| 12 |
-
Pass parameters desribing molecules
|
| 13 |
-
"""
|
| 14 |
-
#! name
|
| 15 |
-
self.name = name
|
| 16 |
-
#! Critical temperature (K)
|
| 17 |
-
self.Tc = Tc
|
| 18 |
-
#! Critical pressure (bar)
|
| 19 |
-
self.Pc = Pc
|
| 20 |
-
#! Accentric factor
|
| 21 |
-
self.omega = omega
|
| 22 |
-
|
| 23 |
-
def print_params(self):
|
| 24 |
-
"""
|
| 25 |
-
Print molecule parameters.
|
| 26 |
-
"""
|
| 27 |
-
print("""Molecule: %s.
|
| 28 |
-
\tCritical Temperature = %.1f K
|
| 29 |
-
\tCritical Pressure = %.1f bar.
|
| 30 |
-
\tAccentric factor = %f""" % (self.name, self.Tc, self.Pc, self.omega))
|
| 31 |
-
|
| 32 |
-
def preos(molecule, T, P, plotcubic=True, printresults=True):
|
| 33 |
-
"""
|
| 34 |
-
Peng-Robinson equation of state (PREOS)
|
| 35 |
-
http://en.wikipedia.org/wiki/Equation_of_state#Peng.E2.80.93Robinson_equation_of_state
|
| 36 |
-
:param molecule: Molecule molecule of interest
|
| 37 |
-
:param T: float temperature in Kelvin
|
| 38 |
-
:param P: float pressure in bar
|
| 39 |
-
:param plotcubic: bool plot cubic polynomial in compressibility factor
|
| 40 |
-
:param printresults: bool print off properties
|
| 41 |
-
|
| 42 |
-
Returns a Dict() of molecule properties at this T and P.
|
| 43 |
-
"""
|
| 44 |
-
# build params in PREOS
|
| 45 |
-
Pr = P/molecule.Pc
|
| 46 |
-
Tr = T / molecule.Tc # reduced temperature
|
| 47 |
-
a = 0.457235 * R**2 * molecule.Tc**2 / molecule.Pc
|
| 48 |
-
b = 0.0777961 * R * molecule.Tc / molecule.Pc
|
| 49 |
-
kappa = 0.37464 + 1.54226 * molecule.omega - 0.26992 * molecule.omega**2
|
| 50 |
-
#kappa = 0.378893 + 1.4897153*molecule.omega - 0.17131848*molecule.omega**2 + 0.0196554*molecule.omega**3
|
| 51 |
-
alpha = (1 + kappa * (1 - np.sqrt(Tr)))**2
|
| 52 |
-
|
| 53 |
-
A = a * alpha * P / R**2 / T**2
|
| 54 |
-
B = b * P / R / T
|
| 55 |
-
|
| 56 |
-
# build cubic polynomial
|
| 57 |
-
def g(z):
|
| 58 |
-
"""
|
| 59 |
-
Cubic polynomial in z from EOS. This should be zero.
|
| 60 |
-
:param z: float compressibility factor
|
| 61 |
-
"""
|
| 62 |
-
return z**3 - (1 - B) * z**2 + (A - 2*B - 3*B**2) * z - (
|
| 63 |
-
A * B - B**2 - B**3)
|
| 64 |
-
|
| 65 |
-
# Solve cubic polynomial for the compressibility factor
|
| 66 |
-
z = newton(g, 1.0) # compressibility factor
|
| 67 |
-
rho = P / (R * T * z) # density
|
| 68 |
-
fugacity_coeff_PengRobin = np.exp(z - 1 - np.log(z - B) - A / np.sqrt(8) / B * np.log((z + (1 + np.sqrt(2)) * B) / (z + (1 - np.sqrt(2)) * B)))
|
| 69 |
-
#R = 8.314
|
| 70 |
-
def reduce_func(Vr):
|
| 71 |
-
#return Vr**3 - (1/3 + 8/3 * Tr/Pr)*(Vr**2) + 3*Vr/Pr - 1/Pr
|
| 72 |
-
return (Pr + 3/(Vr**2))*(3*Vr - 1) - 8*Tr
|
| 73 |
-
Vr = newton(reduce_func, 10)
|
| 74 |
-
#z = (Vr / (Vr - 1/3)) - 9 / (8*Vr*Tr)
|
| 75 |
-
Vm = z*R*T / P
|
| 76 |
-
a = (27*(R*molecule.Tc)**2) / (64*molecule.Pc)
|
| 77 |
-
b = (R*molecule.Tc) / (8*molecule.Pc)
|
| 78 |
-
|
| 79 |
-
# fugacity coefficient comes from an integration
|
| 80 |
-
fugacity_coeff_vander = np.exp(b / (Vm - b) - 2*a / (Vm*R*T) - np.log(1 - a*(Vm - b) / (R*T*(Vm**2))))
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
if printresults:
|
| 84 |
-
print("""PREOS calculation at
|
| 85 |
-
\t T = %.2f K
|
| 86 |
-
\t P = %.2f bar""" % (T, P))
|
| 87 |
-
print("\tCompressibility factor : ", z)
|
| 88 |
-
print("\tFugacity coefficient: ", fugacity_coeff)
|
| 89 |
-
print("\tFugacity at pressure %.3f bar = %.3f bar" % (
|
| 90 |
-
P, fugacity_coeff * P))
|
| 91 |
-
print("\tDensity: %f mol/m3" % rho)
|
| 92 |
-
print("\tMolar volume: %f L/mol" % (1.0 / rho * 1000))
|
| 93 |
-
print("\tDensity: %f v STP/v" % (rho * 22.4 / 1000))
|
| 94 |
-
print("\tDensity of ideal gas at same conditions: %f v STP/v" % (
|
| 95 |
-
rho * 22.4/ 1000 * z))
|
| 96 |
-
|
| 97 |
-
if plotcubic:
|
| 98 |
-
# Plot the cubic equation to visualize the roots
|
| 99 |
-
zz = np.linspace(0, 1.5) # array for plotting
|
| 100 |
-
|
| 101 |
-
plt.figure()
|
| 102 |
-
plt.plot(zz, g(zz), color='k')
|
| 103 |
-
plt.xlabel('Compressibility, $z$')
|
| 104 |
-
plt.ylabel('Cubic $g(z)$')
|
| 105 |
-
plt.axvline(x=z)
|
| 106 |
-
plt.axhline(y=0)
|
| 107 |
-
plt.title('Root found @ z = %.2f' % z)
|
| 108 |
-
plt.show()
|
| 109 |
-
return {"density(mol/m3)": rho, "fugacity_coefficient_peng": fugacity_coeff_PengRobin,
|
| 110 |
-
"fugacity_coefficient_van": fugacity_coeff_vander,
|
| 111 |
-
"compressibility_factor": z, "fugacity(bar)": fugacity_coeff_PengRobin * P,
|
| 112 |
-
"molar_volume(L/mol)": 1.0 / rho * 1000.0}
|
| 113 |
-
|
| 114 |
-
def preos_reverse(molecule, T, f, plotcubic=False, printresults=True):
|
| 115 |
-
"""
|
| 116 |
-
Reverse Peng-Robinson equation of state (PREOS) to obtain pressure for a particular fugacity
|
| 117 |
-
:param molecule: Molecule molecule of interest
|
| 118 |
-
:param T: float temperature in Kelvin
|
| 119 |
-
:param f: float fugacity in bar
|
| 120 |
-
:param plotcubic: bool plot cubic polynomial in compressibility factor
|
| 121 |
-
:param printresults: bool print off properties
|
| 122 |
-
|
| 123 |
-
Returns a Dict() of molecule properties at this T and f.
|
| 124 |
-
"""
|
| 125 |
-
# build function to minimize: difference between desired fugacity and that obtained from preos
|
| 126 |
-
def g(P):
|
| 127 |
-
"""
|
| 128 |
-
:param P: pressure
|
| 129 |
-
"""
|
| 130 |
-
return (f - preos(molecule, T, P, plotcubic=False, printresults=False)["fugacity(bar)"])
|
| 131 |
-
|
| 132 |
-
# Solve preos for the pressure
|
| 133 |
-
P = newton(g, f) # pressure
|
| 134 |
-
|
| 135 |
-
# Obtain remaining parameters
|
| 136 |
-
pars = preos(molecule, T, P, plotcubic=plotcubic, printresults=printresults)
|
| 137 |
-
rho = pars["density(mol/m3)"]
|
| 138 |
-
fugacity_coeff = pars["fugacity_coefficient"]
|
| 139 |
-
z = pars["compressibility_factor"]
|
| 140 |
-
|
| 141 |
-
return {"density(mol/m3)": rho, "fugacity_coefficient": fugacity_coeff,
|
| 142 |
-
"compressibility_factor": z, "pressure(bar)": P,
|
| 143 |
-
"molar_volume(L/mol)": 1.0 / rho * 1000.0}
|
| 144 |
-
|
| 145 |
-
# TODO: Implement mixture in object-oriented way as well
|
| 146 |
-
def preos_mixture(molecule_a, molecule_b, delta, T, P_total, x, plotcubic=True, printresults=True):
|
| 147 |
-
"""
|
| 148 |
-
Peng-Robinson equation of state (PREOS) for a binary mixture
|
| 149 |
-
http://en.wikipedia.org/wiki/Equation_of_state#Peng.E2.80.93Robinson_equation_of_state
|
| 150 |
-
:param molecule_a: Molecule molecule 1 of interest
|
| 151 |
-
:param molecule_b: Molecule molecule 2 of interest
|
| 152 |
-
:param delta: binary interaction parameter between molecules a and b
|
| 153 |
-
:param T: float temperature in Kelvin
|
| 154 |
-
:param P_total: float total pressure in bar
|
| 155 |
-
:param x: array mole fractions
|
| 156 |
-
:param plotcubic: bool plot cubic polynomial in compressibility factor
|
| 157 |
-
:param printresults: bool print off properties
|
| 158 |
-
"""
|
| 159 |
-
# build arrays of properties
|
| 160 |
-
Tc = np.array([molecule_a.Tc, molecule_b.Tc])
|
| 161 |
-
Pc = np.array([molecule_a.Pc, molecule_b.Pc])
|
| 162 |
-
omega = np.array([molecule_a.omega, molecule_b.omega])
|
| 163 |
-
|
| 164 |
-
# build params in PREOS
|
| 165 |
-
Tr = T / Tc # reduced temperature
|
| 166 |
-
a0 = 0.457235 * R**2 * Tc**2 / Pc
|
| 167 |
-
b = 0.0777961 * R * Tc / Pc
|
| 168 |
-
kappa = 0.37464 + 1.54226 * omega - 0.26992 * omega**2
|
| 169 |
-
a = a0 * (1 + kappa * (1 - np.sqrt(Tr)))**2
|
| 170 |
-
|
| 171 |
-
# apply mixing rules
|
| 172 |
-
aij = (1.0 - delta) * np.sqrt(a[0] * a[1])
|
| 173 |
-
a_mix = a[0] * x[0]**2 + a[1] * x[1]**2 + 2.0 * x[0] * x[1] * aij
|
| 174 |
-
b_mix = x[0] * b[0] + x[1] * b[1]
|
| 175 |
-
A = a_mix * P_total / R**2 / T**2
|
| 176 |
-
B = b_mix * P_total / R / T
|
| 177 |
-
|
| 178 |
-
# build cubic polynomial
|
| 179 |
-
def g(z):
|
| 180 |
-
"""
|
| 181 |
-
Cubic polynomial in z from EOS. This should be zero.
|
| 182 |
-
:param z: float compressibility factor
|
| 183 |
-
"""
|
| 184 |
-
return z**3 - (1 - B) * z**2 + (A - 2*B - 3*B**2) * z - (
|
| 185 |
-
A * B - B**2 - B**3)
|
| 186 |
-
|
| 187 |
-
# Solve cubic polynomial for the compressibility factor
|
| 188 |
-
z = newton(g, 1.0) # compressibility factor
|
| 189 |
-
rho = P_total / (R * T * z) # density
|
| 190 |
-
|
| 191 |
-
Lnfug_0 = -np.log(z - B) + (z - 1.0) * b[0] / b_mix - A / np.sqrt(8) / B * (2.0 / a_mix * (x[0] * a[0] + x[1] * aij) - b[0] / b_mix) *\
|
| 192 |
-
np.log((z + (1.0 + np.sqrt(2)) * B) / (z + (1.0 - np.sqrt(2)) * B))
|
| 193 |
-
Lnfug_1 = -np.log(z - B) + (z - 1.0) * b[1] / b_mix - A / np.sqrt(8) / B * (2.0 / a_mix * (x[1] * a[1] + x[0] * aij) - b[1] / b_mix) *\
|
| 194 |
-
np.log((z + (1.0 + np.sqrt(2)) * B) / (z + (1.0 - np.sqrt(2)) * B))
|
| 195 |
-
|
| 196 |
-
# fugacity coefficient comes from an integration
|
| 197 |
-
fugacity_coefs = np.exp(np.array([Lnfug_0, Lnfug_1]))
|
| 198 |
-
|
| 199 |
-
if printresults:
|
| 200 |
-
print("""PREOS calculation at
|
| 201 |
-
\t T = %.2f K
|
| 202 |
-
\t P, total = %.2f bar""" % (T, P_total))
|
| 203 |
-
print("\tDensity: %f mol/m3" % rho)
|
| 204 |
-
print("\tCompressibility factor : %f" % z)
|
| 205 |
-
print("Component 0, %s:" % molecule_a.name)
|
| 206 |
-
print("\tFugacity coefficient: %f" % fugacity_coefs[0])
|
| 207 |
-
print("\tFugacity: %f bar" % (fugacity_coefs[0] * x[0] * P_total))
|
| 208 |
-
print("Component 1, %s:" % molecule_b.name)
|
| 209 |
-
print("\tFugacity coefficient: %f" % fugacity_coefs[1])
|
| 210 |
-
print("\tFugacity: %f bar" % (fugacity_coefs[1] * x[1] * P_total))
|
| 211 |
-
|
| 212 |
-
if plotcubic:
|
| 213 |
-
# Plot the cubic equation to visualize the roots
|
| 214 |
-
zz = np.linspace(0, 1.5) # array for plotting
|
| 215 |
-
|
| 216 |
-
plt.figure()
|
| 217 |
-
plt.plot(zz, g(zz), color='k')
|
| 218 |
-
plt.xlabel('Compressibility, $z$')
|
| 219 |
-
plt.ylabel('Cubic $g(z)$')
|
| 220 |
-
plt.axvline(x=z)
|
| 221 |
-
plt.axhline(y=0)
|
| 222 |
-
plt.title('Root found @ z = %.2f' % z)
|
| 223 |
-
plt.show()
|
| 224 |
-
return {"density(mol/m3)": rho, "fugacity_coefficients": fugacity_coefs,
|
| 225 |
-
"compressibility_factor": z}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|