#!/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/>.
Petroleum fractions hypotethical pseudocomponent definition
:class:`Petroleo`: The main class with all integrated functionality
Correlation for calculation of properties:
* :func:`prop_Ahmed`
* :func:`prop_Riazi_Daubert_1980`
* :func:`prop_Riazi_Daubert`
* :func:`prop_Cavett`
* :func:`prop_Lee_Kesler`
* :func:`prop_Sim_Daubert`
* :func:`prop_Watansiri_Owens_Starling`
* :func:`prop_Rowe`
* :func:`prop_Standing`
* :func:`prop_Willman_Teja`
* :func:`prop_Magoulas_Tassios`
* :func:`prop_Tsonopoulos`
* :func:`prop_Twu`
* :func:`prop_Sancet`
* :func:`prop_Silva_Rodriguez`
* :func:`Tb_Soreide`
* :func:`vc_Hall_Yarborough`
* :func:`M_Goossens`
* :func:`w_Korsten`
* :func:`prop_Riazi`
* :func:`prop_Riazi_Alsahhaf`
* :func:`prop_Riazi_Alsahhaf_PNA`
Correlations for Zc calculations:
* :func:`Zc_Hougen`
* :func:`Zc_Reid`
* :func:`Zc_Salerno`
* :func:`Zc_Nath`
* :func:`Zc_Lee_Kesler`
Distillation curves interconversiono methods:
* :func:`D86_TBP_Riazi`
* :func:`D86_TBP_Daubert`
* :func:`SD_D86_Riazi`
* :func:`SD_D86_Daubert`
* :func:`D86_EFV`
* :func:`SD_TBP`
* :func:`D1160_TBP_10mmHg`
* :func:`Tb_Pressure`
* :func:`curve_Predicted`
* :func:`_Tb_Predicted`
Advanced petroleum fraction properties:
* :func:`PourPoint`
* :func:`AnilinePoint`
* :func:`SmokePoint`
* :func:`FreezingPoint`
* :func:`CloudPoint`
* :func:`CetaneIndex`
* :func:`H_Riazi`
* :func:`H_Goossens`
* :func:`H_ASTM`
* :func:`H_Jenkins_Walsh`
* :func:`viscoAPI`
* :func:`SUS`
* :func:`SFS`
* :func:`S_Riazi`
PNA decomposition procedures:
* :func:`PNA_Riazi`
* :func:`PNA_Peng_Robinson`
* :func:`PNA_Bergman`
* :func:`PNA_van_Nes`
'''
from configparser import ConfigParser
from numpy import array, exp, sqrt
from numpy.lib.scimath import log, log10
from numpy.linalg import solve
from scipy.interpolate import interp1d
from scipy.optimize import fsolve, leastsq, newton
from tools.qt import translate
from lib import unidades
from lib.physics import R_atml, R_Btu
from lib.newComponent import newComponente
from lib.config import conf_dir
from lib.compuestos import prop_Edmister
from lib.utilities import refDoc
__doi__ = {
1:
{"autor": "Katz, D.L., Firoozabadi, A.",
"title": "Predicting Phase Behavior of Condensate/Crude-oil Systems"
"Using Methane Interaction Coefficients",
"ref": "Journal of Petroleum Technology 30(11) (1978) 1649-1655",
"doi": "10.2118/6721-pa"},
2:
{"autor": "Ahmed, T., Cady, G., Story, A.",
"title": "A Generalized Correlation for Characterizing the"
"Hydrocarbon Heavy Fractions.",
"ref": "Paper SPE 14266, presented at the 60th Annual Technical"
"Conference of the Society of Petroleum Engineers, Las Vegas,"
"September 22–25, 1985.",
"doi": ""},
3:
{"autor": "Riazi, M.R., Daubert, T.E.",
"title": "Characterization Parameters for Petroleum Fractions",
"ref": "Ind. Eng. Chem. Res. 26(4) (1987) 755-759",
"doi": "10.1021/ie00064a023"},
4:
{"autor": "Riazi, M.R., Daubert, T.E.",
"title": "Simplify Property Predictions",
"ref": "Hydrocarbon Processing (March 1980): 115–116",
"doi": ""},
5:
{"autor": "Twu, C.H.",
"title": "An Internally Consistent Correlation for Predicting the"
"Critical Properties and Molecular Weights of Petroleum and"
"Coal-tar Liquids",
"ref": "Fluid Phase Equilbria 16 (1984) 137-150",
"doi": "10.1016/0378-3812(84)85027-x"},
6:
{"autor": "Sim, W.J., Daubert, T.E.",
"title": "Prediction of Vapor-Liquid Equilibria of Undefined"
"Mixtures",
"ref": "Ind. Eng. Chem. Process Des. Dev. 19(3) (1980) 386-393",
"doi": "10.1021/i260075a010"},
7:
{"autor": "Cavett, R.H.",
"title": "Physical data for distillation calculations, vapor-liquid"
"equilibrium.",
"ref": "Proceedings of the 27th Meeting, API, San Francisco, Issue 3,"
"351-366.",
"doi": ""},
8:
{"autor": "Kesler, M.G., Lee, B.I.",
"title": "Improve Prediction of Enthalpy of Fractions",
"ref": "Hydrocarbon Processing 55(3) (1976) 153-158",
"doi": ""},
9:
{"autor": "Ahmed, T.",
"title": "Equations of State and PVT Analysis: Applications for"
"Improved Reservoir Modeling, 2nd Edition",
"ref": "Gulf Professional Publishing, 2016, ISBN 9780128015704,",
"doi": "10.1016/B978-0-12-801570-4.00002-7"},
10:
{"autor": "Watansiri, S., Owens, V.H., Starling, K.E.",
"title": "Correlations for estimating critical constants, acentric"
"factor, and dipole moment for undefined coal-fluid"
"fractions",
"ref": "Ind. Eng. Chem. Process. Des. Dev. 24(2) (1985) 294-296",
"doi": "10.1021/i200029a013"},
11:
{"autor": "Rowe, A.M.",
"title": "Internally Consistent Correlations for Predicting Phase"
"Compositions for Use in Reservoir Compositional Simulators",
"ref": "Paper SPE 7475, In: Presented at the 53rd Annual Society of"
"Petroleum Engineers Fall Technical Conference and Exhibition,"
"1978.",
"doi": "10.2118/7475-MS"},
12:
{"autor": "Standing, M.B.",
"title": "Volumetric and Phase Behavior of Oil Field Hydrocarbon"
"Systems.",
"ref": "Society of Petroleum Engineers, Dallas, TX. 1977",
"doi": ""},
13:
{"autor": "Willman, B., Teja, A.",
"title": "Prediction of dew points of semicontinuous natural gas and"
"petroleum mixtures. 1. Characterization by use of an"
"effective carbon number and ideal solution predictions",
"ref": "Ind. Eng. Chem. Res. 26(5) (1987) 948-952",
"doi": "10.1021/ie00065a017"},
14:
{"autor": "Magoulas, S., Tassios, D.",
"title": "Predictions of phase behavior of HT-HP reservoir fluids.",
"ref": "Paper SPE 37294, Society of Petroleum Engineers, Richardson,"
"TX, 1990.",
"doi": ""},
15:
{"autor": "Sancet, J.,",
"title": "Heavy Faction C7+ Characterization for PR-EOS.",
"ref": "SPE 113025, 2007 SPE Annual Conference, November 11–14,"
"Anaheim, CA 2007.",
"doi": "10.2118/113026-stu"},
16:
{"autor": "Silva, M.B., Rodriguez, F.",
"title": "Automatic fitting of equations of state for phase behavior"
"matching.",
"ref": "Paper SPE 23703, Society of Petroleum Engineers, Richardson,"
"TX, 1992.",
"doi": "10.2118/23703-MS"},
17:
{"autor": "Soreide, I.",
"title": "Improved Phase Behavior Predictions of Petroleum Reservoir"
"Fluids From a Cubic Equation of State.",
"ref": "Doctor of engineering dissertation. Norwegian Institute of"
"Technology, Trondheim, 1989.",
"doi": ""},
18:
{"autor": "Hall, K.R., Yarborough, L.",
"title": "New Simple Correlation for Predicting Critical Volume",
"ref": "Chemical Engineering (November 1971): 76",
"doi": ""},
19:
{"autor": "Riazi, M.R., Daubert, T.E.",
"title": "Analytical Correlations Interconvert Distillation Curve "
"Types",
"ref": "Oil & Gas Journal 84 (1986) 50-57",
"doi": ""},
20:
{"autor": "API",
"title": "Technical Data book: Petroleum Refining 6th Edition",
"ref": "",
"doi": ""},
21:
{"autor": "Salerno, S, Cascella, M., May, D., Watson, P., Tassios, D.",
"title": "Prediction of Vapor Pressures and Saturated Volumes with a"
"Simple Cubic Equation of State: Part I. A Reliable Data"
"Base",
"ref": "Fluid Phase Equilibria 27 (1986) 15-34",
"doi": "10.1016/0378-3812(86)87038-8"},
22:
{"autor": "Hougen, O.A., Watson, K.M., Ragatz, R.A.",
"title": "Chemical Process Principles, 2nd ed.",
"ref": "New York: Wiley, 1959, p. 577.",
"doi": ""},
23:
{"autor": "Reid, R., Prausnitz, J.M., Sherwood, T.",
"title": "The Properties of Gases and Liquids, 3rd ed. New York:"
"McGraw-Hill, 1977, p. 21.",
"ref": "",
"doi": ""},
24:
{"autor": "Nath, J.",
"title": "Acentric Factor and the Critical Volumes for Normal Fluids",
"ref": "Ind. Eng. Chem. Fundam. 21(3) (1985) 325-326",
"doi": "10.1021/i100007a023"},
25:
{"autor": "Lee, B.I., Kesler, M.G.",
"title": "A Generalized Thermodynamic Correlation Based on "
"Three-Parameter Corresponding States",
"ref": "AIChE Journal 21(3) (1975) 510-527",
"doi": "10.1002/aic.690210313"},
26:
{"autor": "Riazi, M.R., Al-Sahhaf, T.A., Sl-Shammari M.A.",
"title": "A Generalized Method for Estimation of Critical Constants",
"ref": "Fluid Phase Equilibria 147 (1998) 1-6",
"doi": "10.1016/s0378-3812(98)00251-9"},
27:
{"autor": "Riazi, M.R., A1-Sahhaf, T.A.",
"title": "Physical Properties of Heavy Petroleum Fractions and Crude"
"Oils",
"ref": "Fluid Phase Equilibria 117 (1996) 217-224.",
"doi": "10.1016/s0378-3812(98)00251-9"},
28:
{"autor": "Riazi, M.R., A1-Sahhaf, T.",
"title": "Physical Properties of n-Alkanes and n-Alkyl Hydrocarbons: "
"Application to Petroleum Mixtures",
"ref": "Ind. Eng. Chem. Res. 34(11) (1995) 4145-4148",
"doi": "10.1021/ie00038a062"},
29:
{"autor": "Riazi, M. R.",
"title": "Characterization and Properties of Petroleum Fractions.",
"ref": "ASTM manual series MNL50, 2005",
"doi": ""},
30:
{"autor": "ASTM D2161-05",
"title": "Standard Practice for Conversion of Kinematic Viscosity to "
"Saybolt Universal Viscosity or to Saybolt Furol Viscosity",
"ref": "ASTM International, West Conshohocken, PA 2005, www.astm.org",
"doi": "10.1520/D2161-05"},
31:
{"autor": "Singh, B., Mutyala, S.R., Puttagunta, V.",
"title": "Viscosity range from one test",
"ref": "Hydrocarbon Processing 69 (1990) 39-41 ",
"doi": ""},
32:
{"autor": "Daubert, T.E.",
"title": "Petroleum Fraction Distillation Interconversion",
"ref": "Hydrocarbon Processing 73(9) (1994) 75-78",
"doi": ""},
33:
{"autor": "Edmister, W.C., Okamoto, K.K.",
"title": "Applied Hydrocarbon Thermodynamics, Part 13: Equilibrium "
"Flash Vaporization Correlations for Heavy Oils Under "
"Subatmospheric Pressures",
"ref": "Petroleum Refiner 38(9) (1959) 271-288",
"doi": ""},
34:
{"autor": "Riazi, M.R.",
"title": "Distribution Model for Properties of Hydrocarbon-Plus "
"Fractions",
"ref": "Ind. Eng. Chem. Res. 28(11) (1989) 1731-1735.",
"doi": "10.1021/ie00095a026"},
35:
{"autor": "Van Nes, K., Van Western, H.A.",
"title": "Aspects of the Constitution of Mineral Oils",
"ref": "Elsevier, New York, 1951",
"doi": ""},
36:
{"autor": "Ahmed, T.",
"title": "Hydrocarbon Phase Behavior",
"ref": "Gulf Publishing, Houston, TX, 1989.",
"doi": ""},
37:
{"autor": "Bergman, D.F., Tek, M.R., Katz, D.L.",
"title": "Retrograde Condensation in Natural Gas Pipelines",
"ref": "Project PR 2-29 of Pipelines Research Committee, AGA, January"
" 1977",
"doi": ""},
38:
{"autor": "Robinson, D.B., Peng, D.Y.",
"title": "The characterization of the heptanes and heavier fractions",
"ref": "Research Report 28. GPA, 1978. Tulsa, OK.",
"doi": ""},
39:
{"autor": "Riazi, M.R., Nasimi, N., Roomi, Y.",
"title": "Estimating Sulfur Content of Petroleum Products and Crude"
" Oils",
"ref": "Ind. Eng. Chem. Res. 38(11) (1999) 4507-4512",
"doi": "10.1021/ie990262d"},
40:
{"autor": "Goossens, A.G.",
"title": "Prediction of the Hydrogen Content of Petroleum Fractions",
"ref": "Ind. Eng. Chem. Res. 36(6) (1997) 2500-2504",
"doi": "10.1021/ie960772x"},
41:
{"autor": "Jenkins, G.I., Walsh, R.E",
"title": "Quick Measure of Jet Fuel Properties",
"ref": "Hydrocarbon Processing 47(5) (1968) 161-164",
"doi": ""},
42:
{"autor": "ASTM",
"title": "Annual Book of Standards",
"ref": "ASTM International, West Conshohocken, PA, 2002",
"doi": ""},
43:
{"autor": "Goossens, A.G.",
"title": "Prediction of Molecular Weight of Petroleum Fractions",
"ref": "Ind. Eng. Chem. Res. 35(3) (1996) 985-988",
"doi": "10.1021/ie950484l"},
44:
{"autor": "Korsten, H.",
"title": "Internally Consistent Prediction of Vapor Pressure and "
"Related Properties",
"ref": "Ind. Eng. Chem. Res. 39(3) (2000) 813-820",
"doi": "10.1021/ie990579d"},
45:
{"autor": "Tsonopoulos, C., Heidman, J.L., Hwang, S.C.",
"title": "Thermodynamic and Transport Properties of Coal Liquids",
"ref": "An Exxon Monograph, Wiley, New York, 1986",
"doi": ""},
}
[docs]
def _unit(key, val, unit=None):
"""Set appropiate unit for value
Parameters
----------
key : string
Property name
val : float
Property value to unitize
unit : string, optional
In case it necessary use a alternate unit
Returns
-------
x : unidades.unidad
A instance of appropiate unidades.unidad subclass
Notes
-----
Default use the petroleum english standards units, R, psi, ft³/lb...
"""
if key in ("Tc", "Tb"):
if unit is None:
unit = "R"
x = unidades.Temperature(val, unit)
elif key == "Pc":
if unit is None:
unit = "psi"
x = unidades.Pressure(val, unit)
elif key == "Vc":
if unit is None:
unit = "ft3lb"
x = unidades.SpecificVolume(val, unit)
else:
x = unidades.Dimensionless(val)
return x
# Generalized Correlations
[docs]
@refDoc(__doi__, [1, 2])
def prop_Ahmed(Nc):
"""Calculate petroleum fractions properties with the carbon atom number as
the only known property
Parameters
----------
Nc : float
Carbon atom number [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* M: Molecular weight, [-]
* Tc: Critic temperature, [ºR]
* Pc: Critic pressure, [psi]
* Tb: Normal boiling temperature, [ºR]
* w: Acentric factor, [-]
* SG: Specific gravity, [-]
* Vc: Critic volume, [ft³/lb]
Examples
--------
>>> "%0.0f" % prop_Ahmed(6)["Tb"].R
'604'
>>> "%0.5f" % prop_Ahmed(45)["Vc"].ft3lb
'0.06549'
"""
a1 = [-131.11375, 915.53747, 275.56275, 434.38878, -0.50862704,
0.86714949, 5.223458e-2]
a2 = [24.96156, 41.421337, -12.522269, 50.125279, 8.700211e-2,
3.41434080e-3, 7.87091369e-4]
a3 = [-0.34079022, -0.7586849, 0.29926384, -0.9097293, -1.8484814e-3,
-2.839627e-5, -1.9324432e-5]
a4 = [2.4941184e-3, 5.8675351e-3, -2.8452129e-3, 7.0280657e-3,
1.466389e-5, 2.4943308e-8, 1.7547264e-7]
a5 = [468.32575, -1.3028779e3, 1.7117226e3, -601.856510, 1.8518106,
-1.1627984, 4.4017952e-2]
prop = {}
for i, key in enumerate(["M", "Tc", "Pc", "Tb", "w", "SG", "Vc"]):
x = a1[i] + a2[i]*Nc + a3[i]*Nc**2 + a4[i]*Nc**3 + a5[i]/Nc
val = _unit(key, x)
prop[key] = val
return prop
[docs]
@refDoc(__doi__, [4, 9])
def prop_Riazi_Daubert_1980(Tb, SG):
"""Calculate petroleum fractions properties with the Riazi (1980)
correlation with the boiling temperature and specific gravity as input
paramters
Parameters
----------
Tb : float
Normal boiling temperature, [K]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* M: Molecular weight, [-]
* Tc: Critic temperature, [ºR]
* Pc: Critic pressure, [psi]
* Vc: Critic volume, [ft3/lb]
Examples
--------
Example 2.2 from [9]_: C7+ fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> p = prop_Riazi_Daubert_1980(T, 0.7365)
>>> "%.0f %.0f %.0f %.4f" % (p["M"], p["Tc"].R, p["Pc"].psi, p["Vc"].ft3lb)
'96 990 467 0.0623'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
a = [4.5673e-5, 24.2787, 3.12281e9, 7.5214e-3]
b = [2.1962, 0.58848, -2.3125, 0.2896]
c = [-1.0164, 0.3596, 2.3201, -0.7666]
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["SG"] = unidades.Dimensionless(SG)
for i, key in enumerate(["M", "Tc", "Pc", "Vc"]):
x = a[i]*Tb_R**b[i]*SG**c[i]
val = _unit(key, x)
prop[key] = val
return prop
[docs]
@refDoc(__doi__, [3, 9])
def prop_Riazi_Daubert(tita1, val1, tita2, val2):
"""Calculate petroleum fractions properties known two properties
Parameters
----------
tita1 : string
Name of first known property
tita2 : string
Name of second known property
val1: float
First known property value
val2: float
Second known property value
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Temperatura crítica, [ºR]
* Pc: Presión crítica, [psi]
* Vc: Volumen crítico, [ft³/lb]
* M: Peso molecular, [-]
* Tb: Temperatura fusión, [ºR]
* SG: Gravedad específica, [-]
* I: Huang characterization factor, [-]
* CH: Carbon/hydrogen weight ratio, [-]
Notes
-----
The available input properties for tita are:
* Tb: Temperatura fusión, [ºR]
* SG: Gravedad específica, [-]
* M: Peso molecular, [-]
* CH: Carbon/hydrogen weight ratio, [-]
* I: Huang characterization factor, [-]
* v1: Kinematic viscosity at 100ºF, [m²/s]
Raise :class:`NotImplementedError` if input pair are unsupported or input
isn't in limit:
* 80ºF ≤ T ≤ 650ºF
* 70 ≤ M ≤ 300
Examples
--------
Example 2.1 from [9]_: C7+ fraction with M=150 and SG=0.78
>>> p = prop_Riazi_Daubert("M", 150, "SG", 0.78)
>>> "%i %i %.4f %.0f" % (p["Tc"].R, p["Pc"].psi, p["Vc"].ft3lb, p["Tb"].R)
'1160 320 0.0636 825'
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> p = prop_Riazi_Daubert("Tb", T, "SG", 0.7365)
>>> "%.0f %.0f %.0f %.4f" % (p["M"], p["Tc"].R, p["Pc"].psi, p["Vc"].ft3lb)
'97 986 466 0.0626'
>>> "%.3f" % prop_Edmister(Tc=p["Tc"], Pc=p["Pc"], Tb=p["Tb"])["w"]
'0.287'
"""
# Check correct input parameter
p1 = ("Tb", "M", "v1")
p2 = ("SG", "I", "CH")
if tita1 in p2 and tita2 in p1:
# Invert input parameters
tita1, tita2 = tita2, tita1
val1, val2 = val2, val1
if tita1 not in p1 or tita2 not in p2:
raise NotImplementedError(
translate("Petro", "Undefined input pair"))
if tita1 == "M" and (val1 < 70 or val1 > 300):
raise NotImplementedError(
translate("Petro", "Molecular weight input out of bounds"))
if tita1 == "Tb" and (val1 < 300 or val1 > 620):
raise NotImplementedError(
translate("Petro", "Boiling temperature input out of bounds"))
# Convert input Tb in Kelvin to Rankine to use in the correlation
if tita1 == "Tb":
val1 = unidades.K2R(val1)
par = {
# Table IV
"Tc": {
"Tb-SG": [10.6443, -5.1747e-4, -.54444, 3.5995e-4, .81067, .53691],
"Tb-I": [5.62596e5, -7.317e-4, -16.9097, 2.5131e-3, .6154, 4.3469],
"Tb-CH": [2.2452, 1.9152e-4, -0.06487, -6.0192e-4, 0.7699, 0.900],
"M-SG": [554.4, -1.3478e-4, -0.61641, 0.0, 0.2998, 1.0555],
"M-I": [2.4254e6, 2.001e-4, -13.049, 0.0, 0.2383, 4.0642],
"M-CH": [37.332, 1.3848e-3, -0.1379, -2.7e-4, 0.3526, 1.4191],
"v1-SG": [251.026, -3.177e-2, 1.6587, 0.0, 0.1958, -0.9431],
"v1-I": [4.414e3, -0.0291, -1.2664, 0.0, 0.1884, 0.7492],
"v1-CH": [4.939e2, -2.8e-2, -8.91e-2, 0.0, 0.1928, 0.7744]},
# Table V
"Pc": {
"Tb-SG": [6.162e6, -4.725e-3, -4.8014, 3.1939e-3, -0.4844, 4.0846],
"Tb-I": [2.2337e25, -6.7041e-3, -74.5612, .019, -1.0303, 18.43302],
"Tb-CH": [158.96, -2.1357e-3, -0.3454, 0.0, -0.1801, 3.2223],
"M-SG": [4.5203e4, -1.8078e-3, -0.3084, 0.0, -0.8063, 1.6015],
"M-I": [2.9384e17, -0.01415, -48.5809, 0.0451, -0.8097, 12.9148],
"M-CH": [815.99, -2.139e-3, -0.265, 0.0, -0.6616, 2.4004],
"v1-SG": [1.271e5, -0.2523, -5.6028, 0.355, -0.5913, 6.0793],
"v1-I": [6.1475e22, -0.4586, -71.905, 1.8854, -0.6395, 20.7032],
"v1-CH": [40.9115, 0.01906, 0.1323, 0.0, 0.471, 1.6306]},
# Table VI
"Vc": {
"Tb-SG": [6.233e-4, -1.4679e-3, -.26404, 1.095e-3, .7506, -1.2028],
"Tb-I": [1.3077e-3, -1.799e-3, -3.5349, 4.425e-3, .7687, -.72011],
"Tb-CH": [0.2048, -9.2189e-4, 0.05345, 1.4805e-4, 0.1657, -1.4439],
"M-SG": [1.206e-2, -2.657e-3, 0.5287, 2.6012e-3, 0.20378, -1.3036],
"M-I": [1.016e-6, -2.0208e-3, 14.1853, 4.5318e-3, .2556, -4.60413],
"M-CH": [0.2558, -2.3533e-3, 0.1082, 3.826e-4, 0.0706, -1.3362],
"v1-SG": [1.64424e-3, -2.04563e-1, 3.513392, 2.12365e-1, 1.19093e-1,
-3.801261],
"v1-I": [3.219523e-12, -1.63181e-1, 36.09011, .4608, .1417, -10.65067],
"v1-CH": [.245582, -.11261, .086387, .016031, .046004, -1.028488]},
# Table VII
"M": {
"Tb-SG": [581.96, 5.43076e-4, -9.53384, 1.11056e-3, 0.97476,
6.51274],
"Tb-I": [2.606e-6, 8.6574e-6, 4.2376, 0.0, 2.0935, -1.9985],
"Tb-CH": [3.06584e-3, 5.3305e-4, 7.9113e-2, -2.87657e1, 1.6736,
-0.68681],
"v1-SG": [1.51723e6, -0.195411, -9.63897, .16247, .56370, 6.89383],
"v1-I": [4.0e-9, -8.9854e-2, 38.106, 0.0, 0.6675, -10.6],
"v1-CH": [84.1505, -5.976e-2, -0.10741, 0.0, 0.5596, 0.65815],
"v1-v2": [288.916, 0.1380, -0.7311, -5.704e-3, 0.051, 0.8411]},
# Table VIII
"Tb": {
"M-SG": [6.77857, 3.77409e-3, 2.984036, -4.25288e-3,
4.01673e-1, -1.58262],
"M-I": [136.395, 0.0, 0.0, 0.0, 0.4748, 0.4283],
"M-CH": [36.45625, -1.57415e-4, -4.5707e-2, 9.22926e-6, 5.12976e-1,
4.72372e-1],
"v1-SG": [4.28375e3, -1.3051e-2, -1.68759, -2.1247e-2, 2.62914e-1,
1.34890],
"v1-I": [9.1133e-2, -6.5236e-2, 14.9371, 6.029e-2, .3228, -3.8798],
"v1-CH": [444.377, -3.8093e-2, -7.7305e-2, 0.0, 0.2899, 0.6056]},
# Table IX
"SG": {
"Tb-I": [6.9195, -2.33e-4, -23.5535, 2.2152e-3, 2.9806e7, -0.3418],
"Tb-CH": [7.3238e-1, -1.01845e-3, -8.1635e-2, 3.60649e-5,
1.69916e-3, 8.90041e-1],
"M-I": [6.3028, -1.588e-3, -20.594, 7.344e-3, 1.1284e6, -7.71e-2],
"M-CH": [9.19255e-1, -1.48844e-3, -7.925e-2, 4.921118e-5,
6.84403e-2, 2.89844e-1],
"v1-I": [8.04224, -6.1406e-2, -26.3934, .2533, 3.8083e7, -.02353],
"v1-CH": [1.17777, 0.02614, -0.10966, -5.654e-3, .18242, .05245]},
# Table X
"I": {
"Tb-SG": [0.022657, 3.9052e-4, 2.468316, -5.70425e-4, 5.7209e-2,
-0.719895],
"Tb-CH": [4.307e-3, -9.8747e-5, -6.0737e-2, -4.414e-5, 0.4470, 0.9896],
"M-SG": [0.422375, 3.18857e-4, -0.200996, -4.24514e-4,
-8.43271e-3, 1.117818],
"M-CH": [4.239e-2, -5.6946e-4, -6.836e-2, 0.0, 0.1656, 0.8291],
"v1-SG": [.26376, 1.7458e-2, .231043, -1.8441e-2, -1.1275e-2, .770779],
"v1-CH": [0.08716, 6.1396e-3, -7.019e-2, -2.5935e-3, .05166, .84599]},
# Table XI
"CH": {
"Tb-SG": [17.22022, 8.24983e-3, 16.9402, -6.93931e-3, -2.72522,
-6.79769],
"Tb-I": [1.8866e-12, 4.2873e-3, 71.6531, -0.0116, -1.3773, -13.6139],
"M-SG": [2.35475, 9.3485e-3, 4.74695, -8.01719e-3, -0.68418, -0.7682],
"M-I": [2.9004e-13, 7.8276e-3, 60.3484, -0.02445, -0.37884, -12.34051],
"v1-SG": [2.523e-12, .482811, 29.98797, -0.55768, -.146565, -20.31303],
"v1-I": [2.143e-12, 0.2832, 53.7316, -0.91085, -0.17158, -10.88065]}}
prop = {}
prop[tita1] = _unit(tita1, val1)
prop[tita2] = _unit(tita2, val2)
for key in par.keys():
if key not in (tita1, tita2):
a, b, c, d, e, f = par[key][f"{tita1}-{tita2}"]
x = a*val1**e*val2**f*exp(b*val1+c*val2+d*val1*val2) # Eq 3
val = _unit(key, x)
prop[key] = val
return prop
[docs]
@refDoc(__doi__, [7, 9])
def prop_Cavett(Tb, API):
"""Calculate petroleum fractions properties with the Cavett (1980)
correlation. Use API as a alternate input parameter to specific gravity
Parameters
----------
Tb : float
Normal boiling temperature, [K]
API : float
API gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [ªR]
* Pc: Critic pressure, [Pa]
Examples
--------
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> API = 141.5/0.7365-131.5
>>> p = prop_Cavett(T, API)
>>> "%.1f %.0f" % (p["Tc"].R, p["Pc"].psi)
'978.1 466'
"""
# Convert input Tb in Kelvin to Fahrenheit to use in the correlation
Tb_F = unidades.K2F(Tb)
a = [768.07121, 1.7133693, -0.0010834003, -0.0089212579, 0.38890584e-6,
0.5309492000e-5, 0.3271160000e-7]
Tc = a[0] + a[1]*Tb_F + a[2]*Tb_F**2 + a[3]*API*Tb_F + a[4]*Tb_F**3 + \
a[5]*API*Tb_F**2 + a[6]*API**2*Tb_F**2
b = [2.82904060, 0.94120109e-3, -0.30474749e-5, -0.20876110e-4,
0.15184103e-8, 0.11047899e-7, -0.48271599e-7, 0.13949619e-9]
Pc = 10**(b[0] + b[1]*Tb_F + b[2]*Tb_F**2 + b[3]*API*Tb_F + b[4]*Tb_F**3 +
b[5]*API*Tb_F**2+b[6]*API**2*Tb_F+b[7]*API**2*Tb_F**2)
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["API"] = unidades.Dimensionless(API)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
return prop
[docs]
@refDoc(__doi__, [8, 9])
def prop_Lee_Kesler(Tb, SG):
"""Calculate petroleum fractions properties with the Lee-Kesker (1976)
correlation. Use API as a alternate input parameter to specific gravity
Parameters
----------
Tb : float
Normal boiling temperature, [K]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [ªR]
* Pc: Critic pressure, [Pa]
* M: Molecular weight, [-]
* w: Acentric factor, [-]
Examples
--------
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> p = prop_Lee_Kesler(T, 0.7365)
>>> "%.0f %.0f %.1f %.3f" % (p["Tc"].R, p["Pc"].psi, p["M"], p["w"])
'981 470 98.6 0.306'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
Tc = 341.7+811.1*SG+(0.4244+0.1174*SG)*Tb_R+(0.4669-3.26238*SG)*1e5/Tb_R
Pc = exp(8.3634 - 0.0566/SG - (0.24244+2.2898/SG+0.11857/SG**2)*1e-3*Tb_R +
(1.4685+3.648/SG+0.47227/SG**2)*1e-7*Tb_R**2 -
(0.42019+1.6977/SG**2)*1e-10*Tb_R**3)
M = -12272.6 + 9486.4*SG + (4.6523-3.3287*SG)*Tb_R + \
(1-0.77084*SG-0.02058*SG**2)*(1.3437-720.79/Tb_R)*1e7/Tb_R + \
(1-0.80882*SG+0.02226*SG**2)*(1.8828-181.98/Tb_R)*1e12/Tb_R**3
Tr = Tb_R/Tc
Kw = Tb_R**(1./3)/SG
if Tr > 0.8:
w = -7.904+0.1352*Kw-0.007465*Kw**2+8359*Tr+(1.408-0.01063*Kw)/Tr
else:
w = (-log(Pc/14.7)-5.92714+6.09648/Tr+1.28862*log(Tr)-0.169347*Tr**6)/(
15.2518-15.6875/Tr-13.4721*log(Tr)+0.43577*Tr**6)
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["SG"] = unidades.Dimensionless(SG)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
prop["M"] = unidades.Dimensionless(M)
prop["w"] = unidades.Dimensionless(w)
return prop
[docs]
@refDoc(__doi__, [6, 9])
def prop_Sim_Daubert(Tb, SG):
"""Calculate petroleum fractions properties with the Sim-Daubert (1980)
computerized version of Winn (1957) graphical correlations
Parameters
----------
Tb : float
Normal boiling temperature, [K]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* M: Molecular weight, [-]
* Tc: Critic temperature, [ªR]
* Pc: Critic pressure, [Pa]
Examples
--------
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> p = prop_Sim_Daubert(T, 0.7365)
>>> "%.0f %.0f %.0f" % (p["Tc"].R, p["Pc"].psi, p["M"])
'979 479 96'
"""
M = 5.805e-5*Tb**2.3776/SG**0.9371 # Eq 3
Pc = 6.1483e12*Tb**-2.3177*SG**2.4853 # Eq 4
Tc = exp(4.2009*Tb**0.08615*SG**0.04614) # Eq 5
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["SG"] = unidades.Dimensionless(SG)
prop["M"] = unidades.Dimensionless(M)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc)
return prop
[docs]
@refDoc(__doi__, [10, 9])
def prop_Watansiri_Owens_Starling(Tb, SG, M):
"""Calculate petroleum fractions properties with the Watansiri-Owens-
Starling (1985) correlation using boiling temperature and molecular weight
as input parameters
Parameters
----------
Tb : float
Normal boiling temperature, [K]
SG: float
Specific gravity, [-]
M: float
Molecular weight, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [atm]
* Vc: Critic volume, [cm3/gr]
* w: Acentric factor, [-]
* Dm: Dipole moment, [Debye]
Examples
--------
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> T = unidades.Temperature(198, "F")
>>> p = prop_Watansiri_Owens_Starling(T, 0.7365, 96)
>>> "%.0f %.5f" % (p["Tc"].R, p["Vc"].ft3lb)
'980 0.06548'
"""
Tc = exp(-0.00093906*Tb + 0.03095*log(M) + 1.11067*log(Tb) +
M*(0.078154*SG**0.5 - 0.061061*SG**(1./3.) - 0.016943*SG)) # Eq 1
Vc = exp(80.4479 - 129.8038*SG + 63.175*SG**2 - 13.175*SG**3 +
1.10108*log(M) + 42.1958*log(SG)) # Eq 2
Pc = exp(3.95431 + 0.70682*(Tc/Vc)**0.8 - 4.84*M/Tc - 0.15919*Tb/M) # Eq 3
w = (0.92217e-3*Tb + 0.507288*Tb/M + 382.904/M + 0.242e-5*(Tb/SG)**2 -
0.2165e-4*Tb*M + 0.1261e-2*SG*M + 0.1265e-4*M**2 + 0.2016e-4*SG*M**2 -
80.6495*Tb**(1/3.)/M - 0.378e-2*Tb**(2/3.)/SG**2)*Tb/M # Eq 4
# Eq 6
HVNP = -10397.5 + 46.2681*Tb - 1373.91*Tb**0.5 + 4595.81*log(Tb)
u1 = (197.933/M + 0.039177*M)*Vc/Tc
u2 = 0.3185e-2*Vc + 0.956247e-2*Tb - 0.5479e-3*HVNP
u3 = -1.34634*w + 0.906609*log(w)
u4 = -4.85638 - 0.013548*M + 0.271949e-3*M**2 + 1.04024*log(M)
Dm = u1/u4 + u2*u3
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["M"] = unidades.Dimensionless(M)
prop["Tc"] = unidades.Temperature(Tc)
prop["Pc"] = unidades.Pressure(Pc, "atm")
prop["Vc"] = unidades.SpecificVolume(Vc/M, "ccg")
prop["w"] = unidades.Dimensionless(w)
prop["Dm"] = unidades.DipoleMoment(Dm, "Debye")
return prop
[docs]
@refDoc(__doi__, [11, 9])
def prop_Rowe(M):
"""Calculate petroleum fractions properties with the Rowe
correlations (1978) using only the molecular weight as input parameter
Parameters
----------
M: float
Molecular weight, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [R]
* Tb: Boiling temperature, [R]
* Pc: Critic pressure, [psi]
Examples
--------
Example 2.3 from [9]_: Petroleum fraction with M=216 and SG=0.8605
>>> p = prop_Rowe(216)
>>> "%.1f" % p["Tc"].R
'1279.8'
Notes
-----
Critical pressure examples in [9]_ don't get result, the equations isn't
equal in both references
"""
n = (M-2)/14 # Eq D1
Tc = (961-10**(2.95597-(0.090597*n**(2/3.))))*1.8 # Eq D2
Tb = 4.347e-4*Tc**2+265 # Eq D3
Y = -0.0134426826*n+0.6801481651 # Eq D4
C = 10**Y*1e5 # Eq D5
Pc = C/Tc # Eq D6
prop = {}
prop["M"] = unidades.Dimensionless(M)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Tb"] = unidades.Temperature(Tb, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
return prop
[docs]
@refDoc(__doi__, [12, 9])
def prop_Standing(M, SG):
"""Calculate petroleum fractions properties with the Standing (1977)
correlations based in the graphical plot of Mathews et al. (1942) using
molecular weight and specific gravity as input parameter
Parameters
----------
M: float
Molecular weight, [-]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [atm]
Examples
--------
Example 2.3 from [9]_: Petroleum fraction with M=216 and SG=0.8605
>>> p = prop_Standing(216, 0.8605)
>>> "%.1f %.0f" % (p["Tc"].R, p["Pc"].psi)
'1269.3 270'
"""
Tc = 608 + 364*log10(M-71.2) + (2450*log10(M)-3800)*log10(SG) # Eq 25
Pc = 1188 - 431*log10(M-61.1) + (2319-852*log10(M-53.7))*(SG-0.8) # Eq 26
prop = {}
prop["M"] = unidades.Dimensionless(M)
prop["SG"] = unidades.Dimensionless(SG)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
return prop
[docs]
@refDoc(__doi__, [13, 9])
def prop_Willman_Teja(Tb):
"""Calculate petroleum fractions properties with the Willman-Teja (1987)
correlations using only the boiling temperature as input parameter
Parameters
----------
Tb: float
Boiling temperature, [K]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [MPa]
* n: Carbon number, [-]
Examples
--------
Example 2.2 from [9]_: Petroleum fraction with Tb=198ºF and SG=0.7365
>>> Tb = unidades.Temperature(198, "F")
>>> p = prop_Willman_Teja(Tb)
>>> "%.0f %.0f" % (p["Tc"].R, p["Pc"].psi)
'977 442'
"""
# Eq 11
A = [95.50441892007, 3.742203001499, 2295.53031513, -1042.57256080,
-22.66229823925, -1660.893846582, 439.13226915]
def f(n):
return A[0] + A[1]*n + A[2]*n**0.667 + A[3]*n**0.5 + A[4]*log10(n) + \
A[5]*n**0.8 + A[6]*n**0.9 - Tb
n = fsolve(f, 10)
Tc = Tb*(1+1/(1.25127+0.137242*n)) # Eq 12
Pc = (2.33761+8.16448*n)/(0.873159+0.54285*n)**2 # Eq 13
prop = {}
prop["Tb"] = unidades.Dimensionless(Tb)
prop["n"] = unidades.Dimensionless(n)
prop["Tc"] = unidades.Temperature(Tc)
prop["Pc"] = unidades.Pressure(Pc, "MPa")
return prop
[docs]
@refDoc(__doi__, [9, 14])
def prop_Magoulas_Tassios(M, SG):
"""Calculate petroleum fractions properties with the Magoulas-Tassios(1990)
correlations using molecular weight and specific gravity as input parameter
Parameters
----------
M: float
Molecular weight, [-]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [MPa]
* w: Acentric factor, [-]
Examples
--------
Example 2.3 from [9]_: Petroleum fraction with M=216 and SG=0.8605
>>> p = prop_Magoulas_Tassios(216, 0.8605)
>>> "%.0f %.0f" % (p["Tc"].R, p["Pc"].psi)
'1317 273'
"""
Tc = -1247.4 + 0.792*M + 1971*SG - 27000./M + 707.4/SG
Pc = exp(0.01901 - 0.0048442*M + 0.13239*SG + 227./M - 1.1663/SG +
1.2702*log(M))
w = -0.64235 + 0.00014667*M + 0.021876*SG - 4.539/M + 0.21699*log(M)
prop = {}
prop["M"] = unidades.Dimensionless(M)
prop["SG"] = unidades.Dimensionless(SG)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
prop["w"] = unidades.Dimensionless(w)
return prop
[docs]
@refDoc(__doi__, [45])
def prop_Tsonopoulos(SG, Tb):
"""Calculate petroleum fractions properties with the Tsonopoulos (1990)
correlations using molecular weight and specific gravity as input parameter
Parameters
----------
SG: float
Specific gravity, [-]
Tb: float
Boiling temperature, [K]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [MPa]
"""
# TODO: Search reference
Tc = 10**(1.20016 - 0.61954*log10(Tb) + 0.48262*log10(SG) +
0.67365*log10(SG)**2)
Pc = 10**(7.37498 - 2.15833*log10(Tb) + 3.35417*log10(SG) +
5.64019*log10(SG)**2)
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["SG"] = unidades.Dimensionless(SG)
prop["Tc"] = unidades.Temperature(Tc)
prop["Pc"] = unidades.Pressure(Pc, "bar")
return prop
[docs]
@refDoc(__doi__, [5])
def prop_Twu(Tb, SG):
"""Calculate petroleum fractions properties with the Two (1983)
correlation with the boiling temperature and specific gravity as input
paramters
Parameters
----------
Tb : float
Normal boiling temperature, [K]
SG: float
Specific gravity, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* M: Molecular weight, [-]
* Tc: Critic temperature, [ºR]
* Pc: Critic pressure, [psi]
* Vc: Critic volume, [ft3/lb]
Examples
--------
>>> crit = prop_Twu(510, 1.097)
>>> "%.1f %.1f %.1f" % (crit["Tc"].R, crit["Pc"].psi, crit["M"])
'1380.3 556.8 130.4'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
Tco = Tb_R/(0.533272 + 0.191017e-3*Tb_R + 0.779681e-7*Tb_R**2 -
0.284376e-10*Tb_R**3 + 0.959468e28/Tb_R**13) # Eq 1
alfa = 1-Tb_R/Tco # Eq 5
Vco = (1-(0.419869 - 0.505839*alfa - 1.56436*alfa**3 -
9481.7*alfa**14))**-8 # Eq 2
SGo = 0.843593-0.128624*alfa-3.36159*alfa**3-13749.5*alfa**12 # Eq 3
Pco = (3.83354 + 1.19629*alfa**0.5 + 34.8888*alfa + 36.1952*alfa**2 +
104.193*alfa**4)**2 # Eq 8
# Eq 4
def f(M):
Tita = log(M)
return exp(5.71419 + 2.71579*Tita - 0.286590*Tita**2 - 39.8544/Tita -
0.122488/Tita**2) - 24.7522*Tita + 35.3155*Tita**2 - Tb_R
Moo = Tb_R/(10.44-0.0052*Tb_R)
Mo = newton(f, Moo)
DSGt = exp(5*(SGo-SG))-1 # Eq 13
ft = DSGt*(-0.362456/Tb_R**0.5+(.0398285-0.948125/Tb_R**0.5)*DSGt) # Eq 12
Tc = Tco*((1+2*ft)/(1-2*ft))**2 # Eq 11
DSGv = exp(4*(SGo**2-SG**2))-1 # Eq 16
fv = DSGv*(0.46659/Tb_R**0.5+(-0.182421+3.01721/Tb_R**0.5)*DSGv) # Eq 15
Vc = Vco*((1+2*fv)/(1-2*fv))**2 # Eq 14
DSGp = exp(0.5*(SGo-SG))-1 # Eq 19
fp = DSGp*(2.53262-46.1955/Tb_R**0.5-0.00127885*Tb_R + (
-11.4277+252.14/Tb_R**0.5+0.00230535*Tb_R)*DSGp) # Eq 18
Pc = Pco*Tc/Tco*Vco/Vc*((1+2*fp)/(1-2*fp))**2 # Eq 17
DSGm = exp(5*(SGo-SG))-1 # Eq 23
x = abs(0.012342-0.328086/Tb_R**0.5) # Eq 22
fm = DSGm*(x+(-0.0175691+0.193168/Tb_R**0.5)*DSGm) # Eq 21
M = exp(log(Mo)*((1+2*fm)/(1-2*fm))**2) # Eq 20
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["SG"] = unidades.Dimensionless(SG)
prop["M"] = unidades.Dimensionless(M)
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Pc"] = unidades.Pressure(Pc, "psi")
prop["Vc"] = unidades.SpecificVolume(Vc/M, "ft3lb")
return prop
[docs]
@refDoc(__doi__, [5, 9])
def prop_Sancet(M):
"""Calculate petroleum fractions properties with the Sancet (2007)
correlations using only the molecular weight as input parameter
Parameters
----------
M: float
Molecular weight, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [ºR]
* Pc: Critic pressure, [psi]
* Tb: Boiling temperature, [ºR]
Examples
--------
Example 2.1 from [9]_: C7+ fraction with M=150 and SG=0.78
>>> p = prop_Sancet(150)
>>> "%.0f %.0f %.0f" % (p["Tc"].R, p["Pc"].psi, p["Tb"].R)
'1133 297 828'
"""
Pc = 82.82 + 653*exp(-0.007427*M) # Eq 16
Tc = -778.5 + 383.5*log(M-4.075) # Eq 17
Tb = 194 + 0.001241*Tc**1.869 # Eq 18
prop = {}
prop["M"] = unidades.Dimensionless(M)
prop["Pc"] = unidades.Pressure(Pc, "psi")
prop["Tc"] = unidades.Temperature(Tc, "R")
prop["Tb"] = unidades.Temperature(Tb, "R")
return prop
[docs]
@refDoc(__doi__, [16, 9])
def prop_Silva_Rodriguez(M):
"""Calculate petroleum fractions properties with the Silva-Rodriguez
(1992) correlations
Parameters
----------
M: float
Molecular weight, [-]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tb: Boiling temperature, [K]
* SG: Specific gravity, [-]
Examples
--------
Example 2.1 from [9]_: C7+ fraction with M=150 and SG=0.78
>>> p = prop_Silva_Rodriguez(150)
>>> "%.0f %.4f" % (p["Tb"].R, p["SG"])
'839 0.7982'
"""
Tb = 447.08725*log(M/64.2576) # Eq A4
SG = 0.132467*log(Tb)+0.0116483 # Eq A5
prop = {}
prop["M"] = unidades.Dimensionless(M)
prop["SG"] = unidades.Dimensionless(SG)
prop["Tb"] = unidades.Temperature(Tb, "F")
return prop
[docs]
@refDoc(__doi__, [17])
def Tb_Soreide(M, SG):
"""Calculate petroleum fractions boiling temperature with the Soreide
(1989) correlations
Parameters
----------
M: float
Molecular weight, [-]
SG: float
Specific gravity, [-]
Returns
-------
Tb : float
Boiling temperature, [K]
"""
Tb = 1928.3 - 1.695e5*SG**3.266/M**0.03522*exp(
-4.922e-3*M-4.7685*SG+3.462e-3*M*SG) # Eq 3.59
return {"Tb": unidades.Temperature(Tb, "R")}
[docs]
@refDoc(__doi__, [18])
def vc_Hall_Yarborough(M, SG):
"""Calculate petroleum fractions critic volume with the Hall-Yarborough
(1971) correlation
Parameters
----------
M: float
Molecular weight, [-]
SG: float
Specific gravity, [-]
Returns
-------
vc : float
Boiling temperature, [K]
"""
Vc = 0.025*M**1.15/SG**0.7985
return {"Vc": unidades.SpecificVolume(Vc/M, "ft3lb")}
[docs]
@refDoc(__doi__, [43])
def M_Goossens(Tb, d20):
"""Calculate petroleum fractions molecular weight with the Goossens
(1971) correlation
Parameters
----------
Tb : float
Normal boiling temperature, [K]
d20 : float
Liquid density at 20ºC and 1 atm, [g/cm³]
Returns
-------
M: float
Molecular weight, [-]
Examples
--------
>>> "%.1f" % M_Goossens(306, 0.6258)["M"]
'77.0'
"""
b = 1.52869 + 0.06486*log(Tb/(1078-Tb))
M = 0.01077*Tb**b/d20
return {"M": unidades.Dimensionless(M)}
[docs]
@refDoc(__doi__, [44])
def w_Korsten(Tb, Tc, Pc):
"""Calculate petroleum fractions acentric factor with the Korsten (2000)
correlation
Parameters
----------
Tb : float
Normal boiling temperature, [K]
Tc : float
Critical temperature, [K]
Pc : float
Critical pressure, [Pa]
Returns
-------
w: float
Acentric factor, [-]
"""
tbr = Tb/Tc
# Eq 29
w = 0.5899*tbr**1.3/(1-tbr**1.3)*log10(Pc/101325)-1.
return {"w": unidades.Dimensionless(w)}
[docs]
@refDoc(__doi__, [29])
def prop_Riazi(SG, tita, val):
"""Calculate petroleum fractions properties using the Riazi correlation.
This correlation is recommendated for heavy weight fractions C20-C50.
Parameters
----------
SG: float
Specific gravity, [-]
tita : string
Name of second known property
val float
known property value
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [ºR]
* Pc: Critic pressure, [psi]
* Vc: Critic volume, [ft³/lb]
* Tb: Boiling temperatura, [ºR]
* d20: Liquid density at 20ºC, [g/cm³]
* I: Huang Characterization factor, [-]
Notes
-----
The available input properties for tita are:
* Tb: Boiling temperature, [ºR]
* M: Molecular weight, [-]
The critic volume is calculate in mole base, so be careful to correct with
molecular weight
"""
if tita not in ["M", "Tb"]:
raise NotImplementedError(translate("Petro", "Undefined input pair"))
# Convert input Tb in Kelvin to Rankine to use in the correlation
if tita == "Tb":
val = unidades.K2R(val)
# Table 2.9
par = {
"Tc": {
"Tb": [35.9416, -6.9e-4, -1.4442, 4.91e-4, 0.7293, 1.2771],
"M": [218.9592, -3.4e-4, -0.40852, -2.5e-5, 0.331, 0.8136]},
"Pc": {
"Tb": [6.9575, -0.0135, -0.3129, 9.174e-3, 0.6791, -0.6807],
"M": [8.2365e4, -9.04e-3, -3.3304, 0.01006, -0.9366, 3.1353]},
"Vc": {
"Tb": [6.1677e10, -7.583e-3, -28.5524, 0.01172, 1.20493, 17.2074],
"M": [9.703e6, -9.512e-3, -15.8092, 0.01111, 1.08283, 10.5118]},
"Tb": {
"M": [9.3369, 1.65e-4, 1.4103, -7.5152e-4, 0.5369, -0.7276]},
"I": {
"Tb": [3.2709e-3, 8.4377e-4, 4.59487, -1.0617e-3, 0.03201, -2.34887],
"M": [1.2419e-2, 7.27e-4, 3.3323, -8.87e-4, 6.438e-3, -1.61166]},
"d20": {
"Tb": [0.997, 2.9e-4, 5.0425, -3.1e-4, -0.00929, 1.01772],
"M": [1.04908, 2.9e-4, -7.339e-2, -3.4e-4, 3.484e-3, 1.05015]}}
prop = {}
prop[tita] = _unit(tita, val)
for key in par.keys():
if key != tita and (tita != "Tb" or key != "M"):
a, b, c, d, e, f = par[key][tita]
x = a*val**e*SG**f*exp(b*val+c*SG+d*val*SG) # Eq 2.46
unit = ""
if key == "Pc":
unit = "bar"
val = _unit(key, x, unit)
prop[key] = val
return prop
[docs]
@refDoc(__doi__, [26])
def prop_Riazi_Alsahhaf(Tb, M, d20):
"""Calculate petroleum fractions properties with the Riazi-AlSahhaf (1998)
correlation with the boiling temperature and liquid density at 20ºC as
input paramters.
Parameters
----------
Tb : float
Normal boiling temperature, [K]
M : float
Molecular Weight, [g/mol]
d20 : float
Liquid density at 20ºC and 1 atm, [g/cm³]
Returns
-------
prop : dict
A dict with the calculated properties:
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [MPa]
* Vc: Critic volume, [cm³/g]
Notes
-----
This correlation generalized the Riazi-Daubert method to non-polar
compounds and gases.
"""
a = [1.60193, 10.74145, -8.84800]
b = [0.00558, 0.07434, -0.03632]
c = [-0.00112, -0.00047, -0.00547]
d = [-0.52398, -2.10482, 0.16629]
e = [0.00104, 0.00508, -0.00028]
f = [-0.06403, -1.18869, 0.04660]
g = [0.93857, -0.66773, 2.00241]
h = [-0.00085, -0.01154, 0.00587]
i = [0.28290, 1.53161, -0.96608]
prop = {}
prop["Tb"] = unidades.Temperature(Tb)
prop["d"] = unidades.Density(d, "gcc")
for j, key in enumerate(["Tc", "Pc", "Vc"]):
x = exp(a[j] + b[j]*M + c[j]*Tb + d[j]*d20 + e[j]*Tb*d20) * \
M**f[j] * Tb**(g[j]+h[j]*M) * d20**i[j]
val = _unit(key, x, "")
prop[key] = val
return prop
[docs]
@refDoc(__doi__, [27, 28])
def prop_Riazi_Alsahhaf_PNA(M, cmp):
"""Calculate petroleum fractions properties with the Riazi-AlSahhaf PNA
correlation with the molecular weight as input parameter.
The procedure calculate the phisical properties for paraphins, naphthenes
and aromatics constituents of fraction.
Parameters
----------
M : float
Molecular weight, [-]
cmp : string
Hydrocarbon type, P (paraffins), N (naphthenes) or A (aromatics)
Returns
-------
prop : dict
A dict with the calculated properties:
* Tf: Freezing temperature, [K]
* Tb: Boiling temperature, [K]
* SG: Specific gravity, [-]
* d20: Density at 20ºC, [g/cm³]
* Tc: Critic temperature, [K]
* Pc: Critic pressure, [bar]
* Vc: Critic volume, [cm³/g]
* w: Acentric factor, [-]
* I: Refractive index parameter, [-]
* sigma: Surface tension, [dyn/cm]
"""
if cmp not in "PNA":
raise ValueError("Composition key code must be either of P, N, A")
if cmp == "P":
tita = [397, 1070, 0.85, 0.859, 0.2833, 1.15, 0, 0.26, 0.3, 33.2]
a = [6.5096, 6.98291, 92.22793, 88.01379, 87.6593, -0.41966, 4.65757,
-3.50532, -3.06826, 5.29577]
b = [0.14187, 0.02013, 89.82301, 85.7446, 86.62167, 0.02436, 0.13423,
1.5e-6, -1.04987, 0.61653]
c = [0.470, 2/3, 0.01, 0.01, 0.01, 0.58, 0.5, 2.38, 0.2, 0.32]
elif cmp == "N":
tita = [370, 1028, 0.853, 0.857, 0.283, 1.2, 0, -0.255, 0.3, 30.6]
a = [6.52504, 6.95649, 97.72532, 85.1824, 87.55238, 0.06765, 7.25857,
-3.18846, -8.25682, 14.17595]
b = [0.04945, 0.02239, 95.73589, 83.65758, 86.97556, 0.13763, 1.13139,
0.1658, -5.33934, 7.02549]
c = [2/3, 2/3, 0.01, 0.01, 0.01, 0.35, 0.26, 0.5, 0.08, 0.12]
else:
tita = [375, 1015, -0.8562, -0.854, -0.2829, 1.03, 0, -0.22, 0, 30.4]
a = [6.53599, 6.91062, 224.7257, 238.791, 137.0918, -0.29875, 9.77968,
-1.43083, -14.97, 1.98292]
b = [0.04912, 0.02247, 218.518, 232.315, 135.433, 0.06814, 3.07555,
0.12744, -9.48345, -0.0142]
c = [2/3, 2/3, 0.01, 0.01, 0.01, 0.5, 0.15, 0.5, 0.08, 1.0]
prop = {}
prop["M"] = unidades.Dimensionless(M)
properties = ["Tf", "Tb", "SG", "d20", "I", "Tc", "Pc", "Vc", "w", "sigma"]
for i, key in enumerate(properties):
x = tita[i]-exp(a[i]-b[i]*M**c[i])
# Make conversion where necessary
if key == "Tc":
x = prop["Tb"]/x
elif key in ["Pc", "w"]:
x = -x
elif key == "Vc":
x = 1/x
# Define units
unit = ""
if key == "Pc":
unit = "bar"
elif key == "Vc":
unit = "ccg"
elif key == "sigma":
unit = "dyncm"
val = _unit(key, x, unit)
prop[key] = val
return prop
# Zc Methods
[docs]
@refDoc(__doi__, [22])
def Zc_Hougen(w):
"""Calculate the critical compressibility factdor Zc using the Hougen
correlation (1959)
Parameters
----------
w : float
Acentric factor, [-]
Returns
-------
Zc : float
Critical compressibility factor, [-]
"""
Zc = 1/(1.28*w+3.41)
return unidades.Dimensionless(Zc)
[docs]
@refDoc(__doi__, [23])
def Zc_Reid(w):
"""Calculate the critical compressibility factdor Zc using the Reid
Prausnith and Sherwood (1977) correlation
Parameters
----------
w : float
Acentric factor, [-]
Returns
-------
Zc : float
Critical compressibility factor, [-]
"""
Zc = 0.2918 - 0.0928*w
return unidades.Dimensionless(Zc)
[docs]
@refDoc(__doi__, [21])
def Zc_Salerno(w):
"""Calculate the critical compressibility factdor Zc using the Salerno
correlation (1985)
Parameters
----------
w : float
Acentric factor, [-]
Returns
-------
Zc : float
Critical compressibility factor, [-]
"""
Zc = 0.291 - 0.08*w - 0.016*w**2 # Eq 3
return unidades.Dimensionless(Zc)
[docs]
@refDoc(__doi__, [24])
def Zc_Nath(w):
"""Calculate the critical compressibility factdor Zc using the Nath
correlation (1985)
Parameters
----------
w : float
Acentric factor, [-]
Returns
-------
Zc : float
Critical compressibility factor, [-]
"""
Zc = 0.2908 - 0.0825*w # Eq 1
return unidades.Dimensionless(Zc)
[docs]
@refDoc(__doi__, [25])
def Zc_Lee_Kesler(w):
"""Calculate the critical compressibility factdor Zc using the Lee-Kesler
correlation (1975)
Parameters
----------
w : float
Acentric factor, [-]
Returns
-------
Zc : float
Critical compressibility factor, [-]
"""
Zc = 0.2905 - 0.085*w # Eq 21
return unidades.Dimensionless(Zc)
# Distillation curves interconversion methods Ref. [29] Pag 117
[docs]
@refDoc(__doi__, [19, 29])
def D86_TBP_Riazi(Ti, Xi=None, reverse=False):
"""Interconversion between D86 and TBP at atmospheric pressure using the
Riazi correlation
Parameters
----------
Ti : list
Distillation data with the D86 distillation temperature
Xi : list
Volumetric cut point range
reverse : boolean
To do the reverse conversion
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example 3.2 from [29]_
>>> X = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
>>> TBP = [10, 71.1, 143.3, 204.4, 250.6, 291.7]
>>> TBP_K = [t+273.15 for t in TBP]
>>> D86 = D86_TBP_Riazi(TBP_K, X, reverse=True)
>>> D86_C = [t-273.15 for t in D86]
>>> "%.0f" % D86_C[0]
'32'
Example 3.3 from [29]_
>>> X = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
>>> D86 = [165.6, 173.7, 193.3, 206.7, 222.8, 242.8]
>>> D86_K = [t+273.15 for t in D86]
>>> TDB = D86_TBP_Riazi(D86_K, X)
>>> TDB_C = [t-273.15 for t in TDB]
>>> "%.1f %.1f %.1f %.1f %.1f %.1f" % tuple(TDB_C)
'134.2 157.4 190.3 209.0 230.2 254.7'
"""
# Define the default value for volumetric volume
if Xi is None:
Xi = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 0.95]
a = [0.9177, 0.5564, 0.76517, 0.9013, 0.8821, 0.9552, 0.8177]
b = [1.0019, 1.09, 1.0425, 1.0176, 1.0226, 1.011, 1.0355]
Xmin = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 0.95]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 1.0001]
# Calculate parameters
A = []
B = []
for x in Xi:
for xmin, xmax, ai, bi in zip(Xmin, Xmax, a, b):
if xmin <= x < xmax:
A.append(ai)
B.append(bi)
break
# Calculate desired distillation data
TBP = []
if reverse:
for ai, bi, T in zip(A, B, Ti):
TBP.append(unidades.Temperature((1/ai)**(1/bi) * T**(1/bi)))
else:
for ai, bi, T in zip(A, B, Ti):
TBP.append(unidades.Temperature(ai*T**bi))
return TBP
[docs]
@refDoc(__doi__, [32, 20, 29])
def D86_TBP_Daubert(Ti, Xi=None, T50=None, reverse=False):
"""Interconversion between D86 and TBP at atmospheric pressure using the
Daubert correlation, API procedure 3A1.1
Parameters
----------
Ti : list
Distillation data with the T0, T10, T30, T50, T70, T90, T95
Xi : list
Volumetric cut point range
T50 : float
D86 distillation at 50% point temperature
reverse : boolean
To do the reverse conversion
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example from [20]_
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> D86 = [350, 380, 404, 433, 469]
>>> D86_K = [unidades.F2K(t) for t in D86]
>>> TDB = D86_TBP_Daubert(D86_K, X, D86_K[2])
>>> TDB_F = [t.F for t in TDB]
>>> "%.1f %.1f %.1f %.1f %.1f" % tuple(TDB_F)
'316.5 372.6 411.2 451.2 496.7'
Inverse case
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> TDB = [321, 371, 409, 447, 469]
>>> TDB_K = [unidades.F2K(t) for t in TDB]
>>> D86 = D86_TBP_Daubert(TDB_K, X, TDB_K[2], reverse=True)
>>> D86_F = [t.F for t in D86]
>>> "%.1f %.1f" % (D86_F[1], D86_F[2])
'378.4 401.9'
Example 3.3 from [29]_
>>> X = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
>>> D86 = [165.6, 173.7, 193.3, 206.7, 222.8, 242.8]
>>> D86_K = [t+273.15 for t in D86]
>>> TDB = D86_TBP_Daubert(D86_K, X)
>>> TDB_C = [t-273.15 for t in TDB]
>>> "%.1f %.1f %.1f %.1f %.1f %.1f" % tuple(TDB_C)
'133.5 154.2 189.2 210.7 232.9 258.2'
"""
# Convert to Fahrenheit the input distillation temperature
Ti = [unidades.K2F(t) for t in Ti]
# Define the default value for volumetric volume
if Xi is None:
Xi = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
if T50 is None:
T50 = Ti[3]
else:
T50 = unidades.K2F(T50)
a = [7.4012, 4.9004, 3.0305, 2.5282, 3.0419, 0.11798]
b = [0.60244, 0.71644, 0.80076, 0.82002, 0.75497, 1.6606]
Xmin = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 1.0001]
# Calculate parameters
A = []
B = []
for x in Xi:
for xmin, xmax, ai, bi in zip(Xmin, Xmax, a, b):
if xmin <= x < xmax:
A.append(ai)
B.append(bi)
break
# Calculate the desviation coefficient
if reverse:
TBP50 = exp(log(T50/0.87180)/1.0258)
Y = [exp(log((Ti[i+1]-T)/A[i])/B[i]) for i, T in enumerate(Ti[:-1])]
else:
TBP50 = 0.87180*T50**1.0258
Y = [A[i]*(Ti[i+1]-T)**B[i] for i, T in enumerate(Ti[:-1])]
# Calculate desired distillation data
TBP = [TBP50]*len(Ti)
for i, T in enumerate(TBP):
for y, x in zip(Y[i:], Xi[i:]):
if Xi[i] < 0.5 and x < 0.5:
TBP[i] -= y
for y, x in zip(Y[:i], Xi[:i]):
if Xi[i] >= 0.5 and x >= 0.5:
TBP[i] += y
return [unidades.Temperature(t, "F") for t in TBP]
[docs]
@refDoc(__doi__, [19, 29])
def SD_D86_Riazi(Ti, Xi=None, F=None):
"""Interconversion between SD and D86
Parameters
----------
Ti : list
Distillation data with the D86 distillation temperature
Xi : list
Volumetric cut point range
F : float
Parameter, :math: $F = 0.01411*SD_{10%}^0.05434*SD_{50%}^0.6147
Returns
-------
D86 : list
Calculated distillation data
Examples
--------
Example 3.5 from [29]_
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> SD = [33.9, 64.4, 101.7, 140.6, 182.2]
>>> SD_K = [t+273.15 for t in SD]
>>> F = 0.01411*SD_K[0]**0.05434*SD_K[2]**0.6147
>>> D86 = SD_D86_Riazi(SD_K, X, F)
>>> D86_C = [t-273.15 for t in D86]
>>> "%.1f %.1f %.1f %.1f %.1f" % tuple(D86_C)
'53.2 70.9 96.0 131.3 168.3'
"""
# Define the default value for volumetric volume
if Xi is None:
Xi = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
if F is None:
F = 0.01411*Ti[1]**0.05434*Ti[3]**0.6147
# Possible typo in referencen [20]_, the a_50% parameter with a 10 factor
a = [5.1764, 3.7452, 4.2749, 18.445, 1.0751, 1.0849, 1.7991]
b = [0.7445, 0.7944, 0.7719, 0.5425, 0.9867, 0.9834, 0.9007]
c = [0.2879, 0.2671, 0.345, 0.7132, 0.0486, 0.0354, 0.0625]
Xmin = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 1, 1.0001]
# Calculate parameters
A = []
B = []
C = []
for x in Xi:
for xmin, xmax, ai, bi, ci in zip(Xmin, Xmax, a, b, c):
if xmin <= x < xmax:
A.append(ai)
B.append(bi)
C.append(ci)
break
D86 = []
for ai, bi, ci, T in zip(A, B, C, Ti):
D86.append(unidades.Temperature(ai*T**bi*F**ci))
return D86
[docs]
@refDoc(__doi__, [32, 20, 29])
def SD_D86_Daubert(Ti, Xi=None, SD50=None):
"""Interconversion between gas chromatography (ASTM D2887) and ASTM D86 at
atmospheric pressure using the Daubert correlation, API procedure 3A3.2
Parameters
----------
Ti : list
Distillation data with the T0, T10, T30, T50, T70, T90, T95
Xi : list
Volumetric cut point range
SD50 : float
SD86 distillation at 50% point temperature
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example from [20]_
>>> X = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
>>> SD = [77, 93, 148, 215, 285, 360, 408]
>>> SD_K = [unidades.F2K(t) for t in SD]
>>> D86 = SD_D86_Daubert(SD_K, X)
>>> D86_F = [t.F for t in D86]
>>> "%.1f %.1f %.1f %.1f %.1f %.1f %.1f" % tuple(D86_F)
'121.3 128.2 154.8 206.3 270.6 334.0 367.5'
Example 3.5 from [29]_
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> SD = [33.9, 64.4, 101.7, 140.6, 182.2]
>>> SD_K = [t+273.15 for t in SD]
>>> D86 = SD_D86_Daubert(SD_K, X, SD_K[2])
>>> D86_C = [t-273.15 for t in D86]
>>> "%.1f %.1f %.1f %.1f %.1f" % tuple(D86_C)
'53.5 68.2 96.9 132.6 167.8'
"""
# Convert to Fahrenheit the input distillation temperature
Ti = [unidades.K2F(t) for t in Ti]
# Define the default value for volumetric volume
if Xi is None:
Xi = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
if SD50 is None:
SD50 = Ti[3]
else:
SD50 = unidades.K2F(SD50)
e = [0.3047, 0.06069, 0.07978, 0.14862, 0.30785, 2.6029]
f = [1.1259, 1.5176, 1.5386, 1.4287, 1.2341, 0.65962]
Xmin = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 1.0001]
# Calculate parameters
E = []
F = []
for x in Xi:
for xmin, xmax, ei, fi in zip(Xmin, Xmax, e, f):
if xmin <= x < xmax:
E.append(ei)
F.append(fi)
break
# Calculate the desviation coefficient
U = [E[i]*(Ti[i+1]-T)**F[i] for i, T in enumerate(Ti[:-1])]
# Calculate desired distillation data
D86_50 = 0.77601*SD50**1.0395
D86 = [D86_50]*len(Ti)
for i, T in enumerate(D86):
for y, x in zip(U[i:], Xi[i:]):
if Xi[i] < 0.5 and x < 0.5:
D86[i] -= y
for y, x in zip(U[:i], Xi[:i]):
if Xi[i] >= 0.5 and x >= 0.5:
D86[i] += y
return [unidades.Temperature(t, "F") for t in D86]
[docs]
@refDoc(__doi__, [19, 29])
def D86_EFV(Ti, Xi=None, SG=None, reverse=False):
"""Interconversion between D86 and EFV
Parameters
----------
Ti : list
Distillation data with the D86 distillation temperature
Xi : list
Volumetric cut point range
SG : float
Specific gravity, [-]
reverse : boolean
To do the reverse conversion
Returns
-------
EFV : list
Calculated distillation data
Examples
--------
Example 3.2 from [29]_
>>> X = [0, 0.1, 0.3, 0.5, 0.7, 0.9]
>>> TBP = [10, 71.1, 143.3, 204.4, 250.6, 291.7]
>>> TBP_K = [t+273.15 for t in TBP]
>>> D86 = D86_TBP_Riazi(TBP_K, X, reverse=True)
>>> EFV = D86_EFV(D86, X, SG=0.7862)
>>> EFV_C = [t-273.15 for t in EFV]
>>> "%.0f" % EFV_C[0]
'68'
"""
# Define the default value for volumetric volume
if Xi is None:
Xi = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
if SG is None:
SG = 0.08342*Ti[1]**0.10731*Ti[3]**0.26288
a = [2.9747, 1.4459, 0.8506, 3.268, 8.2873, 10.6266, 7.9952]
b = [0.8466, 0.9511, 1.0315, 0.8274, 0.6874, 0.6529, 0.6949]
c = [0.4209, 0.1287, 0.0817, 0.6214, 0.934, 1.1025, 1.0737]
Xmin = [0, 0.1, 0.3, 0.5, 0.7, 0.9, 1]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 1, 1.0001]
# Calculate parameters
A = []
B = []
C = []
for x in Xi:
for xmin, xmax, ai, bi, ci in zip(Xmin, Xmax, a, b, c):
if xmin <= x < xmax:
A.append(ai)
B.append(bi)
C.append(ci)
break
# Calculate desired distillation data
EFV = []
if reverse:
for ai, bi, ci, T in zip(A, B, C, Ti):
EFV.append(unidades.Temperature((T/ai/SG**ci)**(1./bi)))
else:
for ai, bi, ci, T in zip(A, B, C, Ti):
EFV.append(unidades.Temperature(ai*T**bi*SG**ci))
return EFV
[docs]
@refDoc(__doi__, [32, 20, 29])
def SD_TBP(Ti, Xi=None, SD50=None):
"""Interconversion between gas chromatography (ASTM D2887) and TBP at
atmospheric pressure using the Daubert correlation, API procedure 3A3.1
Parameters
----------
Ti : list
Distillation data with the T0, T10, T30, T50, T70, T90, T95
Xi : list
Volumetric cut point range
SD50 : float
SD86 distillation at 50% point temperature
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example from [20]_
>>> X = [0.05, 0.1, 0.3, 0.5, 0.7, 0.9, 0.95]
>>> SD = [293, 305, 324, 336, 344, 359, 369]
>>> SD_K = [unidades.F2K(t) for t in SD]
>>> TDB = SD_TBP(SD_K, X)
>>> TDB_F = [t.F for t in TDB]
>>> "%.1f %.1f %.1f %.1f %.1f %.1f %.1f" % tuple(TDB_F)
'322.2 327.7 332.4 336.0 339.6 350.1 357.4'
Example 3.4 from [29]_
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> SD = [151.7, 162.2, 168.9, 173.3, 181.7]
>>> SD_K = [t+273.15 for t in SD]
>>> TDB = SD_TBP(SD_K, X, SD_K[2])
>>> TDB_C = [t-273.15 for t in TDB]
>>> "%.1f %.1f %.1f %.1f %.1f" % tuple(TDB_C)
'164.3 166.9 168.9 170.9 176.8'
"""
# Convert to Fahrenheit the input distillation temperature
Ti = [unidades.K2F(t) for t in Ti]
# Define the default value for volumetric volume
if Xi is None:
Xi = [0.05, 0.1, 0.3, 0.5, 0.7, 0.9, 0.95]
if SD50 is None:
SD50 = Ti[3]
else:
SD50 = unidades.K2F(SD50)
c = [0.15779, 0.011903, 0.05342, 0.19861, 0.31531, 0.97476, 0.02172]
d = [1.4296, 2.0253, 1.6988, 1.3975, 1.2938, 0.8723, 1.9733]
Xmin = [0.05, 0.1, 0.3, 0.5, 0.7, 0.9, 0.95]
Xmax = [0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 1.0001]
# Calculate parameters
C = []
D = []
for x in Xi:
for xmin, xmax, ci, di in zip(Xmin, Xmax, c, d):
if xmin <= x < xmax:
C.append(ci)
D.append(di)
break
# Calculate the desviation coefficient
W = [C[i]*(Ti[i+1]-T)**D[i] for i, T in enumerate(Ti[:-1])]
# Calculate desired distillation data
TBP = [SD50]*len(Ti)
for i, T in enumerate(TBP):
for y, x in zip(W[i:], Xi[i:]):
if Xi[i] < 0.5 and x < 0.5:
TBP[i] -= y
for y, x in zip(W[:i], Xi[:i]):
if Xi[i] >= 0.5 and x >= 0.5:
TBP[i] += y
return [unidades.Temperature(t, "F") for t in TBP]
[docs]
@refDoc(__doi__, [33, 29])
def D1160_TBP_10mmHg(Ti, Xi=None):
"""Interconversion between ASTM D1160 and TBP distillation curve at 10 mmHg
Parameters
----------
Ti : list
Distillation data with the T0, T10, T30, T50, T70, T90, T95
Xi : list
Volumetric cut point range
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example 3.6 from [29]_
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> D1160 = [150, 205, 250, 290, 350]
>>> D1160_K = [t+273.15 for t in D1160]
>>> TDB = D1160_TBP_10mmHg(D1160_K, X)
>>> TDB_C = [t-273.15 for t in TDB]
>>> "%.1f %.1f %.0f %.0f %.0f" % tuple(TDB_C)
'146.6 200.9 250 290 350'
"""
# Define the default value for volumetric volume
if Xi is None:
Xi = [0.1, 0.3, 0.5, 0.7, 0.9, 1]
TBP = []
for i, T in enumerate(Ti):
if Xi[i] >= 0.5:
TBP.append(T)
else:
DT = Ti[i+1]-T
if Xi[i] >= 0.1:
F = 0.3 + 1.2775*DT - 5.539e-3*DT**2 + 2.7486e-5*DT**3
else:
F = 2.2566*DT - 266.2e-4*DT**2 + 1.4093e-4*DT**3
TBP.append(Ti[i+1]-F)
return [unidades.Temperature(t) for t in TBP]
[docs]
@refDoc(__doi__, [20, 29])
def Tb_Pressure(T, P, Kw=None, reverse=False):
"""Conversion of boiling point at Sub or super atmospheric pressure to the
normal boiling point, API Procedure 5A1.19
Parameters
----------
T : float
Temperature, [K]
P : float
Pressure, [Pa]
Kw: float
Watson characterization factor, [-]
reverse : boolean
Do the inverse calculation from normal boiling point to other pressure
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example from [20]_
>>> T = unidades.Temperature(365, "F")
>>> P = unidades.Pressure(10, "mmHg")
>>> TDB = Tb_Pressure(T, P, 12.5)
>>> "%.0f" % TDB
'602'
"""
p = unidades.Pressure(P, "Pa")
if p.mmHg < 2:
Q = (6.76156-0.987672*log10(p.mmHg))/(3000.538-43*log10(p.mmHg))
elif p.mmHg < 760:
Q = (5.994296-0.972546*log10(p.mmHg))/(2663.129-95.76*log10(p.mmHg))
else:
Q = (6.412631-0.989679*log10(p.mmHg))/(2770.085-36.*log10(p.mmHg))
if reverse:
if T < 367 or not Kw:
F = 0
elif T < 478:
F = -3.2985+0.009*T*(Kw-12)
else:
F = 1
Tb_ = T-1.3889*F*log10(p.atm)
Tb = Tb_/(748.1*Q-Tb_*(0.3861*Q-0.00051606))
else:
Tb_ = 748.1*Q*T/(1+T*(0.3861*Q-0.00051606))
if Tb_ < 367 or not Kw:
F = 0
elif Tb_ < 478:
F = -3.2985+0.009*Tb_*(Kw-12)
else:
F = 1
Tb = Tb_+1.3889*F*log10(p.atm)
return unidades.Temperature(Tb)
[docs]
@refDoc(__doi__, [34])
def curve_Predicted(x, T):
"""Fill the missing point of a distillation curve
Parameters
----------
x : list
Array with mole/volume/weight fraction, [-]
T : list
Array with boiling point temperatures, [K]
Returns
-------
TBP : list
Calculated distillation data
Examples
--------
Example 4.7 from [54]_
>>> xw = [0.261, 0.254, 0.183, 0.14, 0.01, 0.046, 0.042, 0.024, 0.015, \
0.009, 0.007]
>>> x = [sum(xw[:i+1]) for i, xi in enumerate(xw)]
>>> T = [365, 390, 416, 440, 461, 482, 500, 520, 539, 556, 573]
>>> parameter, r = curve_Predicted(x, T)
>>> "%.0f %.4f %.4f" % tuple(parameter)
'327 0.2028 1.3802'
"""
x = array(x)
T = array(T)
p0 = [T[0], 0.1, 1]
def errf(p, xw, Tb):
return _Tb_Predicted(p, xw) - Tb
p, cov, info, mesg, ier = leastsq(errf, p0, args=(x, T), full_output=True)
ss_err = (info['fvec']**2).sum()
ss_tot = ((T-T.mean())**2).sum()
r = 1-(ss_err/ss_tot)
return p, r
[docs]
def _Tb_Predicted(par, x):
"""Calculate a specific point in the distillation curve"""
return par[0]+par[0]*(par[1]/par[2]*log(1/(1-x)))**(1./par[2])
# Others properties
[docs]
@refDoc(__doi__, [20])
def PourPoint(SG, Tb, v100=None):
"""Calculate the pour point of petroleum fractions using the procedure
2B8 from API technical databook, pag. 235
The pour point is the lowest temperature at which it will flow or can be
poured.
Parameters
----------
SG : float
Specific gravity, [-]
Tb : float
Mean average boiling point, [K]
v100 : float
Kinematic viscosity at 100ºF, [cSt]
Returns
-------
PP : float
Pour point, [ºR]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 0.8 ≤ SG ≤ 1
* 800ºR ≤ Tb ≤ 1500ºR
* 2cSt ≤ v100 ≤ 960cSt
Examples
--------
>>> T = unidades.Temperature(972, "R")
>>> v = unidades.Diffusivity(3, "cSt")
>>> "%0.0f" % PourPoint(0.839, T, v).R
'458'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
v100 = unidades.Diffusivity(v100).cSt
# Check input in range of validity
if SG < 0.8 or SG > 1 or Tb_R < 800 or Tb_R > 1500:
raise NotImplementedError("Incoming out of bound")
if v100 is not None and (v100 < 2 or v100 > 960):
raise NotImplementedError("Incoming out of bound")
if v100 is not None:
# Eq 2B8.1-1
PP = 753 + 136*(1-exp(-0.15*v100)) - 572*SG + 0.0512*v100 + 0.139*Tb_R
else:
# Eq 2B8.1-2
PP = 3.85e-8*Tb_R**5.49*10**-(0.712*Tb.R**0.315+0.133*SG) + 1.4
return unidades.Temperature(PP, "R")
[docs]
@refDoc(__doi__, [20])
def AnilinePoint(SG, Tb):
"""Calculate the aniline point of petroleum fractions using the procedure
2B9 from API technical databook, pag. 237
The aniline point is the lowest temperature at which a petroleum fraction
is completely miscible with an equal volume of distilled aniline.
Parameters
----------
SG : float
Specific gravity, [-]
Tb : float
Mean average boiling point, [ºR]
Returns
-------
AP : float
Aniline point, [ªR]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 0.7 ≤ SG ≤ 1
* 200ºF ≤ Tb ≤ 1100ºF
Examples
--------
>>> T = unidades.Temperature(570.2, "F")
>>> "%0.1f" % AnilinePoint(0.8304, T).R
'635.5'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_F = unidades.K2F(Tb)
Tb_R = unidades.K2R(Tb)
Kw = Tb_R**(1/3)/SG
# Check input in range of validity
if SG < 0.7 or SG > 1 or Tb_F < 200 or Tb_F > 1100:
raise NotImplementedError("Incoming out of bound")
# Eq 2B9.1-1
AP = -1253.7 - 0.139*Tb_R + 107.8*Kw + 868.7*SG
return unidades.Temperature(AP, "R")
[docs]
@refDoc(__doi__, [20])
def SmokePoint(SG, Tb):
"""Calculate the smoke point of petroleum fractions using the procedure 2B10
from API technical databook, pag. 239
The smoke point is the height in millimeters of the flame that is
produced in a lamp at standard conditions without causing smoking.
Parameters
----------
SG : float
Specific gravity, [-]
Tb : float
Mean average boiling point, [ºF]
Returns
-------
SP : float
Cloud point, [mm]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 0.7 ≤ SG ≤ 0.86
* 200ºF ≤ Tb ≤ 550ºF
Examples
--------
>>> T = unidades.Temperature(414.5, "F")
>>> "%0.1f" % SmokePoint(0.853, T).mm
'16.7'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_F = unidades.K2F(Tb)
Tb_R = unidades.K2R(Tb)
Kw = Tb_R**(1/3)/SG
# Check input in range of validity
if SG < 0.7 or SG > 0.86 or Tb_F < 200 or Tb_F > 550:
raise NotImplementedError("Incoming out of bound")
# Eq 2B10.1-1
SP = exp(-1.028+0.474*Kw-0.00168*Tb_R)
return unidades.Length(SP, "mm")
[docs]
@refDoc(__doi__, [20])
def FreezingPoint(SG, Tb):
"""Calculate freezing point of petroleum fractions using the procedure 2B11
from API technical databook, pag. 241
The freezing point is the temperature at which solid crystals formed on
cooling disappear as the temperature is raised.
Parameters
----------
SG : float
Specific gravity, [-]
Tb : float
Mean average boiling point, [ºR]
Returns
-------
FP : float
Cloud point, [ºR]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 0.74 ≤ SG ≤ 0.9
* 725ºR ≤ Tb ≤ 1130ºR
Examples
--------
>>> T = unidades.Temperature(874.5, "R")
>>> "%0.0f" % CloudPoint(0.799, T).R
'417'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
Kw = Tb_R**(1/3)/SG
# Check input in range of validity
if SG < 0.74 or SG > 0.90 or Tb_R < 725 or Tb_R > 1130:
raise NotImplementedError("Incoming out of bound")
# Eq 2B11.1-1
FP = -2390.42 + 1826*SG + 122.49*Kw - 0.135*Tb_R
return unidades.Temperature(FP, "R")
[docs]
@refDoc(__doi__, [20])
def CloudPoint(SG, Tb):
"""Calculate cloud point of petroleum fractions using the procedure 2B12
from API technical databook, pag. 243
The cloud point of is the temperature at which its solid paraffin content
begins to solidify and separate in tiny crystals, causing the oil to appear
cloudy.
Parameters
----------
SG : float
Specific gravity, [-]
Tb : float
Mean average boiling point, [ºR]
Returns
-------
CP : float
Cloud point, [ºR]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 0.77 ≤ SG ≤ 0.93
* 800ºR ≤ Tb ≤ 1225ºR
Examples
--------
>>> T = unidades.Temperature(811.5, "R")
>>> "%0.1f" % CloudPoint(0.787, T).R
'383.4'
"""
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
# Check input in range of validity
if SG < 0.77 or SG > 0.93 or Tb_R < 800 or Tb_R > 1225:
raise NotImplementedError("Incoming out of bound")
# Eq 2B12.1-1
CP = 10**(-7.41+5.49*log10(Tb_R)-0.712*Tb_R**0.315-0.133*SG)
return unidades.Temperature(CP, "R")
[docs]
@refDoc(__doi__, [20])
def CetaneIndex(API, Tb):
"""Calculate cetane index of petroleum fractions using the procedure 2B13
from API technical databook, pag. 245
Cetane index is the number equal to the porcentage of cetane in a blend of
cetane and α-methyl naphthalene having the same ignition quality as a
sample of the petroleum fraction.
Parameters
----------
API : float
API gravity, [-]
Tb : float
Mean average boiling point, [ºF]
Returns
-------
CI : float
Cetane Index, [-]
Notes
-----
Raise :class:`NotImplementedError` if input isn't in limit:
* 27 ≤ API ≤ 47
* 360ºF ≤ Tb ≤ 700ºF
Examples
--------
>>> T = unidades.Temperature(617, "F")
>>> "%0.1f" % CetaneIndex(32.3, T)
'57.1'
"""
# Convert input Tb in Kelvin to Fahrenheit to use in the correlation
Tb_F = unidades.K2F(Tb)
# Check input in range of validity
if API < 27 or API > 47 or Tb_F < 360 or Tb_F > 700:
raise NotImplementedError("Incoming out of bound")
# Eq 2B13.1-1
CI = 415.26 - 7.673*API + 0.186*Tb_F + 3.503*API*log10(Tb_F) - \
193.816*log10(Tb.F)
return unidades.Dimensionless(CI)
# PNA composition procedures
[docs]
@refDoc(__doi__, [20])
def PNA_Riazi(M, SG, n, d20=None, VGC=None, CH=None):
"""Calculate fractional compositon of paraffins, naphthenes and aromatics
contained in petroleum fractions using the procedure 2B4.1 from API
technical databook, pag. 225
Parameters
----------
M : float
Molecular weight, [g/mol]
SG : float
Specific gravity, [-]
n : float
Refractive index, [-]
d20 : float
Density at 20ºC, [g/cm³]
VGC : float
Viscosity gravity constant, [-]
CH : float
Carbon/hydrogen ratio, [-]
Returns
-------
xp : float
Paraffins mole fraction, [-]
xn : float
Naphthenes mole fraction, [-]
xa : float
Aromatics mole fraction, [-]
Notes
-----
Density at 20ºC is optional and can be calculated from specific gravity.
VGC and CH are optional parameters, the procedure need one of them
Raise :class:`NotImplementedError` if input viscosity or CH ratio are
undefined
Examples
--------
>>> "%0.3f %0.3f %0.3f" % PNA_Riazi(378, 0.9046, 1.5002, 0.9, VGC=0.8485)
'0.606 0.275 0.118'
"""
if d20 is None:
d20 = SG-4.5e-3*(2.34-1.9*SG)
Ri = n-d20/2.
m = M*(n-1.475)
if VGC is not None:
if M <= 200:
a, b, c = -13.359, 14.4591, -1.41344
d, e, f = 23.9825, -23.333, 0.81517
else:
a, b, c = 2.5737, 1.0133, -3.573
d, e, f = 2.464, -3.6701, 1.96312
xp = a + b*Ri + c*VGC
xn = d + e*Ri + f*VGC
elif CH is not None:
if M <= 200:
xp = 2.57 - 2.877*SG + 0.02876*CH
xn = 0.52641 - 0.7494*xp - 0.021811*m
else:
xp = 1.9842 - 0.27722*Ri - 0.15643*CH
xn = 0.5977 - 0.761745*Ri + 0.068048*CH
else:
raise NotImplementedError()
xa = 1-xp-xn
return xp, xn, xa
[docs]
@refDoc(__doi__, [36, 38])
def PNA_Peng_Robinson(Nc, M, WABP):
"""Calculate fractional compositon of paraffins, naphthenes and aromatics
contained in petroleum fractions using the Peng-Robinson procedure
Parameters
----------
Nc : index
Carbon number, [-]
M : float
Molecular weight, [g/mol]
WABP : float
Weight average boiling temperature, [K]
Returns
-------
xp : float
Paraffins mole fraction, [-]
xn : float
Naphthenes mole fraction, [-]
xa : float
Aromatics mole fraction, [-]
Notes
-----
This method can too calculate the critical properties of fraction
"""
# Convert input Tb in Kelvin to Fahrenheit to use in the correlation
WABP_R = unidades.K2R(WABP)
Tbp = exp(log(1.8) + 5.8345183 + 0.84909035e-1*(Nc-6) -
0.52635428e-2*(Nc-6)**2 + 0.21252908e-3*(Nc-6)**3 -
0.44933363e-5*(Nc-6)**4 + 0.37285365e-7*(Nc-6)**5)
Tbn = exp(log(1.8) + 5.8579332 + 0.79805995e-1*(Nc-6) -
0.43098101e-2*(Nc-6)**2 + 0.14783123e-3*(Nc-6)**3 -
0.27095216e-5*(Nc-6)**4 + 0.19907794e-7*(Nc-6)**5)
Tba = exp(log(1.8) + 5.867176 + 0.80436947e-1*(Nc-6) -
0.47136506e-2*(Nc-6)**2 + 0.18233365e-3*(Nc-6)**3 -
0.38327239e-5*(Nc-6)**4 + 0.32550576e-7*(Nc-6)**5)
Mp = 14.026*Nc + 2.016
Mn = 14.026*Nc - 14.026
Ma = 14.026*Nc - 20.074
# Solve the system of equation
a = [[1, 1, 1], [Tbp*Mp, Tbn*Mn, Tba*Ma], [Mp, Mn, Ma]]
b = [1, M*WABP_R, M]
Xp, Xn, Xa = solve(a, b)
# Calculate the critical properties of fraction
# pcp = (206.126096*Nc+29.67136)/(0.227*Nc+0.34)**2
# pcn = (206.126096*Nc+206.126096)/(0.227*Nc+0.137)**2
# pca = (206.126096*Nc+295.007504)/(0.227*Nc+0.325)**2
# pc = Xp*pcp+Xn*pcn+Xa*pca
# wp = 0.432*Nc-0.0457
# wn = 0.0432*Nc-0.088
# wa = 0.0445*Nc-0.0995
# S = 0.996704+0.00043155*Nc
# S1 = 0.99627245+0.00043155*Nc
# tcp = S*(1+(3*log10(pcp)-3.501952)/7/(1+wp))*Tbp
# tcn = S1*(1+(3*log10(pcn)-3.501952)/7/(1+wn))*Tbn
# tca = S1*(1+(3*log10(pca)-3.501952)/7/(1+wa))*Tba
# tc = Xp*tcp+Xn*tcn+Xa*tca
return Xp, Xn, Xa
[docs]
@refDoc(__doi__, [36, 37])
def PNA_Bergman(Tb, SG, Kw):
"""Calculate fractional compositon of paraffins, naphthenes and aromatics
contained in petroleum fractions using the Bergman procedure
Parameters
----------
Tb : float
Boiling temperature, [K]
SG : float
Specific gravity, [-]
Kw : float
Watson characterization factor, [-]
Returns
-------
xp : float
Paraffins mole fraction, [-]
xn : float
Naphthenes mole fraction, [-]
xa : float
Aromatics mole fraction, [-]
Notes
-----
This method can too calculate the critical properties of fraction
"""
# Convert input Tb in Kelvin to Fahrenheit to use in the correlation
Tb_F = unidades.K2F(Tb)
# Estimate gthe weight fraction of the aromatic content in fraction
Xwa = 8.47 - Kw
# Solve the linear equation for weight fractions of paraffins and naphtenes
gp = 0.582486 + 0.00069481*Tb_F - 0.7572818e-6*Tb_F**2 + \
0.3207736e-9*Tb_F**3
gn = 0.694208 + 0.0004909267*Tb_F - 0.659746e-6*Tb_F**2 + \
0.330966e-9*Tb_F**3
ga = 0.916103 - 0.000250418*Tb_F + 0.357967e-6*Tb_F**2 - \
0.166318e-9*Tb_F**3
a = [[1, 1], [1/gp, 1/gn]]
b = [1-Xwa, 1/SG - Xwa/ga]
Xwp, Xwn = solve(a, b)
# Calculate the Tc, Pc and acentric factor for each cut
# Tcp = 275.23 + 1.2061*Tb_F - 0.00032984*Tb_F**2
# Pcp = 573.011 - 1.13707*Tb_F + 0.00131625*Tb_F**2 - 0.85103e-6*Tb_F**3
# wp = 0.14 + 0.0009*Tb_F + 0.233e-6*Tb_F**2
# Tcn = 156.8906 + 2.6077*Tb_F - 0.003801*Tb_F**2 + 0.2544e-5*Tb_F**3
# Pcn = 726.414 - 1.3275*Tb_F + 0.9846e-3*Tb_F**2 - 0.45169e-6*Tb_F**3
# wn = wp-0.075
# Tca = 289.535 + 1.7017*Tb_F - 0.0015843*Tb_F**2 + 0.82358e-6*Tb_F**3
# Pca = 1184.514 - 3.44681*Tb_F + 0.0045312*Tb_F**2 - 0.23416e-5*Tb_F**3
# wa = wp-0.1
# pc=Xwp*Pcp+Xwn*Pcn+Xwa*Pca
# tc=Xwp*Tcp+Xwn*Tcn+Xwa*Tca
# w=Xwp*wp+Xwn*wn+Xwa*wa
return Xwp, Xwn, Xwa
[docs]
@refDoc(__doi__, [35, 29])
def PNA_van_Nes(M, n, d20, S):
"""Calculate fractional compositon of paraffins, naphthenes and aromatics
contained in petroleum fractions using the Van Nes procedure
Parameters
----------
M : float
Molecular weight, [g/mol]
n : float
Refractive index, [-]
d20 : float
Density at 20ºC, [g/cm³]
S : float
Sulfur content, [-]
Returns
-------
xp : float
Paraffins mole fraction, [-]
xn : float
Naphthenes mole fraction, [-]
xa : float
Aromatics mole fraction, [-]
Notes
-----
This method can too calculate the total number of rings, the number of
aromatics rings and the naphthenic rings
"""
v = 2.51*(n-1.475)-(d20-0.851)
w = (d20-0.851)-1.11*(n-1.475)
if v > 0:
a = 430
else:
a = 670
if w > 0:
CR = 820*w-3*S + 10000./M
else:
CR = 1440*w - 3*S + 10600./M
Ca = a*v + 3660/M
Cn = CR - Ca
Cp = 100 - CR
return Cp/100., Cn/100., Ca/100.
# Viscosity correlation
[docs]
@refDoc(__doi__, [20])
def viscoAPI(Tb=None, Kw=None, v100=None, v210=None, T=None, T1=None, T2=None):
"""Calculate viscosity of a petroleum fraction using the API procedure
11A4.2 and 11A4.4
Parameters
----------
Tb : float
Boiling temperature, [K]
Kw : float
Watson characterization factor, [-]
v100 : float, optional
Kinematic viscosity at 100ºF, [m²/s]
v210 : float, optional
Kinematic viscosity at 210ºF, [m²/s]
T : float, optional
Optional temperature to calculate the viscosity, [K]
T1 : float, optional
Temperature for v100 viscosity value, [K]
T2 : float, optional
Temperature for v210 viscosity value, [K]
Returns
-------
v100 : float
Kinematic viscosity at 100ºF, [m²/s]
v210 : float
Kinematic viscosity at 210ºF, [m²/s]
vT : float, optional
Kinematic viscosity at T input, [m²/s]
Notes
-----
By default the method calculate the viscosity at 100ºF and 210ºF, can too
calculate the viscosity at input T temperature
if T1 and T2 are different to 100ºF and 210ºF v100 and v210 input are at
that temperatures
if both viscosity are input Tb and Kw input aren't unnecesary
Examples
--------
Example A in procedure 11A4.2
>>> Tb = unidades.Temperature(598.7, "F")
>>> T = unidades.Temperature(140, "F")
>>> mu = viscoAPI(Tb, 11.87, T=T)
>>> "%0.2f %0.2f %0.2f" % (mu["v100"].cSt, mu["v210"].cSt, mu["vT"].cSt)
'5.94 1.88 3.57'
Example B in procedure 11A4.2
The values differ, in reference only use 2 decimal number in intermediate
>>> Tb = unidades.Temperature(647.3, "F")
>>> T = unidades.Temperature(304, "F")
>>> mu = viscoAPI(Tb, 9.955, T=T)
>>> "%0.2f %0.2f %0.2f" % (mu["v100"].cSt, mu["v210"].cSt, mu["vT"].cSt)
'39.41 5.20 2.12'
Example C in procedure 11A4.2
>>> Tb = unidades.Temperature(382.1, "F")
>>> mu = viscoAPI(Tb, 11.93)
>>> "%0.3f" % mu["v100"].cSt
'1.249'
>>> Tb = unidades.Temperature(1113.2, "F")
>>> mu = viscoAPI(Tb, 11.94)
>>> "%0.0f" % mu["v100"].cSt
'2612'
Example B in procedure 11A4.4
>>> T = unidades.Temperature(68, "F")
>>> T1 = unidades.Temperature(32, "F")
>>> T2 = unidades.Temperature(104, "F")
>>> v100 = unidades.Diffusivity(1.644, "cSt")
>>> v210 = unidades.Diffusivity(0.925, "cSt")
>>> mu = viscoAPI(T1=T1, T2=T2, T=T, v100=v100, v210=v210)
>>> "%0.3f" % mu["vT"].cSt
'1.201'
"""
if v100 is None or v210 is None:
# Convert input Tb in Kelvin to Rankine to use in the correlation
Tb_R = unidades.K2R(Tb)
if v100 is None:
# Calculate the viscosity at 100ºF
mu_ref = 10**(-1.35579 + 8.16059e-4*Tb_R + 8.38505e-7*Tb_R**2)
A1 = 34.931-8.84387e-2*Tb_R+6.73513e-5*Tb_R**2-1.01394e-8*Tb_R**3
A2 = -2.92649+6.98405e-3*Tb_R-5.09947e-6*Tb_R**2+7.49378e-10*Tb_R**3
mu_cor = 10**(A1+A2*Kw)
v100 = unidades.Diffusivity(mu_ref+mu_cor, "cSt")
else:
v100 = unidades.Diffusivity(v100)
if v210 is None:
# Calculate the viscosity at 210ºF
mu = 10**(-1.92353+2.41071e-4*Tb_R+0.5113*log10(Tb_R*v100.cSt))
v210 = unidades.Diffusivity(mu, "cSt")
else:
v210 = unidades.Diffusivity(v210)
vs = {}
vs["v100"] = v100
vs["v210"] = v210
if T is not None:
# Calculate the viscosity at other temperature
T_R = unidades.K2R(T)
if T1 is None:
T1 = unidades.Temperature(100, "F")
T1_R = T1.R
if T2 is None:
T2 = unidades.Temperature(210, "F")
T2_R = T2.R
Z1 = v100.cSt+0.7+exp(-1.47-1.84*v100.cSt-0.51*v100.cSt**2)
Z2 = v210.cSt+0.7+exp(-1.47-1.84*v210.cSt-0.51*v210.cSt**2)
B = (log10(log10(Z1))-log10(log10(Z2)))/(log10(T1_R)-log10(T2_R))
Z = 10**(10**(log10(log10(Z1))+B*(log10(T_R)-log10(T1_R))))
mu = Z - 0.7 - exp(
-0.7487-3.295*(Z-0.7)+0.6119*(Z-0.7)**2-0.3191*(Z-0.7)**3)
vs["vT"] = unidades.Diffusivity(mu, "cSt")
return vs
[docs]
@refDoc(__doi__, [20, 30])
def SUS(T, v):
"""Calculate the Saybolt Universal Viscosity in Saybolt Universal Seconds
(SUS) from kinematic viscosity, also referenced in API Procedure 11A1.1,
pag 1027
Parameters
----------
T : float
Temperature, [K]
v : float
Kinematic viscosity, [cSt]
Returns
-------
SUS : float
Saybolt Universal Seconds, [s]
Examples
--------
Example A from [20]_, SUS at 200ºF for ν=53cSt
>>> T = unidades.Temperature(617, "F")
>>> "%0.0f" % SUS(T, 53)
'254'
Example B from [20]_, SUS at 0ºF for ν=90cSt
>>> T = unidades.Temperature(0, "F")
>>> "%0.0f" % SUS(T, 90)
'415'
"""
# Convert input temperature to Fahrenheit
t_F = unidades.K2F(T)
# Eq 5
U100 = 4.6324*v + (1+0.03264*v)/(3930.2+262.7*v+23.97*v**2+1.646*v**3)*1e5
# Eq 6
Ut = (1+0.000061*(t_F-100))*U100
return unidades.Time(Ut)
[docs]
@refDoc(__doi__, [20, 30])
def SFS(T, v):
"""Calculate the Saybolt Furol Viscosity in Saybolt Furol Seconds
(SFS) from kinematic viscosity, also referenced in API Procedure 11A1.4,
pag 1031
Parameters
----------
T : float
Temperature, [K]
v : float
Kinematic viscosity, [cSt]
Returns
-------
SFS : float
Saybolt Furol Seconds, [s]
Examples
--------
Example A from [20]_, SFS at 122ºF and 210ºF for ν122=300cSt, v210=100cSt
>>> T = unidades.Temperature(122, "F")
>>> "%0.1f" % SFS(T, 300)
'141.7'
>>> T = unidades.Temperature(210, "F")
>>> "%0.1f" % SFS(T, 100)
'48.4'
"""
if T == 323.15:
S = 0.4717*v+13924/(v**2-72.59*v+6816) # Eq 7
else:
S = 0.4792*v+5610/(v**2+2130) # Eq 8
return unidades.Time(S)
[docs]
@refDoc(__doi__, [20, 31])
def MuL_Singh(T, v100):
"""Calculate kinematic viscosity of liquid petroleum fractions at low
pressure by Singh correlation, also referenced in API Procedure 11A4.1,
pag 1031
Parameters
----------
T : float
Temperature, [K]
v100 : float
Kinematic viscosity at 100ºF, [cSt]
Returns
-------
v : float
Kinematic viscosity at T, [cSt]
Examples
--------
Example from [20]_, Sumatran crude at 210ºF
>>> T = unidades.Temperature(210, "F")
>>> "%0.3f" % MuL_Singh(T, 1.38).cSt
'0.705'
"""
# Convert input temperature to Rankine
t_R = unidades.K2R(T)
S = 0.28008*log10(v100) + 1.8616
B = log10(v100) + 0.86960
mu = 10**(B*(559.67/t_R)**S - 0.86960)
return unidades.Diffusivity(mu, "cSt")
# Component predition
[docs]
@refDoc(__doi__, [29])
def H_Riazi(S, CH):
"""Calculate hydrogen content of petroleum fractions
Parameters
----------
S : float
Sulfur content, [%]
CH : float
Carbon/hydrogen ratio, [-]
Returns
-------
H : float
Hydrogen content, [%]
Notes
-----
A Simple mass balance discarting other elements composition than hydrogen,
carbon and sulfur
"""
H = (100-S)/(1+CH)
return H
[docs]
@refDoc(__doi__, [40])
def H_Goossens(M, n, d20):
"""Calculate hydrogen content of petroleum fractions using the correlation
of Goossens
Parameters
----------
M : float
Molecular weight, [-]
n : float
Refractive index, [-]
d20 : float
Liquid density at 20ºC, [g/cm³]
Returns
-------
H : float
Hydrogen content, [%]
Examples
--------
Table 1 data for n-decane
>>> "%0.2f" % H_Goossens(142, 1.4119, 0.7301)
'15.45'
"""
H = 30.346 + (82.952-65.341*n)/d20 - 306/M # Eq 3
return H
[docs]
@refDoc(__doi__, [29, 42])
def H_ASTM(Tb, SG, xa):
"""Calculate hydrogen content of petroleum fractions
Parameters
----------
Tb : float
Mean average boiling point, [ºR]
SG : float
Specific gravity, [-]
xa : float
Aromatics mole fraction, [-]
Returns
-------
H : float
Hydrogen content, [%]
"""
H = (5.2407 + 0.01448*Tb - 7.018*xa)/SG - 0.901*xa + 0.01298*xa*Tb - \
0.01345*Tb + 5.6879
return H
[docs]
@refDoc(__doi__, [41])
def H_Jenkins_Walsh(SG, anilineP):
"""Calculate hydrogen content of petroleum fractions using the correlation
of Jenkins-Walsh
Parameters
----------
SG : float
Specific gravity, [-]
anilineP : float
Aniline point, [K]
Returns
-------
H : float
Hydrogen content, [%]
"""
H = 11.17 - 12.89*SG + 0.0389*anilineP
return H
[docs]
@refDoc(__doi__, [39])
def S_Riazi(M, SG, Ri, m):
"""Calculate sulfur content of petroleum fractions
Parameters
----------
M : float
Molecular weight, [-]
SG : float
Specific gravity, [-]
Ri : float
Refractivity intercept, [-]
m : float
characterization factor, [-]
Returns
-------
S : float
Sulfur content, [%]
Examples
--------
S predicted in table 3 for a crude nº1
>>> "%0.2f" % S_Riazi(202, 0.837, 1.0511, -1.4849)
'1.19'
crude nº61
>>> "%0.2f" % S_Riazi(1484, 1.0209, 1.1611, 289.2786)
'2.85'
"""
if M < 200:
S = 177.448 - 170.946*Ri + 0.2258*m + 4.054*SG
else:
S = -58.02 + 38.463*Ri - 0.023*m + 22.4*SG
return S
[docs]
@refDoc(__doi__, [20])
def CombustionHeat(API, water=0, ash=0, S=0):
"""Calculate gross and net heat of combustion at 60ºF for petroleum
fractions, referenced in API procedure 14A1.3, pag 1236
Parameters
----------
API : float
API Specific gravity, [-]
water : float
Weight fraction of water, [%]
ash : float
Weight fraction of inerts, [%]
S : float
Weight fraction of inerts, [%]
Returns
-------
Hgross : float
Gross heat of combustion, [Btu/lb]
Hnet : float
Net heat of combustion, [Btu/lb]
Examples
--------
Fuel oil with 11.3ºAPI, 1.49%S, 1.67%ash, 0.3%water
>>> hg, hn = CombustionHeat(11.3, 0.3, 1.67, 1.49)
>>> "%0.0f %0.0f" % (hg.Btulb, hn.Btulb)
'18218 17222'
"""
# Interpolation data from Table 14-0.1 for normal sulfur and inert content
if API < 35:
_api = [0, 5, 10, 15, 20, 15, 30, 35]
_S = [2.95, 2.35, 1.8, 1.35, 1., 0.7, 0.4, 0.3]
_ash = [1.15, 1., 0.95, 0.85, 0.75, 0.7, 0.65, 0.6]
S -= interp1d(_api, _S)(API)
ash -= interp1d(_api, _ash)(API)
# Gross heating value
hg = 17672 + 66.6*API - 0.316*API**2 - 0.0014*API**3
hgc = unidades.Enthalpy(hg - 0.01*hg*(water+S+ash) + 40.5*S, "Btulb")
# Net heating value
hn = 16796 + 54.5*API - 0.217*API**2 - 0.0019*API**3
hnc = hn - 0.01*hn*(water+S+ash) + 40.5*S - 10.53*water
hnc = unidades.Enthalpy(hnc, "Btulb")
return hgc, hnc
[docs]
class Petroleo(newComponente):
"""Class to define a heavy oil fraction with a unknown composition
Parameters
----------
M : float
Molecular weight, [-]
Tb : float
Mean average boiling point, [K]
SG : float
Specific gravity, [-]
API : float
API gravity, [-]
CH : float
Carbon/hydrogen ratio, [-]
I : float
Huang parameter, [-]
n : float
Refractive index, [-]
Kw : float
Watson characterization factor, [-]
v100 : float
Kinematic viscosity at 100ºF, [m²/s]
v210 : float
Kinematic viscosity at 210ºF, [m²/s]
H : float
Hydrogen content, [-]
S : float
Sulfur content, [-]
N : float
Nitrogen content, [-]
Nc : float
Fraction carbon number, [-]
curveType : string
Name of curve data in curve input: D86, TBP, SD, D1186, EFV
T_curve : list
Boiling point temperature, [K]
X_curve : list
Volume or weight distillation fraction array
P_curve : float
Distillation data pressure, [Pa]
fit_curve : array
Array of fit parameter of curve distillation [To, A, B]
Examples
--------
Example from [20]_, procedure 2B1.1
>>> X = [0.1, 0.3, 0.5, 0.7, 0.9]
>>> D86 = [149, 230, 282, 325, 371]
>>> D86_K = [unidades.F2K(t) for t in D86]
>>> oil = Petroleo(curveType="D86", X_curve=X, T_curve=D86_K)
>>> "%.0f %.0f %.0f %.0f %.0f" % (\
oil.VABP.F, oil.MABP.F, oil.WABP.F, oil.CABP.F, oil.MeABP.F)
'271 241 279 264 253'
Notes
-----
The calculated instance has the necessary calculated properties to be used
in the flowsheet as hypotethical component.
The definition can be with several input parameters:
* Distillation data (TBP or other). This is the prefered and accurate
method to define the pseudocomponent.
* Any combination of physical properties (Tb, SG, M, I, n, CH, v100)
* Nc as only paramter to calculata all the other propeties, this is the
less accurate method and it's not recommended.
Refractive index is equivalent as input parameter to Huang parameter.
Watson characterization factor is equivalent to SG or boiling temperature
API gravity is equivalent to SG as input paramter
"""
kwargs = {"M": 0.0,
"Tb": 0.0,
"SG": 0.0,
"API": 0.0,
"CH": 0.0,
"n": 0.0,
"I": 0.0,
"Kw": 0.0,
"v100": 0.0,
"v210": 0.0,
"H": 0.0,
"S": 0.0,
"N": 0.0,
"Nc": 0,
"name": "",
"curveType": "",
"T_curve": [],
"X_curve": [],
"P_curve": 101325,
"fit_curve": []}
status = 0
_bool = False
msg = ""
definicion = 0
calculatedMethod = {}
CURVE_TYPE = ["D86", "TBP", "SD", "D1186", "EFV"]
METHODS_PNA = ["Riazi (API)",
"Peng Robinson (1978)",
"Bergman (1977)",
"Van Nes (1951)"]
METHODS_M = ["Riazi-Daubert (1987)",
"Riazi-Daubert (1980)",
"Lee-Kesler (1976)",
"Sim Daubert (1980)",
"Goossens (1971)",
"Twu (1983)"]
METHODS_Tb = ["Riazi-Daubert (1987)",
"Riazi (Heavy fractions)",
"Rowe (1978)",
"Sancet (2007)",
"Silva-Rodríguez (1992)",
"Soreide (1989)"]
METHODS_SG = ["Riazi-Daubert (1987)", "Silva-Rodríguez (1992)"]
METHODS_w = ["Edmister (1958)",
"Lee-Kesler (1976)",
"Korsten (2000)",
"Watansiri-Owens-Starling (1985)",
"Magoulas-Tassios (1990)"]
METHODS_crit = ["Riazi-Daubert (1987)",
"Riazi-Daubert (1980)",
"Cavett (1962)",
"Lee-Kesler (1976)",
"Sim Daubert (1980)",
"Watansiri-Owens-Starling (1985)",
"Rowe (1978)",
"Standing (1977)",
"Willman-Teja (1987)",
"Magoulas-Tassios (1990)",
"Tsonopoulos (1986)",
"Twu (1983)",
"Sancet (2007)",
"Riazi (Heavy fractions)",
"Riazi-Alsahhaf (1998)"]
METHODS_Vc = ["Riazi-Daubert (1987)",
"Riazi-Daubert (1980)",
"Sim Daubert (1980)",
"Watansiri-Owens-Starling (1985)",
"Twu (1983)",
"Hall-Yarborough (1971)",
"Riazi (Heavy fractions)",
"Riazi-Alsahhaf (1998)"]
METHODS_n = ["Riazi-Daubert (1987)",
"Riazi (Heavy fractions)",
"Willman-Teja (1987)"]
METHODS_H = ["Riazi", "Goossens", "ASTM", "Jenkins-Walsh"]
METHODS_Zc = ["Lee-Kesler (1975)",
"Salerno (1986)",
"Nath (1985)",
"Reid (1977)",
"Hougen (1952)"]
[docs]
def __init__(self, **kwargs):
self.Preferences = ConfigParser()
self.Preferences.read(conf_dir+"pychemqtrc")
self.__call__(**kwargs)
def __call__(self, **kwargs):
self.kwargs.update(kwargs)
if kwargs:
self._bool = True
if self.isCalculable():
self.calculo()
[docs]
def isCalculable(self):
"""
1 - Tb y SG
2 - M y SG
3 - Tb y I
4 - M y I
5 - Tb y CH
6 - M y CH
7 - v100 y I
8 - Nc (opción muy poco precisa)
9 - curva de destilación
"""
self.status = 0
self.msg = translate("Petro", "Insufficient input")
self.hasSG = self.kwargs["SG"] or self.kwargs["API"] or \
(self.kwargs["Kw"] and self.kwargs["Tb"])
self.hasRefraction = self.kwargs["n"] or self.kwargs["I"]
self.hasCurve = self.kwargs["curveType"] and self.kwargs["T_curve"] \
and self.kwargs["X_curve"]
# Tipo Definición
if self.hasCurve or (self.kwargs["Tb"] and self.hasSG):
self.definicion = 1
elif self.kwargs["M"] and self.hasSG:
self.definicion = 2
elif self.kwargs["Tb"] and self.hasRefraction:
self.definicion = 3
elif self.kwargs["M"] and self.hasRefraction:
self.definicion = 4
elif self.kwargs["Tb"] and self.kwargs["CH"]:
self.definicion = 5
elif self.kwargs["M"] and self.kwargs["CH"]:
self.definicion = 6
elif self.kwargs["v100"] and self.hasRefraction:
self.definicion = 7
elif self.kwargs["Nc"]:
self.definicion = 8
if self.definicion:
self.status = 1
self.msg = ""
return True
[docs]
def calculo(self):
self.formula = ""
self.cp = []
self.Vliq = 0
self.rackett = 0
self.Tf = 0
self.Hf = 0
self.Gf = 0
if self.hasCurve:
# Create the complete curve, using fitting procedure o using the
# input kwargs parameters
# The curva variable has the values at normaliced volume/weight
# fractions
# 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
if self.kwargs["fit_curve"]:
parCurva = self.kwargs["fit_curve"]
else:
x = self.kwargs["X_curve"]
T = self.kwargs["T_curve"]
parCurva, r = curve_Predicted(x, T)
curva = []
for x in [0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99]:
if x/100 in self.kwargs["X_curve"]:
index = self.kwargs["X_curve"].index(x/100)
T = self.kwargs["T_curve"][index]
else:
T = _Tb_Predicted(parCurva, x/100)
curva.append(unidades.Temperature(T))
# If SG isn't known, use the correlation proposed in Riazi, [29]_
# Eq. 3.17, Pag 102
if self.kwargs["curveType"] == "D86":
a, b, c = 0.08342, 0.10731, 0.26288
elif self.kwargs["curveType"] == "TBP":
a, b, c = 0.10431, 0.12550, 0.26288
elif self.kwargs["curveType"] == "EFV":
a, b, c = 0.09138, -0.0153, 0.36844
else:
pass
self.SG = a*curva[2]**b*curva[6]**c
# Calculate the distillation curve missing
P = unidades.Pressure(10, "mmHg")
Pcurve = self.kwargs["P_curve"]
X = self.kwargs["X_curve"]
if self.kwargs["curveType"] == "D86":
self.D86 = curva
self.TBP = self._D86_TBP(curva, X)
self.EFV = D86_EFV(curva, X, self.SG)
self.SD = None
TBP_10mHg = [Tb_Pressure(t, P, reverse=True) for t in self.TBP]
D1160_10mHg = D1160_TBP_10mmHg(TBP_10mHg)
self.D1160 = [Tb_Pressure(t, P) for t in D1160_10mHg]
elif self.kwargs["TBP"]:
if Pcurve == 101325:
self.TBP = curva
TBP_10mmHg = [Tb_Pressure(t, P, reverse=True)
for t in self.TBP]
else:
self.TBP = [Tb_Pressure(t, Pcurve) for t in curva]
if Pcurve == P:
TBP_10mmHg = curva
else:
TBP_10mmHg = [Tb_Pressure(t, P, reverse=True)
for t in self.TBP]
self.D86 = self._D86_TBP(curva, X, reverse=True)
self.EFV = D86_EFV(self.D86, X, self.SG)
self.SD = None
D1160_10mmHg = D1160_TBP_10mmHg(TBP_10mmHg, reverse=True)
self.D1160 = [Tb_Pressure(t, 10./760) for t in D1160_10mmHg]
elif self.kwargs["SD"]:
self.SD = curva
self.D86 = self._SD_D86(curva, X)
self.TBP = SD_TBP(curva, X)
self.EFV = D86_EFV(self.D86, X, self.SG)
TBP_10mmHg = [Tb_Pressure(t, P, True) for t in self.TBP]
D1160_10mmHg = D1160_TBP_10mmHg(TBP_10mmHg, reverse=True)
self.D1160 = [Tb_Pressure(t, P) for t in D1160_10mmHg]
elif self.kwargs["EFV"]:
if Pcurve == 101325:
self.EFV = curva
else:
self.EFV = [Tb_Pressure(t, Pcurve) for t in curva]
self.D86 = D86_EFV(curva, X, self.SG, reverse=True)
self.SD = None
self.TBP = self._D86_TBP(self.D86, X)
TBP_10mmHg = [Tb_Pressure(t, P, True) for t in self.TBP]
D1160_10mmHg = D1160_TBP_10mmHg(TBP_10mmHg, reverse=True)
self.D1160 = [Tb_Pressure(t, P) for t in D1160_10mmHg]
else:
if Pcurve == P:
D1160_10mmHg = curva
self.D1160 = [Tb_Pressure(t, P) for t in D1160_10mmHg]
elif Pcurve == 101325:
self.D1160 = curva
D1160_10mmHg = [Tb_Pressure(t, P, True) for t in curva]
else:
self.D1160 = [Tb_Pressure(t, Pcurve) for t in curva]
D1160_10mmHg = [Tb_Pressure(t, P, reverse=True)
for t in self.D1160]
TBP_10mmHg = D1160_TBP_10mmHg(D1160_10mmHg)
self.TBP = [Tb_Pressure(t, P) for t in TBP_10mmHg]
self.D86 = self._D86_TBP(self.TBP, X, reverse=True)
self.EFV = D86_EFV(self.D86, X, self.SG)
self.SD = None
# Hardcoded key temperatures in distillation curve
self.T5 = self.D86[1]
self.T10 = self.D86[2]
self.T20 = self.D86[3]
self.T30 = self.D86[4]
self.T40 = self.D86[5]
self.T50 = self.D86[6]
self.T60 = self.D86[7]
self.T70 = self.D86[8]
self.T80 = self.D86[9]
self.T90 = self.D86[10]
# Calculate average boiling points
# Ref. [20] Procdedure 2B1.1
self.VABP = unidades.Temperature((
self.T10 + self.T30 + self.T50 + self.T70 + self.T90)/5.)
SL = (self.T90.F-self.T10.F)/80.
DT1 = -3.062123-0.01829*(self.VABP.F-32)**0.6667+4.45818*SL**0.25
DT2 = -0.56379-0.007981*(self.VABP.F-32)**0.6667+3.04729*SL**0.333
DT3 = -0.23589-0.06906*(self.VABP.F-32)**0.45+1.8858*SL**0.45
DT4 = -0.94402-0.00865*(self.VABP.F-32)**0.6667+2.99791*SL**0.333
self.WABP = unidades.Temperature(self.VABP.F+exp(DT1), "F")
self.MABP = unidades.Temperature(self.VABP.F-exp(DT2), "F")
self.CABP = unidades.Temperature(self.VABP.F-exp(DT3), "F")
self.MeABP = unidades.Temperature(self.VABP.F-exp(DT4), "F")
self.Tb = self.MeABP
# Reid Vapour Pressure, [29]_ Eq 3.100
ReidVP = 3.3922 - 0.02537*self.T5.C - 0.070739*self.T10.C + \
.00917*self.T30.C - .0393*self.T50.C + 6.8257e-4*self.T10.C**2
self.ReidVP = unidades.Pressure(ReidVP, "bar")
# V/L Ratio, [29]_ Eq 106
self.VL_12 = 88.5 - 0.19*self.T70 - 42.5*self.ReidVP.bar
self.VL_20 = 90.6 - 0.25*self.T70 - 39.2*self.ReidVP.bar
self.VL_36 = 94.7 - 0.36*self.T70 - 32.3*self.ReidVP.bar
# Critical vapor locking index, [29]_ Eq 109
self.CVLI = 4.27 + 0.24*self.T70 + 0.069*self.ReidVP.bar
# Fuel volatility index, [29]_ Eq 110
self.FVI = 1000*self.ReidVP.bar + 7*self.T70
# Flash point, API procedure 2B7.1
# Pensky-Martens Closed Cup (ASTM D93)
self.FlashPc = unidades.Temperature(0.69*self.T10.F-118.2, "F")
# Cleveland Open Cup (ASTM D92)
self.FlashPo = unidades.Temperature(0.68*self.T10.F-109.6, "F")
# Calculate PNA decomposition
# self.xp, self.xn, self.xa = self._PNA()
if self.definicion == 8:
# Simple definition known only the number of carbon atoms
prop = prop_Ahmed(self.kwargs["Nc"])
self.M = prop["M"]
self.Tc = prop["Tc"]
self.Pc = prop["Pc"]
self.Vc = prop["Vc"]
self.Tb = prop["Tb"]
self.f_acent = prop["w"]
self.SG = prop["SG"]
self.API = 141.5/self.SG-131.5
self.d20 = self.SG-4.5e-3*(2.34-1.9*self.SG)
else:
# Definition with any pair of variables
# The curve definition is as SG + Tb with aditional properties
# calculated above
# Load input parameters
if self.kwargs["Tb"]:
self.Tb = unidades.Temperature(self.kwargs["Tb"])
if self.kwargs["M"]:
self.M = self.kwargs["M"]
if self.hasSG:
if self.kwargs["SG"]:
self.SG = self.kwargs["SG"]
elif self.kwargs["API"]:
self.SG = 141.5/(self.kwargs["API"]+131.5)
elif self.kwargs["Kw"] and self.kwarg["Tb"]:
self.SG = self.Tb.R**(1./3)/self.kwargs["Kw"]
self.API = 141.5/self.SG-131.5
self.d20 = self.SG-4.5e-3*(2.34-1.9*self.SG)
if self.hasRefraction:
if self.kwargs["n"]:
self.n = self.kwargs["n"]
else:
I = self.kwargs["I"]
self.n = ((1+2*I)/(1-I))**0.5
self.I = (self.n**2-1)/(self.n**2+2)
if self.kwargs["CH"]:
self.CH = self.kwargs["CH"]
if self.kwargs["v100"]:
self.v100 = unidades.Diffusivity(self.kwargs["v100"])
if self.kwargs["v210"]:
self.v210 = unidades.Diffusivity(self.kwargs["v210"])
# Calculate the unknown variables
if not self.kwargs["M"]:
self.M = self._M()
if not self.kwargs["Tb"]:
self.Tb = self._Tb()
if self.kwargs["Kw"]:
self.Kw = self.kwargs["Kw"]
else:
self.Kw = self.Tb.R**(1./3)/self.SG
if not self.hasSG:
self.SG = self._SG()
self.API = 141.5/self.SG-131.5
if not self.hasRefraction:
self.n, self.I = self._n()
if not self.kwargs["CH"]:
self.CH = self._CH()
self.Tc, self.Pc = self._critic()
self.Vc = self._Vc()
self.f_acent = self._f_acent()
self.Zc = self._Zc()
# self.Parametro_solubilidad = prop_Riazi_Alsahhaf(9, self.M), "calcc"
# Tc, Pc, Vc, w, Dm prop_Watansiri_Owens_Starling(Tb, SG, M)
# Tc, Pc, Vc, Tb, d20, I prop_Riazi(SG, tita, val)
if not self.kwargs["v100"] and not self.kwargs["v210"]:
visco = viscoAPI(self.Tb, self.Kw)
self.v100 = visco["v100"]
self.v210 = visco["v210"]
elif not self.kwargs["v210"]:
visco = viscoAPI(self.Tb, self.Kw, v100=self.kwargs["v100"])
self.v210 = visco["v210"]
else:
visco = viscoAPI(self.Tb, self.Kw)
self.v100 = visco["v100"]
# Calculate Viscosity gravity constant (VGC)
if self.kwargs["v210"] and not self.kwargs["v100"]:
T = unidades.Temperature(210, "F")
vSUS = SUS(T, self.v210.cSt)
self.VGC = (self.SG-0.24-0.022*log10(vSUS-35.5))
else:
T = unidades.Temperature(100, "F")
vSUS = SUS(T, self.v100.cSt)
self.VGC = (10*self.SG-1.0752*log10(vSUS-38))/(10-log10(vSUS-38))
if not self.hasSG:
self.d20 = self.SG-4.5e-3*(2.34-1.9*self.SG)
self.Ri = self.n-self.d20/2.
self.m = self.M*(self.n-1.475)
self.VI = self.Viscosity_Index()
try:
self.PourP = PourPoint(self.SG, self.Tb, self.v100)
except NotImplementedError:
self.PourP = None
try:
self.CloudP = CloudPoint(self.SG, self.Tb)
except NotImplementedError:
self.CloudP = None
try:
self.FreezingP = FreezingPoint(self.SG, self.Tb)
except NotImplementedError:
self.FreezingP = None
try:
self.AnilineP = AnilinePoint(self.SG, self.Tb)
self.DieselI = self.API*self.AnilineP.F/100.
except NotImplementedError:
self.AnilineP = None
self.DieselI = None
try:
self.SmokeP = SmokePoint(self.SG, self.Tb)
except NotImplementedError:
self.SmokeP = None
try:
self.CetaneI = CetaneIndex(self.API, self.Tb)
except NotImplementedError:
self.CetaneI = None
if self.kwargs["S"]:
self.S = self.kwargs["S"]
else:
self.S = S_Riazi(self.M, self.SG, self.Ri, self.m)
if self.kwargs["H"]:
self.H = self.kwargs["H"]
else:
self.H = self._H()
self.N = self.kwargs["N"]
# Conradson carbon residue, ref [29]_ Eq 3.141
# HC: HC atomic ratio Eq. 2.122
HC = 11.9147/self.CH
CCR = 148 - 86.96/HC
if CCR < 0:
CCR = 0
elif CCR > 100:
CCR = 100
self.CCR = unidades.Dimensionless(CCR)
self.NetHeating, self.GrossHeating = CombustionHeat(self.API, S=self.S)
newComponente.calculo(self)
[docs]
def tr(self, T):
return T/self.Tc
[docs]
def pr(self, P):
return P/self.Pc.atm
[docs]
def _M(self):
"""Molecular weight calculation"""
# Method defined to calculate properties
if self.definicion != 1:
# The only defined method is the prop_Rizi_Daubert
methodIndex = 0
else:
methodIndex = self.Preferences.getint("petro", "M")
methods = [prop_Riazi_Daubert, prop_Riazi_Daubert_1980,
prop_Lee_Kesler, prop_Sim_Daubert, M_Goossens, prop_Twu]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
M = self.calculatedMethod[method.__name__]["M"]
return unidades.Dimensionless(M)
[docs]
def _critic(self):
"""Critic pressure and temperature calculation"""
methodIndex = self.Preferences.getint("petro", "critical")
# Discard method with incomplete input
if methodIndex in [1, 2, 3, 4, 10, 11] and self.definicion != 1:
methodIndex = 0
if methodIndex in [7, 9] and self.definicion != 2:
methodIndex = 0
if methodIndex in [6, 12] and not self.kwargs["M"]:
methodIndex = 0
if methodIndex == 8 and not self.kwargs["Tb"]:
methodIndex = 0
if methodIndex in [13, 14] and self.definicion not in [1, 2]:
methodIndex = 0
methods = [prop_Riazi_Daubert, prop_Riazi_Daubert_1980, prop_Cavett,
prop_Lee_Kesler, prop_Sim_Daubert,
prop_Watansiri_Owens_Starling, prop_Rowe, prop_Standing,
prop_Willman_Teja, prop_Magoulas_Tassios, prop_Tsonopoulos,
prop_Twu, prop_Sancet, prop_Riazi, prop_Riazi_Alsahhaf]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
Tc = self.calculatedMethod[method.__name__]["Tc"]
Pc = self.calculatedMethod[method.__name__]["Pc"]
return unidades.Temperature(Tc), unidades.Pressure(Pc)
[docs]
def _Vc(self):
"""Critic volume calculation"""
methodIndex = self.Preferences.getint("petro", "vc")
# Discard method with incomplete input
if methodIndex in [1, 2, 4] and self.definicion != 1:
methodIndex = 0
if methodIndex == 5 and self.definicion != 2:
methodIndex = 0
if methodIndex in [3, 6, 7] and self.definicion not in [1, 2]:
methodIndex = 0
methods = [prop_Riazi_Daubert, prop_Riazi_Daubert_1980,
prop_Watansiri_Owens_Starling, prop_Twu, vc_Hall_Yarborough,
prop_Riazi, prop_Riazi_Alsahhaf]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
Vc = self.calculatedMethod[method.__name__]["Vc"]
return unidades.SpecificVolume(Vc)
[docs]
def _f_acent(self):
"""Acentric factor calculation"""
methodIndex = self.Preferences.getint("petro", "f_acent")
# This procedure has no limitation, the chossen method use calculated
# properties is isn't in input
methods = [prop_Edmister, prop_Lee_Kesler, w_Korsten,
prop_Watansiri_Owens_Starling, prop_Magoulas_Tassios]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
w = self.calculatedMethod[method.__name__]["w"]
return unidades.Dimensionless(w)
[docs]
def _Tb(self):
"""Boiling temperature calculation"""
methodIndex = self.Preferences.getint("petro", "Tb")
if self.definicion not in [1, 2] and methodIndex > 1:
# Set the method to Riaxi Daubert if the choosen method is
# unavailable for the input parameters
methodIndex = 0
methods = [prop_Riazi_Daubert, prop_Riazi, prop_Rowe, prop_Sancet,
prop_Silva_Rodriguez, Tb_Soreide]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
Tb = self.calculatedMethod[method.__name__]["Tb"]
return unidades.Temperature(Tb)
[docs]
def _SG(self):
"""Specific gravity procedure calculation"""
methodIndex = self.Preferences.getint("petro", "SG")
if methodIndex == 1 and not self.kwargs["M"]:
# If molecular weight isn't in input parameter the Silva-Rodriguez
# method can't be used
methodIndex = 0
methods = [prop_Riazi_Daubert, prop_Silva_Rodriguez]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
SG = self.calculatedMethod[method.__name__]["SG"]
return unidades.Dimensionless(SG)
[docs]
def _n(self):
"""Refractive index procedure calculation"""
methodIndex = self.Preferences.getint("petro", "n")
if methodIndex == 2 and not self.kwargs["Tb"]:
# If boiling temperature isn't in input parameter the Willman-Teja
# method can't be used
methodIndex = 0
if self.definicion not in [1, 2] and methodIndex == 1:
methodIndex = 0
methods = [prop_Riazi_Daubert, prop_Willman_Teja, prop_Riazi]
method = methods[methodIndex]
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
if method == prop_Willman_Teja:
n = self.calculatedMethod[method.__name__]["n"]
I = (n**2-1)/(n**2+2)
else:
I = self.calculatedMethod[method.__name__]["I"]
n = ((1+2*I)/(1-I))**0.5
return unidades.Dimensionless(n), unidades.Dimensionless(I)
[docs]
def _CH(self):
"""Carbon-Hydrogen procedure calculation"""
method = prop_Riazi_Daubert
if method.__name__ not in self.calculatedMethod:
self.calculateMethod(method)
CH = self.calculatedMethod[method.__name__]["CH"]
return unidades.Dimensionless(CH)
[docs]
def calculateMethod(self, method):
"""Calculate method of properties and save to avoid other iteration"""
Tb_SG = [prop_Riazi_Daubert_1980, prop_Lee_Kesler, prop_Sim_Daubert,
prop_Twu]
M_SG = [prop_Standing, prop_Magoulas_Tassios, Tb_Soreide,
vc_Hall_Yarborough]
M = [prop_Rowe, prop_Sancet, prop_Silva_Rodriguez]
if method == prop_Riazi_Daubert:
# Special case for Riazi_daubert advanced method
if self.definicion in [1, 8]:
prop = prop_Riazi_Daubert("Tb", self.Tb, "SG", self.SG)
elif self.definicion == 2:
prop = prop_Riazi_Daubert("M", self.M, "SG", self.SG)
elif self.definicion == 3:
prop = prop_Riazi_Daubert("Tb", self.Tb, "I", self.I)
elif self.definicion == 4:
prop = prop_Riazi_Daubert("M", self.M, "I", self.I)
elif self.definicion == 5:
prop = prop_Riazi_Daubert("Tb", self.Tb, "CH", self.CH)
elif self.definicion == 6:
prop = prop_Riazi_Daubert("M", self.M, "CH", self.CH)
elif self.definicion == 7:
prop = prop_Riazi_Daubert("M", self.v100, "I", self.I)
elif method == prop_Riazi:
if self.definicion in [1, 8]:
prop = prop_Riazi(self.SG, "Tb", self.Tb)
elif self.definicion == 2:
prop = prop_Riazi(self.SG, "M", self.M)
elif method == prop_Cavett:
prop = prop_Cavett(self.Tb, self.API)
elif method == M_Goossens:
prop = M_Goossens(self.Tb, self.d20)
elif method == prop_Willman_Teja:
prop = prop_Willman_Teja(self.Tb)
elif method == prop_Watansiri_Owens_Starling:
prop = prop_Watansiri_Owens_Starling(self.Tb, self.SG, self.M)
elif method == prop_Riazi_Alsahhaf:
prop = prop_Riazi_Alsahhaf(self.Tb, self.M, self.d20)
elif method == prop_Edmister:
prop = prop_Edmister(Tb=self.Tb, Tc=self.Tc, Pc=self.Pc)
elif method in Tb_SG:
prop = method(self.Tb, self.SG)
elif method in M_SG:
prop = method(self.M, self.SG)
elif method in M:
prop = method(self.M)
self.calculatedMethod[method.__name__] = prop
[docs]
def _Zc(self):
methods = [Zc_Lee_Kesler, Zc_Salerno, Zc_Nath, Zc_Reid, Zc_Hougen]
Zc = methods[self.Preferences.getint("petro", "Zc")]
return Zc(self.f_acent)
[docs]
def _H(self):
if self.Preferences.getint("petro", "H") == 0:
H = H_Riazi(self.S, self.CH)
elif self.Preferences.getint("petro", "H") == 1:
H = H_Goossens(self.M, self.n, self.d20)
elif self.Preferences.getint("petro", "H") == 2:
if self.hasCurve:
Tb = (self.T10+self.T50+self.T90)/3.
else:
Tb = self.Tb
H = H_ASTM(Tb, self.SG, self.xa)
else:
H = H_Jenkins_Walsh(self.SG, self.AnilineP)
return H
[docs]
def _D86_TBP(self, D86, reverse=False):
"""Use the preferences to calcuate the TBP distillation curve from D86
with the desired method"""
index = self.Preferences.getint("petro", "curve")
method = [D86_TBP_Riazi, D86_TBP_Daubert][index]
TBP = method(D86, reverse)
return TBP
[docs]
def _SD_D86(self, SD):
"""Use the preferences to calcuate the D86 distillation curve from SD
with the desired method"""
index = self.Preferences.getint("petro", "curve")
method = [SD_D86_Riazi, SD_D86_Daubert][index]
D86 = method(SD)
return D86
[docs]
def _PNA(self):
"""Calculate the Paraffin-Naphthenes-Aromatics group composition"""
if self.Preferences.getint("petro", "PNA") == 0:
xp, xn, xa = PNA_Riazi(
self.M, self.SG, self.n, d20=None, VGC=self.VGC, CH=None)
elif self.Preferences.getint("petro", "PNA") == 1:
xp, xn, xa = PNA_Bergman(self.Tb, self.SG, self.Kw)
elif self.Preferences.getint("petro", "PNA") == 2:
xp, xn, xa = PNA_Peng_Robinson(self.Nc, self.M, self.WABP)
else:
xp, xn, xa = PNA_van_Nes(self.M, self.n, self.d20, self.S)
return xp, xn, xa
[docs]
def Viscosity_Index(self):
"""Método de calculo del indice de viscosidad, API procedure 11A6.1, pag 1083"""
if self.v210.cSt>70:
L=0.8353*self.v210.cSt**2+14.67*self.v210.cSt-216
H=0.1684*self.v210.cSt**2+11.85*self.v210.cSt-97
else: #Ajuste de los datos de la tabla, producción propia
"""Polynomial Fit of dataset: Table1_L, using function: a0+a1*x+a2*x^2+a3*x^3+a4*x^4+a5*x^5
--------------------------------------------------------------------------------------
Chi^2/doF = 1,4854228443647e+00
R^2 = 0,9999990418201
Adjusted R^2 = 0,9999990229086
RMSE (Root Mean Squared Error) = 1,218779243491
RSS (Residual Sum of Squares) = 453,0539675312
---------------------------------------------------------------------------------------
Polynomial Fit of dataset: Table1_H, using function: a0+a1*x+a2*x^2+a3*x^3+a4*x^4+a5*x^5
--------------------------------------------------------------------------------------
Chi^2/doF = 1,7949865589785e-01
R^2 = 0,999998895674
Adjusted R^2 = 0,9999988738781
RMSE (Root Mean Squared Error) = 0,4236728170391
RSS (Residual Sum of Squares) = 54,74709004884
---------------------------------------------------------------------------------------
"""
L=-1.2756691045812e+01+6.1466654146190*self.v210.cSt+9.9774520581931e-01*self.v210.cSt**2-2.5045430263656e-03*self.v210.cSt**3+3.1748553181177e-05*self.v210.cSt**4-1.8264076604682e-07*self.v210.cSt**5
H=-7.6607640162508+5.4845434135144*self.v210.cSt+0.38222987985934*self.v210.cSt**2-4.6556329076069e-03*self.v210.cSt**3+5.1653200038471e-05*self.v210.cSt**4-2.3274903246922e-07*self.v210.cSt**5
if self.v100.cSt>H:
VI=(L-self.v100.cSt)/(L-H)*100
else:
N=(log10(H)-log10(self.v100.cSt))/log10(self.v210.cSt)
VI=(10**N-1)/0.00715+100
return VI
# def Pv_Tsonopoulos(self, T):
# """Tsonopoulos, C., Heidman, J. L., and Hwang, S.-C.,Thermodynamic and
# Transport Properties of Coal Liquids, An Exxon Monograph, Wiley, New York, 1986."""
# Tr=T/self.tpc
# A=5.671485+12.439604*self.f_acent
# B=5.809839+12.755971*self.f_acent
# C=0.867513+9.654169*self.f_acent
# D=0.1383536+0.316367*self.f_acent
# pr=exp(A-B/Tr-C*log(Tr)+D*Tr**6)
# return unidades.Pressure(pr, "bar")
# def Pv_simple(self, T):
# """eq 7.25"""
# pv=10**(3.2041*(1.-0.998*(self.Tb-41)/(self.Tb-41)*(1393-T)/(1393-self.Tb)))
# return unidades.Pressure(pr, "bar")
# def Pv_gasoline(self, T):
# """Método de cálculo de la presión de vapor de productos terminados de petroleo, gasolinas, naftas, etc, API procedure 5B1.1 pag 404"""
# #FIXME: No da un resultado correcto, posiblemente algún parénteis mal puesto
# t=unidades.Temperature(T)
# SL=(unidades.Temperature(self.D86[-3]).F-unidades.Temperature(self.D86[1]).F)/15.
# p=exp(1/t.R*(21.36412862-6.7769666*sqrt(SL)-0.93213944*log(self.ReidVP.psi)+1.42680425*sqrt(SL)*log(self.ReidVP.psi)-0.29458386*self.ReidVP.psi+(-0.00568374+0.00577103*sqrt(SL)-0.00106045*sqrt(SL)*log(self.ReidVP.psi)+0.00060246*self.ReidVP.psi)*t.R+(-10177.78660360+2306.00561642*sqrt(SL)+1097.68947465*log(self.ReidVP.psi)-463.19014182*sqrt(SL)*log(self.ReidVP.psi)+65.61239475*self.ReidVP.psi+0.13751932*self.ReidVP.psi**2)))
# return unidades.Pressure(p, "psi")
# def Pv_API(self, T):
# """Método de cálculo de la presión de vapor de fracciones de petroleo, API procedure 5B1.2 pag 406"""
# t=unidades.Temperature(T)
# p=exp(7.78511307-1.08100387*log(self.ReidVP.psi)+0.05319502*self.ReidVP.psi+0.00451316*t.R+(-5756.85623050+1104.41248797*log(self.ReidVP.psi)-0.00068023*self.ReidVP.psi**4)/t.R)
# return unidades.Pressure(p, "psi")
# def RhoL(self, T):
# """Método de cálculo de la densidad del líquido de fraciones de petroleo
# a presión atmosférica, API procedure 6A3.5,pag 494"""
# t=unidades.Temperature(T)
# rho=62.3636*sqrt(self.SG**2-(1.2655*self.SG-0.5098+8.011e-5*self.Tb.R)*(t.R-519.67)/self.Tb.R)
# return unidades.Density(rho, "lbft3")
# def RhoL_Rackett(self, T):
# """Método de cálculo de la densidad de la fase líquida de fracciones
# de petróleo a presión atmosférica, API procedure 6A3.6 pag 495"""
# rho=self.SG*1000
# t=unidades.Temperature(60, "F")
# Zra=(self.Pc.atm/(rho/self.M*R_atml*self.Tc))**(1/(1+(1-t/self.Tc)**(2./7)))
# inv=R_atml*self.Tc/self.Pc.atm*Zra**(1+(1-T/self.Tc)**(2./7))
# return unidades.Density(1/inv*self.M, "gl")
# def RhoL_Presion(self, T, P):
# """Método de cálculo de la densidad de la fase líquida de fracciones de petróleo a alta presión, API procedure 6A3.7, 6A3.10 pag 497"""
# rho0=self.RhoL_Rackett(T)
# p=unidades.Pressure(P, "atm")
# t=unidades.Temperature(T)
# B20=10**(-6.1e-4*t.F+4.9547+0.7133*rho0.kgl)
# m=21646+0.0734*p.psig+1.4463e-7*p.psig**2
# X=(B20-100000)/23170
# B1=1.52e+4+4.704*p.psig-2.5807e-5*p.psig**2+1.0611e-10*p.psig**3
# Bt=m*X+B1
# return unidades.Density(rho0/(1.0-p.psig/Bt))
# def Entalpia(self, T, P):
# """Cálculo de la entalpia de fracciones petrolíferas, API procedure 7B4.7, pag 658"""
# T=unidades.Temperature(T)
# if T<self.Tb and self.tr(T)<=0.8 and self.pr(P)<1.:
# A1=1e-3*(-1171.26+(23.722+24.907*self.SG)*self.watson+(1149.82-46.535*self.watson)/self.SG)
# A2=1e-6*((1.+0.82463*self.watson)*(56.086-13.817/self.SG))
# A3=-1e-9*((1.+0.82463*self.watson)*(9.6757-2.3653/self.SG))
# H=A1*(T.R-259.7)+A2*(T.R**2-259.7**2)+A3*(T.R**3-259.7**3)
# else:
# Hl=self.Entalpia(0.8*self.Tc, 0.1*self.Pc.atm)
# if T<self.Tb:
# H_adimensional_presion=Lee_Kesler_Entalpia_lib(self.tr(T), self.pr(P), self.f_acent, fase=1)
# else:
# H_adimensional_presion=Lee_Kesler_Entalpia_lib(self.tr(T), self.pr(P), self.f_acent, fase=0)
# if 10.<self.watson<12.8 and 0.7<self.SG<0.885:
# B4=((12.8/self.watson-1.)*(1.-10./self.watson)*(self.SG-0.885)*(self.SG-0.7)*1e4)**2
# else:
# B4=0
# B1=1e-3*(-356.44+29.72*self.watson+B4*(295.02-248.49/self.SG))
# B2=1e-6*(-146.24+(77.62-2.772*self.watson)*self.watson-B4*(301.42-253.87/self.SG))
# B3=1e-9*(-56.487-2.95*B4)
# H=Hl.Btulb+B1*(T.R-0.8*self.Tc.R)+B2*(T.R**2-0.64*self.Tc.R**2)+B3*(T.R**3-0.512*self.Tc.R**3)+R_Btu*self.Tc.R/self.M*(4.507+5.266*self.f_acent-H_adimensional_presion)
# return unidades.Enthalpy(H, "Btulb")
# def Cp_liquid_API(self, T):
# """Cálculo de la capacidad calorífica isobárica de la fase liquida de fracciones petrolíferas, API procedure 7D2.2, pag 702"""
# t=unidades.Temperature(T)
# A1=-1.17126+(0.023722+0.024907*self.SG)*self.watson+(1.14982-0.046535*self.watson)/self.SG
# A2=1e-4*(1+0.82463*self.watson)*(1.12172-0.27634/self.SG)
# A3=-1e-8*(1+0.82463*self.watson)*(2.9027-0.70958/self.SG)
# return unidades.SpecificHeat(A1+A2*t.R+A3*t.R**2, "BtulbF")
# def Cp_liquid_Tsonopoulos(self, T):
# """Tsonopoulos, C., Heidman, J. L., and Hwang, S.-C.,Thermodynamic and Transport Properties of Coal Liquids, An Exxon Monograph, Wiley, New York, 1986."""
# cp=(0.28299+0.23605*self.watson)*(0.645-0.05959*self.SG+(2.32056-0.94752*self.SG)*(T/1000.-0.25537))
# return unidades.SpecificHeat(cp, "kJkgK")
# def Cp_liquid_Kesler_Lee(self, T):
# """Kesler, M. G. and Lee, B. I., "Improve Prediction of Enthalpy of Fractions," Hydrocarbon Processing, Vol. 55, No. 3, 1976, pp. 153-158."""
# a=1.4651+0.2302*self.watson
# b=0.306469-0.16734*self.SG
# c=0.001467-0.000551*self.SG
# return unidades.SpecificHeat(a*(b+c*T), "kJkgK")
# def Cp_liquid_Bondi(self, T):
# """Ref Eq 7.40 Riazi - Characterization of petroleum fraction, pag 333"""
# Tr=T/self.Tc
# Cp_ideal
# cp_adimensional=1.586+0.49*(1-Tr)+self.f_acent*(4.2775+6.3*(1-Tr)**(1./3)/Tr+0.4355/(1-Tr))
# return unidades.SpecificHeat(cp_adimensional*R+Cp_ideal, "kJkgK")
# def Lee_Kesler_lib_Cp(self, T, P):
# """Librería para el cálculo de capacidades calorificas, usada a continuación en diferentes funciones
# Procedure API 7E1.6 Pag.726"""
# #FIXME: No concuerdan mucho los valores de cp y cv con los valores por DIPPR
# Tr=self.tr(T)
# vr0, vrh=self.Lee_Kesler_lib(T, P.atm, "gas")
# E=0.042724/2/Tr**3/0.060167*(0.65392+1-(0.65392+1+0.060167/vr0**2)*exp(-0.060167/vr0**2))
# Cv0=-2*(0.154790+3*0.030323/Tr)/Tr**2/vr0+6*E
# E=0.041577/2/Tr**3/0.03754*(1.226+1-(1.226+1+0.03754/vrh**2)*exp(-0.03754/vrh**2))
# Cvh=-2*(0.027655+3*0.203488/Tr)/Tr**2/vrh+3*0.016901/Tr**3/vrh**2+6*E
# return Cv0, Cvh
# def Cp_gas(self, T, P):
# """Cálculo de la capacidad calorífica isobárica de la fase vapor de fracciones petrolíferas, API procedure 7D4.2, pag 717"""
# if 10.<=self.watson<=12.8 and 0.70<self.SG<=0.885:
# A4=((12.8/self.watson-1.)*(1.-10/self.watson)*(self.SG-0.885)*(self.SG-0.7)*1e4)**2
# else: A4=0
# A1=-0.35644+0.02972*self.watson+A4*(0.29502-0.24846/self.SG)
# A2=-1e-4*(2.9247-(1.5524-0.05543*self.watson)*self.watson+A4*(6.0283-5.0694/self.SG))
# A3=-1e-7*(1.6946+0.0844*A4)
# #TODO: calculo factor cp adimensional
# Cp0, Cph=self.Lee_Kesler_lib_Cp(T, P)
# # Cp_adimensional=-1.107
# Cp_adimensional=Cp0+self.f_acent/0.3978*(Cph-Cp0)
# return unidades.SpecificHeat(A1+A2*t.R+A3*t.R**2-R_Btu/self.M*Cp_adimensional, "BtulbF")
# def flash(self):
# """Método de cálculo del equilibrio líquido-vapor, API procedure 8D1.5, pag 828"""
# pass
# def flash2(self):
# """Método de cálculo del equilibrio líquido-vapor, cuando parte de la composición sí es conocida, API procedure 8D1.6, pag 832"""
# pass
# def Tension_API(self,T):
# """Método de cálculo de la tensión superficial de fracciones petrolíferas, API procedure 10A3.2, pag 997"""
# t=unidades.Temperature(T)
# sigma=673.7/self.watson*((self.Tc.R-t.R)/self.Tc.R)**1.232
# return unidades.Tension(sigma, "dyncm")
# def Tension_Baker_Swerdloff(self, T, P=1):
# """Baker, O. and Swerdloff, W.: "Finding Surface Tension of Hydrocarbon Liquids," Oil and Gas J. (Jan. 2, 1956) 125"""
# t=unidades.Temperature(T)
# p=unidades.Pressure(P, "atm")
# s68=39.-0.2571*self.API
# s100=37.5-0.2571*self.API
# if t.F<=68.:
# s=s68
# elif t.F<100:
# s=s68-((t.F-68)*(s68-s100))/32
# else:
# s=s100
# F=1.-0.024*p.psi**0.45
# return unidades.Tension(F*s, "dyncm")
# def Tension_Tsonopoulos(self, T):
# """Método alternativo de cálculo de la tensión superficial
# Tsonopoulos, C., Heidman, J. L., and Hwang, S.-C.,Thermodynamic and Transport Properties of Coal Liquids, An Exxon Monograph, Wiley, New York, 1986."""
# Pa=1.7237*self.Tb**0.05873*self.SG**-0.64927
# rhoL=self.RhoL(T)
# rhoV
# return unidades.Tension((Pa*(rhoL-rhoV))**4, "dyncm")
# def Tension_Miqueu(self, T):
# """Método alternativo de cálculo de la tensión superficial
# Miqueu, C., Satherley, J., Mendiboure, B., Lachiase, J., and Graciaa, A., "The Effect of P/N/A Distribution on the Parachors of Petroleum Fractions," Fluid Phase Equilibria, Vol. 180, 2001,pp. 327-344."""
# Pa=(0.85-0.19*self.f_acent)*self.Tc**(12/11.)/(self.Pc.bar/10)**(9./11)
# rhoL=self.RhoL(T)
# rhoV
# return unidades.Tension((Pa/self.M*(rhoL-rhoV))**(11./3), "dyncm")
# def Tension_PNA(self, T):
# """Método alternativo de cálculo de la tensión superficial si se conoce la composición PNA
# Miqueu, C., Satherley, J., Mendiboure, B., Lachiase, J., and Graciaa, A., "The Effect of P/N/A Distribution on the Parachors of Petroleum Fractions," Fluid Phase Equilibria, Vol. 180, 2001,pp. 327-344."""
# PaP=27.503+2.9963*self.M
# PaN=18.384+2.7367*self.M
# PaA=25.511+2.8332*self.M
# Pa=self.xa*PaA+self.xn*PaN+self.xp*PaP
# rhoL=self.RhoL(T)
# rhoV
# return unidades.Tension((Pa/self.M*(rhoL-rhoV))**(11./3), "dyncm")
# def Mu_Singh(self, T, mu):
# """Calculo de la viscosidad cinemática de fracciones petrolíferas a baja presión, conocida la viscosidad cinemática a 100ºF, API procedure 11A4.1 pag 1054
# mu: viscosidad cinematica experimental a 100ºF
# valor obtenido en centistokes"""
# t=unidades.Temperature(T)
# S=0.28008*log10(mu)+1.8616
# B=log10(mu)+0.86960
# return 10**(B*(559.67/t.R)**S-0.86960)
# def V100_API(self):
# """Cálculo de la viscosidad cinemática a 100ºF de fracciones petrolíferas a baja presión, API procedure 11A4.2, pag 1056"""
# A1=34.9310-8.84387e-2*self.Tb.R+6.73513e-5*self.Tb.R**2-1.01394e-8*self.Tb.R**3
# A2=-2.92649+6.98405e-3*self.Tb.R-5.09947e-6*self.Tb.R**2+7.49378e-10*self.Tb.R**3
# mu_ref=10**(-1.35579+8.16059e-4*self.Tb.R+8.38505e-7*self.Tb.R**2)
# mu_cor=10**(A1+A2*self.watson)
# return unidades.Diffusivity(mu_ref+mu_cor, "cSt")
# def V210_API(self):
# """Cálculo de la viscosidad cinemática a 210ºF de fracciones petrolíferas a baja presión, API procedure 11A4.2, pag 1056"""
# if self.v100:
# v100=self.v100
# else:
# v100=self.V100_API()
# return unidades.Diffusivity(10**(-1.92353+2.41071e-4*self.Tb.R+0.5113*log10(self.Tb.R*v100)), "cSt")
# def Viscosidad_ASTM(self, T, T1=unidades.Temperature(100, "F"), T2=unidades.Temperature(210, "F"), mu1=0, mu2=0):
# """Cálculo de la viscosidad cinemática a cualquier temperatura, conociendo otros dos valores de viscosidad a otras temperaturas, API procedure 11A4.4, pag 1063
# Parámetros:
# T:Temperatura a la que se quiere calcular la viscosidad
# T1,T2:opcional, temperatura a la que se conoce la viscosidad
# mu1,mu2:opcionales, valores de viscosidad conocidos
# Si no se suministran los parámetros opcionales se consideran los valores a 100 y 210ºF
# """
# if mu1==0:
# mu1=self.v100.cSt
# if mu2==0:
# mu2=self.v210.cSt
# t=unidades.Temperature(T)
# Z1=mu1+0.7+exp(-1.47-1.84*mu1-0.51*mu1**2)
# Z2=mu2+0.7+exp(-1.47-1.84*mu2-0.51*mu2**2)
# B=(log10(log10(Z1))-log10(log10(Z2)))/(log10(T1.R)-log10(T2.R))
# Z=10**(10**(log10(log10(Z1))+B*(log10(t.R)-log10(T1.R))))
# return unidades.Diffusivity(Z-0.7-exp(-0.7487-3.295*(Z-0.7)+0.6119*(Z-0.7)**2-0.3191*(Z-0.7)**3), "cSt")
# def Viscosidad_liquido_blend(self, T, fraccion_masica, petro1, petro2):
# """Método de cálculo de la viscosidad de líquidos en mezclas de fracciones petrolíferas, API procedure 11A4.5, pag 1066
# Los parámetros petro tienen la estructura [T1,T2,mu1,mu2]"""
# #TODO: de momoento el procedimiento requiere como parámetros petro1 y petro2, matrices con cuatro elementos, dos temperaturas y sus correspondientes viscosidades, cuando se defina correctamente las fracciones petroliferas estos parámetros serán sustituidos por un simple id de fracción petrolífera
# t=unidades.Temperature(T)
# T1=unidades.Temperature(petro1[0])
# T2=unidades.Temperature(petro1[1])
# ml=(log(log(petro1[3]+0.7))-log(log(petro1[2]+0.7)))/(log(T2.R)-log(T1.R))
# bl=log(log(petro1[2]+0.7))-ml*log(T1.R)
# mh=(log(log(petro2[3]+0.7))-log(log(petro2[2]+0.7)))/(log(T2.R)-log(T1.R))
# bh=log(log(petro2[2]+0.7))-mh*log(T1.R)
# Tl=exp((log(log(petro2[2]+0.7))-bl)/ml)
# Tx=exp(fraccion_masica[0]*log(Tl)+fraccion_masica[1]*log(T1.R))
# Th=exp((log(log(petro1[3]+0.7))-bh)/mh)
# Ty=exp(fraccion_masica[0]*log(T2.R)+fraccion_masica[1]*log(Th))
# m=(log(log(petro1[3]+0.7))-log(log(petro2[2]+0.7)))/(log(Ty)-log(Tx))
# b=log(log(petro2[2]+0.7))-m*log(Tx)
# return exp(exp(m*log(t.R)+b))-0.7
# def ThCond_Liquido_simple(self, T):
# """Método de cálculo de la conductividad térmica de fracciones
# petrolíferas líquidas a baja presión, API procedure 12A3.1, pag 1149"""
# t=unidades.Temperature(T)
# k=0.07577-4.1e-5*t.F
# return unidades.Conductividad_termica(k, "BtuhftF")
# def ThCond_Liquido_Tsonopoulos(self, T):
# """Método de cálculo de la conductividad térmica de fracciones petrolíferas líquidas a baja presión,
# Tsonopoulos, C., Heidman, J. L., and Hwang, S.-C.,Thermodynamic and Transport Properties of Coal Liquids, An Exxon Monograph, Wiley, New York, 1986."""
# k=0.05351+0.10177*(1-T/self.Tc)**(2./3)
# return unidades.Conductividad_termica(k)
# def ThCond_Liquido_API(self, T):
# """Método de cálculo de la conductividad térmica de fracciones
# petrolíferas en líquidas a baja presión, API procedure 12A3.2, pag 1151"""
# t=unidades.Temperature(T)
# k=self.Tb.R**0.2904*(9.961e-3-5.364e-6*t.F)
# return unidades.Conductividad_termica(k, "BtuhftF")
# def ThCond_Gas(self, T):
# """Método de cálculo de la conductividad térmica de vapores de
# fracciones petrolíferas a baja presión, API procedure 12B3.1, pag 1168"""
# t=unidades.Temperature(T)
# k=0.0013349+0.24628/self.M+1.1493/self.M**2+t.F*(3.2768e-5+4.1881e-5/self.M+0.0018427/self.M**2)
# return unidades.Conductividad_termica(k, "BtuhftF")
if __name__ == '__main__':
# petroleo=Petroleo()
# print petroleo.VABP
# print "WABP: ", petroleo.WABP
# print "MABP: ", petroleo.MABP
# print "CABP: ", petroleo.CABP
# print "MeABP: ", petroleo.MeABP.F
# print "Peso molecular: ", petroleo.M
# print "TBP:", petroleo.D86_to_TBP([350, 380, 404, 433, 469])
# print "TBP:", petroleo.TBP_to_D86(petroleo.D86_to_TBP([350, 380, 404, 433, 469]))
# print "TBP:", petroleo.D2887_to_TBP([293, 305, 324, 336, 344, 359, 369])
# print "TBP:", petroleo.D2887_to_D86([293, 305, 324, 336, 344, 359, 369])
# print petroleo.RhoL_altapresion(unidades.Temperature(68, "F"), 368.4482)
# s=petroleo.Reduccion_volumetrica(5000/95000., 86.5-30.7)
# print s*5000
# t=unidades.Temperature(455, "F")
# print petroleo.Cp_liquido(t).BtulbF
# print petroleo.Cp_gas(t).BtulbF
# print petroleo.Tension_superficial(t).dyncm
# print petroleo.Viscosidad_Singh(t, 1.38)
# print petroleo.Viscosidad_Fitzgerald_100()
# print petroleo.Viscosidad_Fitzgerald_210()
# print petroleo.Viscosidad_ASTM(t, unidades.Temperature(32, "F"), unidades.Temperature(104, "F"), 1.644, 0.925)
# print petroleo.Viscosidad_liquido_blend(t, [0.6, 0.4], [unidades.Temperature(50, "F"), unidades.Temperature(122, "F"), 14.22, 4.85], [unidades.Temperature(50, "F"), unidades.Temperature(122, "F"), 163.4, 24.98])
# print petroleo.Conductividad_termica_liquido_simple(t).BtuhftF
# print petroleo.Conductividad_termica_liquido(t).BtuhftF
# print petroleo.Conductividad_termica_gas(t).BtuhftF
# print PNA_Peng_Robinson(7, 655, 94)
# gas=Natural_Gas(0.699)
# print gas.ppc.psi, gas.tpc.R
# print Z_Papay(1.346, 5.603)
# print Z_Hall_Yarborough(1.346, 5.603)
# print Z_Dranchuk_Abu_Kassem(1.346, 5.603)
# print Z_Dranchuk_Purvis_Robinson(1.346, 5.603)
# print Z_ShellOil(1.346, 5.603)
# print Z_Beggs_Brill(1.346, 5.603)
# print Z_Sarem(1.346, 5.603)
# print Z_Gopal(1.346, 5.603)
# petroleo=Petroleo(API=44.4, Tb=unidades.Temperature(319., "F"))
# print petroleo.SG
# print petroleo.M, petroleo.tc.F, petroleo.pc.psi, petroleo.vc.ft3lb
# t=unidades.Temperature(325, "F")
# print petroleo.Cp_liquido(t).BtulbF
# petroleo=Petroleo(API=22.5, M=339.7)
# print petroleo.peso_molecular_pesado(55.1, 5.87)
# print petroleo.watson
# petroleo=Petroleo(SG=0.9046, Tb=unidades.Temperature(798, "F"))
# print petroleo.M
# print petroleo.refractive_index()
# print petroleo.composicion_molecular(v100=336)
# petroleo=Petroleo(SG=0.839, Tb=unidades.Temperature(972, "R"), v100=3)
# print petroleo.pour_point().R
# petroleo=Petroleo(SG=0.8304, Tb=unidades.Temperature(570.2, "F"))
# print petroleo.aniline_point().R, petroleo.watson
# petroleo=Petroleo(SG=0.853, Tb=unidades.Temperature(414.5, "F"))
# print petroleo.smoke_point().mm, petroleo.watson
# petroleo=Petroleo(SG=0.799, Tb=unidades.Temperature(874.5, "R"))
# print petroleo.freezing_point().R, petroleo.watson
# petroleo=Petroleo(SG=0.787, Tb=unidades.Temperature(811.5, "R"))
# print petroleo.cloud_point().R
# petroleo=Petroleo(API=32.3, Tb=unidades.Temperature(617, "F"))
# print petroleo.cetane_index()
# d86=[unidades.Temperature(t, "F") for t in [149, 230, 282, 325, 429]]
# petroleo=Petroleo(D86=d86)
# print petroleo.VABP.F
# print petroleo.MABP.F
# print petroleo.WABP.F
# print petroleo.CABP.F
# print petroleo.MeABP.F
# print petroleo.pv_fraccion(unidades.Temperature(70, "F"), unidades.Pressure(6, "psi").atm).psi
# t, bool= Hydrates_Sloan("T", T=300, P=10, y=[0.78, 0.06, 0.03, 0.01, 0.02, 0.06, 0.04, 0.0])
# print t.F
# petroleo=Petroleo(API=30.6, Tb=unidades.Temperature(538, "F"))
# print petroleo.RhoL(unidades.Temperature(160, "F")).gml
# petroleo=Petroleo(API=31.4, Tb=unidades.Temperature(538, "F"))
# t=unidades.Temperature(68, "F")
# p=unidades.Pressure(5400, "psig")
# print petroleo.RhoL_Presion(t, p.atm).gml
# petroleo=Petroleo(API=43.5, Tb=unidades.Temperature(407.2, "F"))
# t=unidades.Temperature(600, "F")
# p=unidades.Pressure(50, "psi")
# print petroleo.Entalpia(t, p.atm).Btulb
# d86=[unidades.Temperature(t, "F") for t in [304, 313, 321, 329, 341]]
# petroleo=Petroleo(API=44.4, D86=d86)
# t=unidades.Temperature(325, "F")
# print petroleo.Cp_liquido(t).BtulbF
# d86=[unidades.Temperature(t, "F") for t in [304, 313, 321, 329, 341]]
# petroleo=Petroleo(API=44.4, D86=d86)
# t=unidades.Temperature(885, "F")
# p=unidades.Pressure(205, "psi")
# print petroleo.Cp_gas(t, p.atm).BtulbF
# R=unidades.V2V(675, "ft3bbl")
# gas=Natural_Gas(SG=0.95, CO2=0.2, H2S=0.1)
# petroleo=Petroleo(API=31., Rgo=R, gas=gas)
# t=unidades.Temperature(180, "F")
# print petroleo.pb_Standing(t).psi
# print petroleo.pb_Lasater(t).psi
# print petroleo.pb_Vazquez_Beggs(t, unidades.Temperature(85, "F"), unidades.Pressure(100, "psi").atm).psi
# print petroleo.pb_Glaso(t).psi
# print petroleo.pb_Total(t).psi
# print petroleo.pb_Al_Marhoun(t).psi
# print petroleo.pb_Dokla_Osman(t).psi
# print petroleo.pb_Petrosky_Farshad(t).psi
# print petroleo.pb_Kartoatmodjo_Schmidt(t, unidades.Temperature(85, "F"), unidades.Pressure(100, "psi").atm).psi
# R=unidades.V2V(675, "ft3bbl")
# t=unidades.Temperature(180, "F")
# p=unidades.Pressure(4000, "psi")
# petroleo=Petroleo(API=31.)
# print petroleo.Mu_Beal(t).cP
# print petroleo.Mu_Beggs_Robinson(t).cP
# print petroleo.Mu_Glaso(t).cP
# print petroleo.Mu_Egbogad(t).cP
# print petroleo.Mu_Kartoatmodjo_Schmidt(t).cP
# print petroleo.Mu_Chew_Connally(t, R).cP
# print petroleo.Mu_Beggs_Robinson_vivo(t, R).cP
# print petroleo.Mu_Kartoatmodjo_Schmidt_vivo(t, R).cP
# petroleo=Petroleo(API=33., M=250)
# print petroleo.Viscosidad_gas(unidades.Temperature(100, "F")).cP
# agua=Water()
# t=unidades.Temperature(200, "F")
# p=unidades.Pressure(5000, "psi")
# print agua.Solubilidad_Culberson_McKetta(t, p.atm, 2).ft3bbl
# print agua.Solubilidad_McCoy(t, p.atm, 2).ft3bbl
# agua=Water()
# t=unidades.Temperature(200, "F")
# p=unidades.Pressure(5000, "psi")
# print agua.Factor_Volumetrico_McCain(t, p.atm, 2)
# print agua.Factor_Volumetrico_McCoy(t, p.atm, 2)
# R=unidades.V2V(17.8, "ft3bbl")
# print agua.Compresibilidad_Dodson_Standing(t, p.atm, 2, R)
# print agua.Compresibilidad_Osif(t, p.atm, 2)
# print agua.Mu_Van_Wingen(t).cP
# print agua.Mu_Mattews_Russel(t, p.atm, 2).cP
# print agua.Mu_McCain(t, p.atm, 2).cP
# print agua.Mu_McCoy(t, 2).cP
# print agua.Tension_Jennings_Newman(t, p.atm).dyncm
# print agua.Rho(t, p.atm, 2).lbft3
# print agua.Rho_McCain(t, p.atm, 2).lbft3
# t=unidades.Temperature(200, "F")
# print SUS(t, 53.)
# t=unidades.Temperature(0, "F")
# print SUS(t, 90.)
# print SUF(122, 300)
# print SUF(210, 100)
# petroleo=Petroleo(v100=73.3, v210=8.86)
# print petroleo.VI
# petroleo=Petroleo(v100=5000, v210=100)
# print petroleo.VI
# petroleo=Petroleo(v100=22.83, v210=5.05)
# print petroleo.VI
# petroleo=Petroleo(v100=1500, v210=100)
# print petroleo.VI
# SG=0.867566
# SGo=0.7
# SG_=(SG-SGo)/SGo
# B=3.
# A=SG_**3/0.619**3
# x=arange(0.05, 0.96, 0.05)
# print x
# SGi=[SGo+SGo*(A/B*log10(1/(1-xi)))**(1./B) for xi in x]
# Mi=[prop_Riazi_Alsahhaf(1, g, reverse=True) for g in SGi]
# print SGi
# print Mi
# petroleo=Petroleo(M=250, API=43.3)
# t=unidades.Temperature(100, "F")
# print petroleo.Mu_Gas(t).cP
# print petroleo.Tension_API(t).dyncm
# print petroleo.Tension_Baker_Swerdloff(t).dyncm
# print petroleo.API
# petroleo=Petroleo(API=22.5, M=339.7)
# print(petroleo.API, petroleo.M)
v_i = [0.10, 0.30, 0.50, 0.70, 0.90]
D1160 = [i+273.15 for i in [150, 205, 250, 290, 350]]
petroleo = Petroleo(P_dist=10, curveType="D1160", X_curve=v_i, T_curve=D1160)