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


'''Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2017, 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/>.'''


###############################################################################
# Pseudocomponent definition from crude database
###############################################################################


import warnings

from PyQt5.QtWidgets import QApplication
from scipy import pi, exp, log10, log, sin
from scipy.optimize import fsolve

from lib.physics import R_atml

from lib import unidades
from lib.compuestos import Componente
from lib.petro import Petroleo
from lib.sql import databank
from lib.utilities import refDoc


__doi__ = {
    1:
        {"autor": "",
         "title": "",
         "ref": "",
         "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"},
    30:
        {"autor": "Papay, J.A.,",
         "title": "Termelestechnologiai Parameterek Valtozasa a Gazlelepk"
                  "Muvelese",
         "ref": "Soran. OGIL MUSZ, Tud, Kuzl. [Budapest], 1985. pp. 267–273.",
         "doi": ""},
    31:
        {"autor": "Hall, K.R., Yarborough, L.",
         "title": "A New Equation of State for Z-factor Calculations",
         "ref": "Oil and Gas Journal (June 18, 1973): 82–92.",
         "doi": ""},
    32:
        {"autor": "Dranchuk, P.M., Abu-Kassem, J.H.",
         "title": "Calculate of Z factors for Natural Gases Using Equations "
                  "of State",
         "ref": "Journal of Canadian Petroleum Technology (July–September "
                "1975): 34-36",
         "doi": "10.2118/75-03-03"},
    33:
        {"autor": "Dranchuk, P.M., Purvis, R.A., Robinson, D.B.",
         "title": "Computer Calculations of Natural Gas Compressibility "
                  "Factors Using the Standing and Katz Correlation",
         "ref": "Technical Series, no. IP 74–008. Institute of Petroleum, "
                "Alberta, Canada, 1974.",
         "doi": "10.2118/73-112"},
    34:
        {"autor": "Brill, J.P., Beggs, H.D.",
         "title": "Two-Phase Flow in Pipes",
         "ref": "University of Tulsa, INTERCOMP Course, The Hague, 1974",
         "doi": ""},
    35:
        {"autor": "Kumar, N.",
         "title": "Compressibility factors for natural and sour reservoir "
                  "gases by correlations and cubic equations of state",
         "ref": "Thesis of master of science in Petroleum Engineering, 2004, "
                "Texas Tech University.",
         "doi": ""},
    36:
        {"autor": "Gopal, V.N.",
         "title": "Gas Z-Factor Equations Developed for Computer",
         "ref": "Oil and Gas J. (Aug. 8, 1977) 58-60",
         "doi": ""},
    37:
        {"autor": "Sarem, A.M.",
         "title": "Z-Factor Equation Developed for Use in Digital Computers.",
         "ref": "Oil and Gas J. (Sept. 18, 1961) 118",
         "doi": ""},
    38:
        {"autor": "Dranchuk, P.M., Quon, D.",
         "title": "A General Solution of the Equations Describing Steady State"
                  "Turbulent Compressible Flow in Circular Conduits",
         "ref": "Journal of Canadian Petroleum Technology 3(2):60-65, 1964",
         "doi": "10.2118/64-02-04"},
    39:
        {"autor": "Burnett, R.R.",
         "title": "Calculator gives compressibility factors",
         "ref": "Oil & Gas Journal, June 11, 1979, pp. 70-74.",
         "doi": ""},
    40:
        {"autor": "Takacs., G.",
         "title": "Comparing Methods for Calculating Z-factor",
         "ref": "Oil & Gas Journal, May 15, 1989, pp. 43-46.",
         "doi": ""},
    41:
        {"autor": "Sanjari E, Lay E.N.",
         "title": "An accurate empirical correlation for predicting natural "
                  "gas compressibility factors.",
         "ref": "Journal of Natural Gas Chemistry 21(2012):184-188.",
         "doi": "10.1016/s1003-9953(11)60352-6"},
    42:
        {"autor": "Heidaryan E, Moghadasi J, Rahimi M.",
         "title": "New correlations to predict natural gas viscosity and "
                  "compressibility factor.",
         "ref": "Journal of Petroleum Science and Engineering 73 (2010):67-72",
         "doi": "10.1016/j.petrol.2010.05.008"},
    43:
        {"autor": "Heidaryan, E., Salarabadi, A., Moghadasi, J.",
         "title": "A novel correlation approach for prediction of natural gas "
                  "compressibility factor.",
         "ref": "J. Nat. Gas Chem. 19 (2) 2010, 189–192.",
         "doi": "10.1016/s1003-9953(09)60050-5"},
    44:
        {"autor": "Azizi N, Behbahani R, Isazadeh M A.",
         "title": "An efficient correlation for calculating compressibility "
                  "factor of natural gases",
         "ref": "Journal of Natural Gas Chemistry 19 (2010) 642-645",
         "doi": "10.1016/s1003-9953(09)60081-5"},
    45:
        {"autor": "Hall, K.R., Iglesias-Silva, G.A.",
         "title": "Improved equations for the StandingeKatz tables",
         "ref": "Hydrocarb. Process 86 (4), 2007. 107-110",
         "doi": ""},
    46:
        {"autor": "Shokir, Eissa M.El-M., El-Awad, Musaed N., Al-Quraishi, "
                  "Adulhrahman A., Al-Mahdy, Osama A.",
         "title": "Compressibility factor model of sweet, sour, and condensate"
                  " gases using genetic programming",
         "ref": "Chem. Eng. Res. Des. 90 (2012), 785-792.",
         "doi": "10.1016/j.cherd.2011.10.006"},
    47:
        {"autor": "Bahadori, A., Mokhatab, S., Towler, B.F.",
         "title": "Rapidly estimating natural gas compressibility factor",
         "ref": "J. Nat. Gas Chem. 16 (4) 2007, 349-353.",
         "doi": "10.1016/s1003-9953(08)60003-1"},
    48:
        {"autor": "Londono, F.E., Archer, R.A., Blasingame, T.A.",
         "title": "Correlations for hydrocarbon-gas viscosity and gas "
                  "density-validation and correlation of behavior using a "
                  "large-scale database",
         "ref": "SPE Reserv. Evalu. Eng. 8 (6) 2005, 561–572.",
         "doi": "10.2118/75721-PA"},
    49:
        {"autor": "Chankalani, A., Mae'soumi, A., Sameni, A.",
         "title": "An Intelligent Approach for Optimal Prediction of Gas "
                  "Deviation Factor Using Particle Swarm Optimization and "
                  "Genetic Algorithm",
         "ref": "Journal of Natural Gas Science and Engineering 14(2013) "
                "132-143",
         "doi": "10.1016/j.jngse.2013.06.002"},
    50:
        {"autor": "Elsharkawy, A.M.",
         "title": "Efficient methods for calculations of compressibility, "
                  "density and viscosity of natural gases",
         "ref": "Fluid Phase Equilibria 218:1 (2004) 1-13",
         "doi": "10.1016/j.fluid.2003.02.003"}
        }


# Gas compresibility factor
@refDoc(__doi__, [30, 9])
def Z_Papay(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Papay
    (1985)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Examples
    --------
    >>> "%0.4f" % Z_Papay(2, 3)
    '0.9422'
    """
    Z = 1 - 3.53*Pr/10**(0.9813*Tr) + 0.274*Pr**2/10**(0.8157*Tr)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [31, 9])
def Z_Hall_Yarborough(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Hall &
    Yarborough (1973)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    # Check input in range of validity
    if Tr <= 1:
        warnings.warn("Using extrapolated values")

    X1 = -0.06125*Pr/Tr*exp(-1.2*(1-1/Tr)**2)
    X2 = 14.76/Tr - 9.76/Tr**2 + 4.58/Tr**3
    X3 = 90.7/Tr - 242.2/Tr**2 + 42.4/Tr**3
    X4 = 2.18+2.82/Tr

    def f(Y):
        return X1+(Y+Y**2+Y**3-Y**4)/(1-Y)**3-X2*Y**2+X3*Y**X4

    Yo = 0.0125*Pr/Tr*exp(-1.2*(1-1/Tr)**2)
    Y = fsolve(f, Yo, full_output=True)
    if Y[2] == 1 and abs(Y[1]["fvec"][0]) < 1e-5:
        Z = 0.06125*Pr/Tr/Y[0][0]*exp(-1.2*(1-1/Tr)**2)
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


@refDoc(__doi__, [32])
def Z_Dranchuk_Abu_Kassem(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Dranchuk-
    Abu-Kassem (1975)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 30
    """
    # Check input in range of validity
    if Tr < 1 or Tr > 3 or Pr < 0.2 or Pr > 30:
        raise NotImplementedError("Incoming out of bound")

    C1 = 0.3265 - 1.07/Tr - 0.5339/Tr**3 + 0.01569/Tr**4 - 0.05165/Tr**5
    C2 = 0.5475 - 0.7361/Tr + 0.1844/Tr**2
    C3 = 0.1056*(-0.7361/Tr + 0.1844/Tr**2)

    # Eq 2
    def f(rho):
        C4 = 0.6134*(1+0.721*rho**2)*rho**2/Tr**3
        Z = 0.27*Pr/Tr/rho
        return 1 + C1*rho + C2*rho**2 - C3*rho**5 + C4*exp(-0.721*rho**2) - Z

    rho0 = 0.27*Pr/Tr
    rho = fsolve(f, rho0, full_output=True)
    if rho[2] == 1:
        Z = 0.27*Pr/Tr/rho[0]
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


@refDoc(__doi__, [33])
def Z_Dranchuk_Purvis_Robinson(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Dranchuk-
    Purvis-Robinson (1974)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.05 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 30
    """
    # Check input in range of validity
    if Tr < 1.05 or Tr > 3 or Pr < 0.2 or Pr > 30:
        raise NotImplementedError("Incoming out of bound")

    C1 = 0.31506237 - 1.0467099/Tr - 0.5783272/Tr**3
    C2 = 0.53530771 - 0.61232032/Tr
    C3 = 0.61232032*0.10488813/Tr
    A8 = 0.68446549

    # Eq 3
    def f(rho):
        C4 = 0.68157001*rho**2/Tr**3*(1+A8*rho**2)
        Z = 0.27*Pr/Tr/rho
        return 1 + C1*rho + C2*rho**2 + C3*rho**5 + C4*exp(-A8*rho**2) - Z

    rho0 = 0.27*Pr/Tr
    rho = fsolve(f, rho0, full_output=True)
    if rho[2] == 1:
        Z = 0.27*Pr/Tr/rho[0]
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


@refDoc(__doi__, [34, 35])
def Z_Brill_Beggs(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Brill-
    Beggs (1974)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.15 ≤ Tr ≤ 2.4
        * 0.2 ≤ Pr ≤ 15
    """
    # Check input in range of validity
    if Tr < 1.15 or Tr > 2.4 or Pr < 0.2 or Pr > 15:
        raise NotImplementedError("Incoming out of bound")

    A = 1.39*(Tr-0.92)**0.5 - 0.36*Tr - 0.101
    B = (0.62-0.23*Tr)*Pr + (0.066/(Tr-0.86)-0.037)*Pr**2 + \
        0.32/10**(9*(Tr-1))*Pr**6
    C = 0.132 - 0.32*log10(Tr)
    D = 10**(0.3016-0.49*Tr+0.1824*Tr**2)
    Z = A + (1-A)/exp(B) + C*Pr**D
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [36, 35])
def Z_Gopal(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Gopal
    (1974)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.05 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 15
    """
    if Pr <= 1.2 and Tr <= 3:
        if Tr <= 1.2:
            A, B, C, D = 1.6643, -2.2114, -0.3647, 1.4385
        elif 1.2 <= Tr < 1.4:
            A, B, C, D = 0.0522, -0.8511, -0.0364, 1.0490
        elif 1.4 <= Tr < 2.0:
            A, B, C, D = 0.1391, -0.2988, 0.0007, 0.9969
        elif 2.0 <= Tr <= 3.0:
            A, B, C, D = 0.0295, -0.0825, 0.0009, 0.9967
    elif 1.2 <= Pr < 2.8 and Tr <= 3:
        if Tr <= 1.2:
            A, B, C, D = -1.3570, 1.4942, 4.6315, -4.7009
        elif 1.2 <= Tr < 1.4:
            A, B, C, D = 0.1717, -0.3232, 0.5869, 0.1229
        elif 1.4 <= Tr < 2.0:
            A, B, C, D = 0.0984, -0.2053, 0.0621, 0.8580
        elif 2.0 <= Tr <= 3.0:
            A, B, C, D = 0.0211, -0.0527, 0.0127, 0.9549
    elif 2.8 <= Pr <= 5.4 and Tr <= 3:
        if Tr <= 1.2:
            A, B, C, D = -0.3278, 0.4752, 1.8223, -1.9036
        elif 1.2 <= Tr < 1.4:
            A, B, C, D = -0.2521, 0.3871, 1.6087, -1.6635
        elif 1.4 <= Tr < 2.0:
            A, B, C, D = -0.0284, 0.0625, 0.4714, -0.0011
        elif 2.0 <= Tr <= 3.0:
            A, B, C, D = 0.0041, 0.0039, 0.0607, 0.7927
    elif 5.4 <= Pr < 15:
        Z = Pr*(0.711 + 3.66*Tr)**-1.4667 - 1.637/(0.319*Tr+0.522) + 2.071
        return unidades.Dimensionless(Z)
    else:
        # Input not in range of validity
        raise NotImplementedError("Incoming out of bound")

    Z = Pr*(A*Tr+B) + C*Tr + D
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [35])
def Z_ShellOil(Tr, Pr):
    """Calculate gas compressibility factor using the Shell Oil Company
    correlation (2004)

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    A = -0.101 - 0.36*Tr + 1.3868*(Tr-0.919)**0.5
    B = 0.021 + 0.04275/(Tr-0.65)
    C = 0.6222 - 0.224*Tr
    D = 0.0657/(Tr-0.86) - 0.037
    E = 0.32*exp(-19.53*(Tr-1))
    F = 0.122*exp(-11.3*(Tr-1))
    G = Pr*(C + D*Pr + E*Pr**4)
    Z = A + B*Pr + (1-A)*exp(-G) - F*(Pr/10)**4
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [37])
def Z_Sarem(Tr, Pr):
    """Calculate gas compressibility factor using the Sarem (1969) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.05 ≤ Tr ≤ 2.95
        * 0.1 ≤ Pr ≤ 14.9
    """
    # Check input in range of validity
    if Tr < 1.05 or Tr > 2.95 or Pr < 0.1 or Pr > 14.9:
        raise NotImplementedError("Incoming out of bound")

    x = (2.*Pr-15)/14.8
    y = (2.*Tr-4)/1.9
    Aij = [
        [2.1433504, .0831762, -.0214670, -.0008714, .0042846, -.0016595],
        [.3312352, -.1340361, .0668810,  -.0271743,  .0088512,  -.002152],
        [.1057287,  -.0503937,  .0050925,  .0105513,  -.0073182,  .0026960],
        [.0521840,  .0443121,  -.0193294,  .0058973,  .0015367,  -.0028327],
        [.0197040,  -.0263834, .019262,  -.0115354,  .0042910,  -.0081303],
        [.0053096,  .0089178,  -.0108948,  .0095594,  -.0060114, .0031175]]

    P = [lambda a: 0.7071068,
         lambda a: 1.224745*a,
         lambda a: 0.7905695*(3*a**2-1),
         lambda a: 0.9354145*(5*a**3-3*a),
         lambda a: 0.265165*(35*a**4-30*a**2+3),
         lambda a: 0.293151*(63*a**5-70*a**3+15*a)]

    Z = 0
    for i in range(6):
        for j in range(6):
            Z += Aij[i][j]*P[i](x)*P[j](y)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [38])
def Z_Leung(Tr, Pr):
    """Calculate gas compressibility factor using the Leung (1964) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    The correlation is in cited reference, the parameters are least square
    fitting by Leung.

    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.1 ≤ Tr ≤ 2.6
        * 0.5 ≤ Pr ≤ 11
    """
    # Check input in range of validity
    if Tr < 1.1 or Tr > 2.6 or Pr < 0.5 or Pr > 11:
        raise NotImplementedError("Incoming out of bound")

    Bij = [
        [1.877, -4.936, 8.987, -5.215],
        [0.6562, 3.692, -6.477, 3.077],
        [0.1015, -0.5242, 0.8359, -0.3192],
        [-0.00422, 0.0205, -0.0288, 0.00742]]

    Z = 0
    for i in range(4):
        for j in range(4):
            Z += Bij[i][j] * Pr**(i-1) * Tr**(1-j)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [39, 40])
def Z_Burnett(Tr, Pr):
    """Calculate gas compressibility factor using the Burnett (1979)
    correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    The correlation is in cited reference, the parameters are least square
    fitting by Leung.

    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.3 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 4
    """
    # FIXME: Don't work
    # Check input in range of validity
    if Tr < 1.1 or Tr > 2.6 or Pr < 0.5 or Pr > 11:
        raise NotImplementedError("Incoming out of bound")

    Zo = 0.3379*log(log(Tr)) + 1.091
    Po = 21.46*Zo - 11.9*Zo**2 - 5.9
    N = (1.1 + 0.26*Tr + (1.04-1.42*Tr)*Pr/Po)*exp(Pr/Po)/Tr
    Z = 1 + (Zo-1) * sin(pi/2*Pr/Po)**N
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [41])
def Z_Sanjari_Lay(Tr, Pr):
    """Calculate gas compressibility factor using the Sanjari-Lay (2012)
    correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.01 ≤ Tr ≤ 3
        * 0.01 ≤ Pr ≤ 15
    """
    # Check input in range of validity
    if Tr < 1.01 or Tr > 3 or Pr < 0.01 or Pr > 15:
        raise NotImplementedError("Incoming out of bound")

    # Table 1
    if Pr < 3:
        A = [0, 0.007698, 0.003839, -0.467212, 1.018801, 3.805723, -0.087361,
             7.138305, 0.083440]
    else:
        A = [0, 0.015642, 0.000701, 2.341511, -0.657903, 8.902112, -1.136000,
             3.543614, 0.134041]

    # Eq 16
    Z = 1 + A[1]*Pr + A[2]*Pr**2 + A[3]*Pr**A[4]/Tr**A[5] + \
        A[6]*Pr**(A[4]+1)/Tr**A[7] + A[8]*Pr**(A[4]+2)/Tr**(A[7]+1)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [43])
def Z_Heidaryan_Salarabadi(Tr, Pr):
    """Calculate gas compressibility factor using the Heidaryan-Salarabadi-
    Moghadasi (2010) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.2 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 15
    """
    # Check input in range of validity
    if Tr < 1.2 or Tr > 3 or Pr < 0.2 or Pr > 15:
        raise NotImplementedError("Incoming out of bound")

    # Table 1
    A = [0, 1.11532372699824, -.0790395208876, .01588138045027, .0088613449601,
         -2.16190792611599, 1.1575311867207, -0.05367780720737,
         0.01465569989618, -1.80997374923296, 0.95486038773032]

    # Eq 5
    num = A[1] + A[2]*log(Pr) + A[3]*log(Pr)**2 + A[4]*log(Pr)**3 + \
        A[5]/Tr + A[6]/Tr**2
    dem = 1 + A[7]*log(Pr) + A[8]*log(Pr)**2 + A[9]/Tr + A[10]/Tr**2
    Z = log(num/dem)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [42])
def Z_Heidaryan_Moghadasi(Tr, Pr):
    """Calculate gas compressibility factor using the Heidaryan-Moghadasi-
    Rahimi (2010) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.2 ≤ Tr ≤ 3
        * 0.2 ≤ Pr ≤ 15
    """
    # Check input in range of validity
    if Tr < 1.2 or Tr > 3 or Pr < 0.2 or Pr > 15:
        raise NotImplementedError("Incoming out of bound")

    # Table 1
    if Pr < 3:
        A = [0, 2.827793, -4.688191e-1, -1.262288, -1.536524, -4.535045,
             6.895104e-2, 1.903869e-1, 6.200089e-1, 1.838479, 4.052367e-1,
             1.073574]
    else:
        A = [0, 3.252838, -1.306424e-1, -6.449194e-1, -1.518028, -5.391019,
             -1.379588e-2, 6.600633e-2, 6.120783e-1, 2.317431, 1.632223e-1,
             5.660595e-1]

    # Eq 8
    num = A[1] + A[3]*log(Pr) + A[5]/Tr + A[7]*log(Pr)**2 + A[9]/Tr**2 + \
        A[11]/Tr*log(Pr)
    dem = 1 + A[2]*log(Pr) + A[4]/Tr + A[6]*log(Pr)**2 + A[8]/Tr**2 + \
        A[10]/Tr*log(Pr)
    Z = log(num/dem)
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [44])
def Z_Azizi(Tr, Pr):
    """Calculate gas compressibility factor using the Azizi-Behbahani-Isazadeh
    (2010) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.1 ≤ Tr ≤ 2
        * 0.2 ≤ Pr ≤ 11
    """
    # Check input in range of validity
    if Tr < 1.1 or Tr > 2 or Pr < 0.2 or Pr > 11:
        raise NotImplementedError("Incoming out of bound")

    # Table 1
    a = 0.0373142485385592
    b = -0.0140807151485369
    c = 0.0163263245387186
    d = -0.0307776478819813
    e = 13843575480.943800
    f = -16799138540.763700
    g = 1624178942.6497600
    h = 13702270281.086900
    i = -41645509.896474600
    j = 237249967625.01300
    k = -24449114791.1531
    l = 19357955749.3274
    m = -126354717916.607
    n = 623705678.385784
    o = 17997651104.3330
    p = 151211393445.064
    q = 139474437997.172
    r = -24233012984.0950
    s = 18938047327.5205
    t = -141401620722.689

    A = a*Tr**2.16 + b*Pr**1.028 + c*Pr**1.58/Tr**2.1 + d*log(Tr)**0.5   # Eq 2
    B = e + f*Tr**2.4 + g*Pr**1.56 + h*Pr**0.124*Tr**3.033               # Eq 3
    C = i/log(Tr)**1.28 + j*log(Tr)**1.37 + k*log(Pr) + l*log(Pr)**2 + \
        m*log(Pr)*log(Tr)                                                # Eq 4
    D = 1 + n*Tr**5.55 + o*Pr**0.68*Tr**0.33                             # Eq 5
    E = p*log(Tr)**1.18 + q*log(Tr)**2.1 + r*log(Pr) + s*log(Pr)**2 + \
        t*log(Pr)*log(Tr)                                                # Eq 6
    Z = A + (B + C) / (D + E)                                            # Eq 1
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [46])
def Z_Shokir(Tr, Pr):
    """Calculate gas compressibility factor using the Shokir-Awad-Quraishi
    (2012) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    # Eq 8
    A = 2.679562*(2*Tr-Pr-1)/((Pr**2+Tr**3)/Pr)
    B = -7.686825*((Pr*Tr+Pr**2)/(Tr*Pr+2*Tr**2+Tr**3))
    C = -0.000624*(Tr**2*Pr-Tr*Pr**2+Tr*Pr**3+2*Tr*Pr-2*Pr**2+2*Pr**3)
    D = 3.067747*(Tr-Pr)/(Pr**2+Tr+Pr)
    E = 0.068059/Tr/Pr + 0.139489*Tr**2 + 0.081873*Pr**2 - 0.041098*Tr/Pr + \
        8.152325*Pr/Tr - 1.63028*Pr + 0.24287*Tr - 2.64988
    Z = A + B + C + D + E
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [47])
def Z_Bahadori(Tr, Pr):
    """Calculate gas compressibility factor using the Bahadori-Mokhatab-Towler
    (2007) correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]

    Examples
    --------
    Case study in paper
    >>> "%0.4f" % Z_Bahadori(297/197.98, 13860/4287.73)
    '0.7689'

    Notes
    -----
    Raise :class:`NotImplementedError` if input pair isn't in limit:

        * 1.05 ≤ Tr ≤ 2.4
        * 0.2 ≤ Pr ≤ 16
    """
    # Check input in range of validity
    if Tr < 1.05 or Tr > 2.4 or Pr < 0.2 or Pr > 16:
        raise NotImplementedError("Incoming out of bound")

    a = 0.969469 - 1.349238*Tr + 1.443959*Tr**2 - 0.36860*Tr**3         # Eq 8
    b = -0.107783 - 0.127013*Tr + 0.100828*Tr**2 - 0.012319*Tr**3       # Eq 9
    c = 0.0184810 + 0.0523405*Tr - 0.050688*Tr**2 + 0.010870*Tr**3      # Eq 10
    d = -0.000584 - 0.002146*Tr + 0.0020961*Tr**2 - 0.000459*Tr**3      # Eq 11
    Z = a + b*Pr + c*Pr**2 + d*Pr**3                                    # Eq 7
    return unidades.Dimensionless(Z)


@refDoc(__doi__, [48])
def Z_Londono_DAK(Tr, Pr, pure=False):
    """Calculate gas compressibility factor using the Londono-Archer-Blasingame
    (2007) correlation
    This method implement the Dranckuk-Abu-Kassem optimized version from paper

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]
    pure : boolean
        Aditional parameter to use the parameters of combined dabase

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    if pure:
        # Eq 34b
        C1 = 0.2965749 - 1.032952/Tr - 0.05394955/Tr**3 - 0.7694/Tr**4 + \
            0.2183666/Tr**5
        C2 = 0.6226256 - 1.006653/Tr + 0.3116857/Tr**2
        C3 = 0.09506539*(-1.006653/Tr + 0.3116857/Tr**2)
        A10 = 0.7544825
        A11 = 0.788

    else:
        # Eq 34a
        C1 = 0.3024696 - 1.046964/Tr - 0.1078916/Tr**3 - 0.7694186/Tr**4 + \
            0.1965439/Tr**5
        C2 = 0.6527819 - 1.118884/Tr + 0.3951957/Tr**2
        C3 = 0.09313593*(-1.118884/Tr + 0.3951957/Tr**2)
        A10 = 0.8483081
        A11 = 0.7880011

    # Eq 2
    def f(rho):
        C4 = A10*(1+A11*rho**2)*rho**2/Tr**3
        Z = 0.27*Pr/Tr/rho
        return 1 + C1*rho + C2*rho**2 - C3*rho**5 + C4*exp(-A11*rho**2) - Z

    rho0 = 0.27*Pr/Tr
    rho = fsolve(f, rho0, full_output=True)
    if rho[2] == 1:
        Z = 0.27*Pr/Tr/rho[0]
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


@refDoc(__doi__, [48])
def Z_Londono_NS(Tr, Pr, pure=False):
    """Calculate gas compressibility factor using the Londono-Archer-Blasingame
    (2007) correlation
    This method implement the Nishiumi-Saito optimized version from paper

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]
    pure : boolean
        Aditional parameter to use the parameters of combined dabase

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    if pure:
        # Eq 37b
        A1 = 4.645095e-1
        A2 = 1.627089
        A3 = -9.830729e-1
        A4 = 5.954591e-1
        A5 = 6.183499e-1
        A6 = 4.109793e-1
        A7 = 8.148481e-2
        A8 = 3.541591e-1
        A9 = -1.941089e-2
        A10 = -4.314707e-3
        A11 = 2.789035e-1
        A12 = 7.277907e-1
        A13 = -3.207280e-1
        A14 = 1.756311e-1
        A15 = 7.905733e-1

    else:
        # Eq 37a
        A1 = 2.669857e-1
        A2 = 1.048341
        A3 = -1.516869
        A4 = 4.435926
        A5 = -2.407212
        A6 = 6.089671e-1
        A7 = 5.174665e-1
        A8 = 1.296739
        A9 = -2.892824e-2
        A10 = -1.684037e-2
        A11 = 2.120655
        A12 = -5.046405e-1
        A13 = 1.802678e-1
        A14 = 8.563869e-2
        A15 = 4.956134e-1

    C1 = A1 - A2/Tr - A3/Tr**3 - A4/Tr**4 - A5/Tr**5
    C2 = A6 - A7/Tr - A8/Tr**2 - A9/Tr**5 - A10/Tr**24
    C3 = A11*(A7/Tr + A8/Tr**2 + A9/Tr**5 + A10/Tr**24)

    def f(rho):
        C4 = (A12/Tr**3+A13/Tr**9+A14/Tr**18) * rho**2 * (1+A15*rho**2)
        Z = 0.27*Pr/Tr/rho
        return 1 + C1*rho + C2*rho**2 - C3*rho**5 + C4*exp(-A15*rho**2) - Z

    rho0 = 0.27*Pr/Tr
    rho = fsolve(f, rho0, full_output=True)
    if rho[2] == 1:
        Z = 0.27*Pr/Tr/rho[0]
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


@refDoc(__doi__, [45, 49])
def Z_Hall_Iglesias(Tr, Pr):
    """Calculate gas compressibility factor using the correlation of Hall-
    Iglesias (2007). This is a extension of Hall-Yarborough correlation to
    reduced values of temperature.

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    X1 = 14.54/Tr-8.23/Tr**2+3.39*Tr**3.5
    X2 = 90.7/Tr-242.2/Tr**2+42.4/Tr**3
    X3 = 1.18+2.82/Tr
    k1 = 1/(1.87+0.001*Tr**63)
    k2 = 171.8*Tr**13
    k3 = -3525*(1-exp(-219/Tr**63))

    def f(Z):
        Y = (0.06125*Pr*exp(-1.2*(1-1/Tr)**2))/Tr/Z
        return Z - (1+Y+Y**2-Y**3)/(1-Y)**3 - X1*Y + X2*Y**X3 + \
            k1*Y*exp(-k2*(Y-0.421)**2) + k3*Y**10*exp(-69279*(Y-0.374)**4)

    Z = fsolve(f, 0.5, full_output=True)
    if Z[2] != 1:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z[0])


@refDoc(__doi__, [50])
def Z_Elsharkawy(Tr, Pr):
    """Calculate gas compressibility factor using the Elsharkawy (2003)
    correlation

    Parameters
    ------------
    Tr : float
        Reduced temperature [-]
    Pr : float
        Reduced pressure [-]

    Returns
    -------
    Z : float
        Gas compressibility factor [-]
    """
    C1 = 0.3265 - 1.07/Tr - 0.5339/Tr**3 + 0.01569/Tr**4 - 0.05165/Tr**5
    C2 = 0.5475 - 0.7361/Tr + 0.1844/Tr**2
    C3 = 0.1056*(0.7361/Tr + 0.1844/Tr**2)

    # Eq 24
    def f(rho):
        C4 = 0.6134*(1+0.721*rho**2)*rho**2/Tr**3*3
        Z = 0.27*Pr/Tr/rho
        return 1 + C1*rho + C2*rho**2 - C3*rho**5 + C4*exp(-0.721*rho**2) - Z

    rho0 = 0.27*Pr/Tr
    rho = fsolve(f, rho0, full_output=True)
    if rho[2] == 1:
        Z = 0.27*Pr/Tr/rho[0]
    else:
        raise ValueError("Iteration not converge")

    return unidades.Dimensionless(Z)


Z_list = (Z_Hall_Yarborough, Z_Papay, Z_Dranchuk_Abu_Kassem,
          Z_Dranchuk_Purvis_Robinson, Z_ShellOil, Z_Brill_Beggs, Z_Sarem,
          Z_Gopal, Z_Leung, Z_Burnett, Z_Sanjari_Lay, Z_Heidaryan_Salarabadi,
          Z_Heidaryan_Moghadasi, Z_Azizi, Z_Shokir, Z_Bahadori, Z_Londono_DAK,
          Z_Londono_NS, Z_Elsharkawy, Z_Hall_Iglesias)


class Crudo(Petroleo):
    """Class to model a hypotetical component from a defined crude oil
    Clase que define una fracción de petroleo a partir de la base de datos

    Parameters
    ------------
    index : index
        index of crude in crude databank
    Cplus : index
        Number of fraction to split the crude oil for heavier component than C6

    Notes
    -----
    The resultant instancecan be used as hypotetical component as Petroleo.
    """
    kwargs = Petroleo.kwargs.copy()
    kwarg = {"index": 0,
             "Cplus": 0,

             "Rgo": 0.0,
             "gas": None,
             "water": None}
    kwargs.update(kwarg)

    status = 0
    _bool = False
    msg = ""
    hasCurve = False
    hasSG = True
    hasRefraction = False

    def isCalculable(self):
        if self.kwargs["index"]:
            self.status = 1
            self.msg = ""
            return True
        else:
            self.status = 0
            self.msg = QApplication.translate("pychemqt", "Undefined petrol")

    def calculo(self):
        id = self.kwargs["index"]
        databank.execute("SELECT * FROM CrudeOil WHERE id=='%i'" % id)
        prop = databank.fetchone()

        API = prop[4]
        SG = 141.5/(API+131.5)
        PP = unidades.Temperature(prop[8], "F")
        v100 = prop[10]
        Tb = unidades.Temperature(
            (-753.-136*(1.-exp(-.15*v100))+572*SG-0.0512*v100+PP.R)/0.139, "R")

        self.definicion = 1
        self.kwargs["name"] = ", ".join(prop[1:3])
        self.kwargs["SG"] = SG
        self.kwargs["Tb"] = Tb
        self.kwargs["S"] = prop[5]
        self.kwargs["N"] = prop[6]
        self.kwargs["v100"] = prop[10]
        # Petroleo.calculo(self)

        self.vanadium = prop[11]
        self.nickel = prop[12]
        self.carbonResid = prop[13]
        self.asphaltene = prop[14]
        self.S2 = prop[6]
        self.H2S = prop[18]
        self.nNeutralization = prop[19]
        self.ash = prop[21]
        self.salt = prop[22]
        self.water = prop[20]
        self.NPentane = prop[15]
        if prop[16]:
            self.reidVP = unidades.Pressure(prop[16], "psi")
        else:
            self.reidVP = None
        if prop[17]:
            self.FlashP = unidades.Temperature(prop[17], "F")
        self.PourP = PP

        self.C1 = prop[23]/100.
        self.C2 = prop[24]/100.
        self.C3 = prop[25]/100.
        self.iC4 = prop[26]/100.
        self.nC4 = prop[27]/100.
        self.iC5 = prop[28]/100.
        self.nC5 = prop[29]/100.

        # SGo = 0.7
        # SG_ = (SG-SGo)/SGo
        # B = 3.
        # A = SG_**3/0.619**3
        # Cplus = int(self.kwargs["Cplus"])
        # Tbi=[unidades.Temperature(1090-exp(6.9955-0.11193*Nc**(2./3))) for Nc in range(6, Cplus)]
        # SGi=[1.07-exp(3.65097-3.8864*Nc**0.1) for Nc in range(6, Cplus)]
        # x=[1-1/exp(A/B*(SG-SGo)**B/SGo**B) for SG in SGi]
        # Mi=[prop_Riazi_Alsahhaf(1, g, reverse=True) for g in SGi]
        # APIi=[141.5/SG-131.5 for SG in SGi]
        # Kwi=[Tbi[i].R**(1./3)/SGi[i] for i in range(len(Mi))]
        # di=[unidades.Density(prop_Riazi_Alsahhaf(2, M), "gcc") for M in Mi]
        # Ii=[prop_Riazi_Alsahhaf(3, M) for M in Mi]
        # Tci=[unidades.Temperature(Tbi[i]/prop_Riazi_Alsahhaf(4, M)) for i, M in enumerate(Mi)]
        # Pci=[unidades.Pressure(prop_Riazi_Alsahhaf(5, M), "bar") for M in Mi]
        # Vci=[unidades.SpecificVolume(1/prop_Riazi_Alsahhaf(6, M), "ccg") for M in Mi]
        # Wi=[prop_Riazi_Alsahhaf(7, M) for M in Mi]
        # Tensioni=[unidades.Tension(prop_Riazi_Alsahhaf(8, M), "dyncm") for M in Mi]
        # ParSoli=[unidades.SolubilityParameter(prop_Riazi_Alsahhaf(9, M), "calcc") for M in Mi]


    def pb_Standing(self, T):
        """Standing, M.B.: Volumetric and Phase Behavior of Oil Field Hydrocarbon Systems, SPE, Dallas (1977)"""
        t=unidades.Temperature(T)
        F=(self.Rgo.ft3bbl/self.gas.SG)**0.83*10**(0.00091*t.F-0.0125*self.API)
        return unidades.Pressure(18.2*(F-1.4), "psi")

    def pb_Lasater(self, T):
        """Lasater, J.A: "Bubble Point Pressure Correlation," Trans., AIME (1958) 213, 379-381"""
        t=unidades.Temperature(T)
        if self.API<=40:
            M=630-10.*self.API
        else:
            M=73110.*self.API**-1.562
        yg=self.Rgo.ft3bbl/379.3/(self.Rgo.ft3bbl/379.3+350*self.SG/M)
        if yg<=0.6:
            pb=0.679*exp(2.786*yg)-0.323
        else:
            pb=8.26*yg**3.56+1.95
        return unidades.Pressure(pb*t.R/self.gas.SG, "psi")

    def pb_Vazquez_Beggs(self, T, ts=350, ps=10):
        """Vázquez, M.E. and Beggs, H.D.: "Correlations for Fluid Physical Property Prediction," J.Pet. Tech. (June 1980), 968-970"""
        t=unidades.Temperature(T)
        ts=unidades.Temperature(ts)
        ps=unidades.Pressure(ps, "atm")
        if self.API<=30:
            C1, C2, C3=0.0362, 1.0937, 25.724
        else:
            C1, C2, C3=0.0178, 1.187, 23.931

        gravity_corr=self.gas.SG*(1.+5.912e-5*self.API*ts.F*log10(ps.psi/114.7))
        return unidades.Pressure((self.Rgo.ft3bbl/C1/gravity_corr/exp(C3*self.API/T.R))**(1./C2), "psi")

    def pb_Glaso(self, T):
        """Glaso, O.: "Generalized Pressure-Volume-Temperature Correlations," J. Pet. Tech. (May 1980), 785-795"""
        t=unidades.Temperature(T)
        F=(self.Rgo.ft3bbl/self.gas.SG)**0.816*t.F**0.172/self.API**0.989
        return unidades.Pressure(10**(1.7669+1.7447*log10(F)-0.30218*log10(F)**2), "psi")

    def pb_Total(self, T):
        """TOTAL Compagnie Francaise Des Petroles: "Proyectos de Inyección de Fluidos - Correlaciones PVT para Crudos del Oriente de Venezuela," S.A. MENEVEN, Sept. 1983"""
        t=unidades.Temperature(T)
        if self.API<=10:
            C1, C2, C3, C4=12.847, 0.9636, 0.000993, 0.03417
        elif self.API<=35:
            C1, C2, C3, C4=25.2755, 0.7617, 0.000835, 0.011292
        else:
            C1, C2, C3, C4=216.4711, 0.6922, -0.000427, 0.02314
        return unidades.Pressure(C1*(self.Rgo.ft3bbl/self.gas.SG)**C2*10**(C3*t.F-C4*self.API), "psi")

    def pb_Al_Marhoun(self, T):
        """Al-Marhoun, M.A.: "PVT Correlation for Middle East Crude Oils," J. Pet. Tech (May 1988), 650-666"""
        t=unidades.Temperature(T)
        return unidades.Pressure(5.38088e-3*self.Rgo.ft3bbl**0.715082*self.gas.SG**-1.87784*self.SG**3.1437*t.R**1.32657, "psi")

    def pb_Dokla_Osman(self, T):
        """Dokla, M.E. and Osman, M.E.: "Correlation of PVT properties for UAE Crudes," Trans., AIME (1992) 293, 41-46"""
        t=unidades.Temperature(T)
        return unidades.Pressure(0.836386e4*self.Rgo.ft3bbl**0.724047*self.gas.SG**-1.01049*self.SG**0.107991*t.R**-0.952584, "psi")

    def pb_Petrosky_Farshad(self, T):
        """Petrosky, G.E., Jr. and Farshad, F.F.: "Pressure-Volume-Temperature Correlations for Gulf of Mexico Crude Oils," paper SPE 26644 presented at the 68th Annual Technical Conference and Exhibition, Houston, Texas, Oct. 3-6,1993."""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl**0.5774/self.gas.SG**0.8439*10**(4.561e-5*t.F**1.3911-7.916e-4*self.API**1.541)
        return unidades.Pressure(112.727*(F-12.34), "psi")

    def pb_Kartoatmodjo_Schmidt(self, T, ts=350, ps=10):
        """Kartoatmodjo, T. and Schmidt, Z.: "Large Data Bank Improve Crude Physical Property Correlations," Oil and Gas J. (July 4, 1994) 51-55"""
        t=unidades.Temperature(T)
        ts=unidades.Temperature(ts)
        ps=unidades.Pressure(ps, "atm")
        if self.API<=30:
            C1, C2, C3, C4=0.05958, 0.7972, 13.1405, 0.9986
        else:
            C1, C2, C3, C4=0.0315, 0.7587, 11.2895, 0.9143

        gravity_corr=self.gas.SG*(1.+0.1595*self.API**0.4078*ts.F**-0.2506*log10(ps.psi/114.7))
        return unidades.Pressure((self.Rgo.ft3bbl/C1/gravity_corr**C2/10**(C3*self.API/t.R))**C4, "psi")

    def pb(self, T):
        """Presión de burbujeo del crudo"""
        t=unidades.Temperature(T)
        metodo_pb=[self.pb_Standing, self.pb_Lasater, self.pb_Vazquez_Beggs, self.pb_Glaso, self.pb_Total, self.pb_Al_Marhoun, self.pb_Dokla_Osman, self.pb_Petrosky_Farshad, self.pb_Kartoatmodjo_Schmidt][Preferences.getint("petro", "pb")]
        pb=metodo_pb(t)
        CN2=1.+((-2.65e-4*self.API+5.5e-3)*t.F+(0.0931*self.API-0.895))*self.gas.N2
        CCO2=1.-693.8*self.gas.CO2*t.F**-1.553
        CH2S=1.-(0.9035+0.0015*self.API)*self.gas.H2S+0.019*(45-self.API)*self.gas.H2S**2
        return unidades.Pressure(CN2*CH2S*CCO2*pb)


    def B_Standing(self, T):
        """Standing, M.B.: Volumetric and Phase Behavior of Oil Field Hydrocarbon Systems, SPE, Dallas (1977)"""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl*(self.gas.SG/self.SG)**0.5+1.25*t.F
        return 0.9759+12e-5*F**1.2

    def B_Vazquez_Beggs(self, T, ts=350, ps=10):
        """Vázquez, M.E. and Beggs, H.D.: "Correlations for Fluid Physical Property Prediction," J.Pet. Tech. (June 1980), 968-970"""
        t=unidades.Temperature(T)
        ts=unidades.Temperature(ts)
        ps=unidades.Pressure(ps, "atm")
        if self.API<=30:
            C1, C2, C3=4.667e-4, 1.751e-5, -1.8106e-6
        else:
            C1, C2, C3=4.67e-4, 1.1e-5, 1.337e-9

        gravity_corr=self.gas.SG*(1.+5.912e-5*self.API*ts.F*log10(ps.psi/114.7))
        return 1.+C1*self.Rgo.ft3bbl+C2*(t.F-60)*self.API/gravity_corr+C3*self.Rgo.ft3bbl*(t.F-60)*self.API/gravity_corr

    def B_Glaso(self, T):
        """Glaso, O.: "Generalized Pressure-Volume-Temperature Correlations," J. Pet. Tech. (May 1980), 785-795"""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl(self.gas.SG/self.SG)**0.526*+0.968*t.F
        return 1.+10**(-6.58511+2.91329*log10(F)-0.27683*log10(F)**2)

    def B_Total(self, T):
        """TOTAL Compagnie Francaise Des Petroles: "Proyectos de Inyección de Fluidos - Correlaciones PVT para Crudos del Oriente de Venezuela," S.A. MENEVEN, Sept. 1983"""
        t=unidades.Temperature(T)
        return 1.022+4.857e-4*self.Rgo.ft3bbl-2.009e-6*(t.F-60)*self.API/self.gas.SG+17.569e-9*self.Rgo.ft3bbl*(t.F-60)*self.API/self.gas.SG

    def B_Al_Marhoun(self, T):
        """Al-Marhoun, M.A.: "PVT Correlation for Middle East Crude Oils," J. Pet. Tech (May 1988), 650-666"""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl**0.74239*self.gas.SG**0.323294*self.SG**-1.20204
        return 0.497069+0.862963e-3*t.R+0.182594e-2*F+0.318099e-5*F**2

    def B_Dokla_Osman(self, T):
        """Dokla, M.E. and Osman, M.E.: "Correlation of PVT properties for UAE Crudes," Trans., AIME (1992) 293, 41-46"""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl**0.773572*self.gas.SG**0.40402*self.SG**-0.882605
        return 0.431935e-1+0.156667e-2*t.R+0.139775e-2*F+0.380525e-5*F**2

    def B_Petrosky_Farshad(self, T):
        """Petrosky, G.E., Jr. and Farshad, F.F.: "Pressure-Volume-Temperature Correlations for Gulf of Mexico Crude Oils," paper SPE 26644 presented at the 68th Annual Technical Conference and Exhibition, Houston, Texas, Oct. 3-6,1993."""
        t=unidades.Temperature(T)
        F=self.Rgo.ft3bbl**0.3738*self.gas.SG**0.2914/self.SG**0.6265+0.24626*t.F**0.5371
        return 1.0113+7.2046e-5*F**3.0936

    def B_Kartoatmodjo_Schmidt(self, T, ts=350, ps=10):
        """Kartoatmodjo, T. and Schmidt, Z.: "Large Data Bank Improve Crude Physical Property Correlations," Oil and Gas J. (July 4, 1994) 51-55"""
        t=unidades.Temperature(T)
        ts=unidades.Temperature(ts)
        ps=unidades.Pressure(ps, "atm")

        gravity_corr=self.gas.SG*(1.+0.1595*self.API**0.4078*ts.F**-0.2506*log10(ps.psi/114.7))
        F=self.Rgo.ft3bbl**0.755*gravity_corr**0.25*self.SG**-1.5+0.45*t.F
        return 0.98496+1e-4*F**1.5

    def B(self, T, P):
        """Factor volumétrico, relación entre el volumen a las condiciones del yacimiento y las condiciones normales a la presión de burbujeo"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        metodo_B=[self.pb_Standing, self.pb_Vazquez_Beggs, self.pb_Glaso, self.pb_Total, self.pb_Al_Marhoun, self.pb_Dokla_Osman, self.pb_Petrosky_Farshad, self.pb_Kartoatmodjo_Schmidt][Preferences.getint("petro", "Vol_factor")]
        Bpb=metodo_B(t)
        pb=self.pb(T)
        if p>pb:
            c=self.compressibilidad(T)
            return Bpb*exp(c*(pb-p))
        else:
            return Bpb


    def Mu_Gas(self, T):
        """Método de cáluclo de la viscosidad de vapores, API procedure 11B3.1, pag 1105"""
        #FIXME: no sale
        t=unidades.Temperature(T)
        return unidades.Viscosity(-0.0092696+t.R**0.5*(0.0010310+4.4507e-5*self.M**0.5)+1.1249e-5*self.M, "cP")
#        return unidades.Viscosity(-0.0092696+T**0.5*(0.001383-5.9712e-5*self.M**0.5)+1.1249e-5*self.M, "cP")


    def Mu_Beal(self, T):
        """Beal, C.: "The Viscosity of Air, Water, Natural Gas, crude Oil and its Associated Gases at Oil-Field Temperatures and Pressures," Trans., AIME (1946) 165, 94-115"""
        t=unidades.Temperature(T)
        a=10**(0.43+8.33/self.API)
        mu=(0.32+1.8e7/self.API**4.53)*(360/(t.F+200))**a
        return unidades.Viscosity(mu, "cP")

    def Mu_Beggs_Robinson(self, T):
        """Beggs, H.D. and Robinson, J.R.: "Estimating the Viscosity of Crude Oil Systems," J. Pet. Tech. Forum (Sept. 1975), 1140-1141"""
        t=unidades.Temperature(T)
        z=3.0324-0.02023*self.API
        y=10**z
        x=y*t.F**-1.163
        return unidades.Viscosity(10**x-1, "cP")

    def Mu_Glaso(self, T):
        """Glaso, O.: "Generalized Pressure-Volume-Temperature Correlations," J. Pet. Tech. (May 1980), 785-795"""
        t=unidades.Temperature(T)
        mu=3.141e10*t.F**-3.444*log10(self.API)**(10.313*log10(t.F)-36.447)
        return unidades.Viscosity(mu, "cP")

    def Mu_Egbogah(self, T):
        """Egbogah, E.O.: "An Improved Temperature-Viscosity Correlation for Crude Oil Systems," paper 83-34-32 presented at the 1983 Annual Technical Meeting of the Petroleum Society of CIM, Banff, Alberta, May 10-13, 1983"""
        t=unidades.Temperature(T)
        mu=1.8653-0.025086*self.API-0.5644*log10(t.F)
        return unidades.Viscosity(10**(10**mu)-1, "cP")

    def Mu_Kartoatmodjo_Schmidt(self, T):
        """Kartoatmodjo, T. and Schmidt, Z.: "Large Data Bank Improve Crude Physical Property Correlations," Oil and Gas J. (July 4, 1994) 51-55"""
        t=unidades.Temperature(T)
        mu=16e8*t.F**-2.8177*log10(self.API)**(5.7526*log10(t.F)-26.9718)
        return unidades.Viscosity(mu, "cP")

    def Mu_Muerto(self, T):
        """Viscosidad de petroleos muertos (sin gas disuelto)"""
        metodos=[self.Mu_Beal, self.Mu_Beggs_Robinson, self.Mu_Glaso, self.Mu_Egbogah, self.Mu_Kartoatmodjo_Schmidt][Preferences.getint("petro", "mu_dead")]
        return metodos(T)

    def Mu_Chew_Connally(self, T, R):
        """Chew, J.N. and Connally, C.A. Jr.: "A Viscosity Correlation for Gas-Saturated Crude Oils," Trans, AIME (1959) 216, 23-25"""
        t=unidades.Temperature(T)
        r=unidades.V2V(R)
        muo=self.Mu_Muerto(T)
        A=10**(r.ft3bbl*(2.2e-7*r.ft3bbl-7.4e-4))
        b=0.68/10**(8.62e-5*r.ft3bbl)+0.25/10**(1.1e-3*r.ft3bbl)+0.062/10**(3.74e-3*r.ft3bbl)
        return unidades.Viscosity(A*muo.cP**b, "cP")

    def Mu_Beggs_Robinson_vivo(self, T, R):
        """Beggs, H.D. and Robinson, J.R.: "Estimating the Viscosity of Crude Oil Systems," J. Pet. Tech. Forum (Sept. 1975), 1140-1141"""
        t=unidades.Temperature(T)
        r=unidades.V2V(R)
        muo=self.Mu_Muerto(T)
        A=10.715*(r.ft3bbl+100)**-0.515
        b=5.44*(r.ft3bbl+150)**-0.338
        return unidades.Viscosity(A*muo.cP**b, "cP")

    def Mu_Kartoatmodjo_Schmidt_vivo(self, T, R):
        """Kartoatmodjo, T. and Schmidt, Z.: "Large Data Bank Improve Crude Physical Property Correlations," Oil and Gas J. (July 4, 1994) 51-55"""
        t=unidades.Temperature(T)
        r=unidades.V2V(R)
        muo=self.Mu_Muerto(T)
        b=10**(-0.00081*r.ft3bbl)
        A=(0.2001+0.8428*10**(-0.000845*r.ft3bbl))*muo.cP**(0.43+0.5165*b)
        return unidades.Viscosity(-0.06821+0.9824*A+40.34e-5*A**2, "cP")

    def Mu_Vivo(self, T, R):
        """Viscosidad de petroleos vivos (con gas disuelto)"""
        metodos=[self.Mu_Chew_Connally, self.Mu_Beggs_Robinson_vivo, self.Mu_Kartoatmodjo_Schmidt_vivo][Preferences.getint("petro", "mu_live")]
        return metodos(T, R)


    def Mu_Beal_presion(self, T, P, R):
        """Beal, C.: "The Viscosity of Air, Water, Natural Gas, crude Oil and its Associated Gases at Oil-Field Temperatures and Pressures," Trans., AIME (1946) 165, 94-115"""
        p=unidades.Pressure(P, "atm")
        pb=self.pb(T)
        muo=self.Mu_Vivo(T, R)
        mu=(0.024*muo.cP**1.6+0.038*muo.cP**0.56)*0.001*(p.psi-pb.psi)+muo.cP
        return unidades.Viscosity(mu, "cP")

    def Mu_Vazquez_Beggs(self, T, P, R):
        """Vázquez, M.E. and Beggs, H.D.: "Correlations for Fluid Physical Property Prediction," J.Pet. Tech. (June 1980), 968-970"""
        p=unidades.Pressure(P, "atm")
        pb=self.pb(T)
        muo=self.Mu_Vivo(T, R)
        m=2.6*p.psi**1.187*exp(-11.513-8.98e-5*p.psi)
        return unidades.Viscosity(muo.cP*(p.psi/pb.psi)**m, "cP")

    def Mu_Kartoatmodjo_Schmidt_presion(self, T, P, ):
        """Kartoatmodjo, T. and Schmidt, Z.: "Large Data Bank Improve Crude Physical Property Correlations," Oil and Gas J. (July 4, 1994) 51-55"""
        p=unidades.Pressure(P, "atm")
        pb=self.pb(T)
        muo=self.Mu_Vivo(T, R)
        mu=1.00081*muo.cP+1.127e-3*(p.psi-pb.psi)*(-65.17e-4*muo.cP**1.8148+0.038*muo.cP**1.59)
        return unidades.Viscosity(mu, "cP")

    def Mu_Presion(self, T, P):
        """Viscosidad de petroleos vivos (con gas disuelto)"""
        metodos=[self.Mu_Beal_presion, self.Mu_Vazquez_Beggs, self.Mu_Kartoatmodjo_Schmidt_presion][Preferences.getint("petro", "mu_live")]
        return metodos(T, P)


class Water(Componente):
    """Clase que define el agua específica que acompaña al petroleo, con las propiedades específicas"""
    def __init__(self):
        Componente.__init__(self, 62)

    def Solubilidad_Culberson_McKetta(self, T, P, S=0):
        """Culberson, O.L. and McKetta, J.J., Jr.: "Phase Equilibria in Hydrocarbon-Water Systems III - The solubility of Methane in Water at Pressures to 10,000 psia," Trans., AIME (1951) 192, 223-226
        S: salinidad en % en peso"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        A=8.15839-6.12265e-2*t.F+1.91663e-4*t.F**2-2.1654e-7*t.F**3
        B=1.01021e-2-7.44241e-5*t.F+3.05553e-7*t.F**2-2.94883e-10*t.F**3
        C=(-9.02505+0.130237*t.F-8.53425e-4*t.F**2+2.34122e-6*t.F**3-2.37049e-9*t.F**4)*1e-7
        R=A+B*p.psi+C*p.psi**2
        Rs=R*10**(-0.0840655*S*t.F**-0.285854)
        return unidades.V2V(Rs, "ft3bbl")

    def Solubilidad_McCoy(self, T, P, S=0):
        """McCoy, R.L.: Microcomputer Programs for Petroleum Engineers: Vol. 1, Reservoir Engineering and Formation Evaluation, Gulf Publishing Co., Houston (1983).
        S: salinidad en % en peso"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        A=2.12+3.45e-3*t.F-3.59e-5*t.F**2
        B=0.0107-5.26e-5*t.F+1.48e-7*t.F**2
        C=-8.75e-7+3.9e-9*t.F-1.02e-11*t.F**2
        R=A+B*p.psi+C*p.psi**2
        Rs=R*(1-(0.0753-1.73e-4*t.F)*S)
        return unidades.V2V(Rs, "ft3bbl")


    def Factor_Volumetrico_McCain(self, T, P, S=0):
        """McCain, W.D., Jr: The Properties of Petroleum Fluids, 2nd ed. Tulsa, OK: PennWell Books, 1990.
        S: salinidad en % en peso"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        DVp=-1.0001e-2+1.33391e-4*t.F+5.50654e-7*t.F**2
        DVt=-1.95301e-9*p.psi*t.F-1.72834e-13*p.psi**2*t.F-3.58922e-7*p.psi-2.25341e-10*p.psi**2
        B=(1+DVp)*(1+DVt)
        return B*(1+S*(5.1e-8*p.psi+(5.47e-6-1.95e-10*p.psi)*(t.F-60)-(3.23e-8-8.5e-13*p.psi)*(t.F-60)**2))

    def Factor_Volumetrico_McCoy(self, T, P, S=0, R=1):
        """McCoy, R.L.: Microcomputer Programs for Petroleum Engineers: Vol. 1, Reservoir Engineering and Formation Evaluation, Gulf Publishing Co., Houston (1983).
        R: razon de gas disuelto
        S: salinidad en % en peso"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        if R==0:
            A=0.9947+5.8e-6*t.F+1.02e-6*t.F**2
            B=-4.228e-6+1.8276e-8*t.F-6.77e-11*t.F**2
            C=1.3e-10-1.3855e-12*t.F+4.285e-15*t.F**2
        else:
            A=0.9911+6.35e-5*t.F+8.5e-7*t.F**2
            B=-1.093e-6-3.497e-9*t.F+4.57e-12*t.F**2
            C=-5e-11+6.429e-13*t.F-1.43e-15*t.F**2
        B=A+B*p.psi+C*p.psi**2
        return B*(1+S*(5.1e-8*p.psi+(5.47e-6-1.95e-10*p.psi)*(t.F-60)-(3.23e-8-8.5e-13*p.psi)*(t.F-60)**2))

    def Rho(self, T, P, S=0):
        B=self.Factor_Volumetrico_McCain(T, P, S)
        s=S*1e7/58443
        g=1.+0.695e-6*s
        return unidades.Density(62.4*g/B, "lbft3")

    def Rho_McCain(self, T, P, S=0):
        """McCain, W.D., Jr: The Properties of Petroleum Fluids, 2nd ed. Tulsa, OK: PennWell Books, 1990."""
        B=self.Factor_Volumetrico_McCain(T, P, S)
        g=62.368+0.438603*S+1.60074e-3*S**2
        return unidades.Density(g/B, "lbft3")

    def Compresibilidad_Dodson_Standing(self, T, P, S=0, R=0):
        """Dodson, C.R. and Standing, M.B.: "Pressure-Volume-Temperature and Solubility RElations for Natural Gas-Water-Mixtures," Drill. and Prod. Prac., API (1944) 173-179"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        R=unidades.V2V(R)
        a=3.8546-1.34e-4*p.psi
        b=-0.01052+4.77e-7*p.psi
        c=3.9267e-5-8.8e-10*p.psi
        cw=(a+b*t.F+c*t.F**2)/1e6
        cr=1.+8.9e-3*R.ft3bbl
        cs=1+S**0.7*(-5.2e-2+2.7e-4*t.F-1.14e-6*t.F**2+1.121e-9*t.F**3)
        return cw*cr*cs

    def Compresibilidad_Osif(self, T, P, S=0):
        """Osif, T.L.: "The Effects of Salt, Gas, Temperature and Pressure on the Compressibility of Water," SPE Res.Eng. (Feb. 1988) 3, No.1. 175-181"""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        S=S*1e4/58443
        return 1/(7.033*p.psi+541.5*S-537.*t.F+403300.)


    def Mu_Van_Wingen(self, T):
        """Van Wingen, N.: "Viscosity of Air, Water, Natural Gas, and Crude Oil at Varying Pressure and Temperatures," Secondary Recovery of Oil in the United States, API (1950) 127."""
        t=unidades.Temperature(T)
        return unidades.Viscosity(exp(1.003-1.479e-2*t.F+1.982e-5*t.F**2), "cP")

    def Mu_Mattews_Russel(self, T, P, S=0):
        """Mathews, C.S and Russel, D.G.: Pressure Buildup and Flow Text in Wells. Monograph Series. Society of Petroleum Engineers of AIME, Dallas (1967) 1, Appendix G."""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        A=-0.04518+0.009313*S-0.000383*S**2
        B=70.634+0.09576*S**2
        mu=A+B/t.F
        f=1.+3.5e-12*p.psi**2*(t.F-40.)
        return unidades.Viscosity(mu*f, "cP")

    def Mu_McCain(self, T, P, S=0):
        """McCain, W.D., Jr: The Properties of Petroleum Fluids, 2nd ed. Tulsa, OK: PennWell Books, 1990."""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        A=109.574-8.40564*S+0.313314*S**2+8.72213e-3*S**3
        B=-1.12166+2.63951e-2*S-6.79461e-4*S**2-5.47119e-5*S**3+1.55586e-6*S**4
        mu=A*t.F**B
        f=0.9994+4.0295e-5*p.psi+3.1062e-9*p.psi**2
        return unidades.Viscosity(mu*f, "cP")

    def Mu_McCoy(self, T, S=0):
        """McCoy, R.L.: Microcomputer Programs for Petroleum Engineers: Vol. 1, Reservoir Engineering and Formation Evaluation, Gulf Publishing Co., Houston (1983)."""
        t=unidades.Temperature(T)
        mu=0.02414*10**(247.8/(t-140))
        f=1.-1.87e-3*S**0.5+2.18e-4*S**2.5+(t.F**0.5-1.35e-2*t.F)*(2.76e-3*S-3.44e-4*S**1.5)
        return unidades.Viscosity(mu*f, "cP")

    def Tension_Jennings_Newman(self, T, P):
        """Jennings, H.Y., Jr. and Newman, G.I.L.:"The Effect of Temperature and Pressure on the Interfacial Tension of Water Against Mechane-Normal Decane Mixtures," Trans., AIME (1971) 251, 171-175."""
        t=unidades.Temperature(T)
        p=unidades.Pressure(P, "atm")
        A=79.1618-0.118978*t.F
        B=-5.28473e-3+9.87913e-6*t.F
        C=(2.33814-4.57194e-4*t.F-7.52678e-6*t.F**2)*1e-7
        return unidades.Tension(A+B*p.psi+C*p.psi**2, "dyncm")


class Natural_Gas(object):
    """Clase que define un gas natural como fracción desconocida de petroleo"""
    def __init__(self, SG=None, composicion=[], wet=False, CO2=0., H2S=0., N2=0.):
        """
        g: gravedad específica
        composicion: en la forma de array [[componentes],[fracciones molares]]
        wet: parámetro opcional que indica si se trata de un gas húmedo (con una pequeña fracción de fase líquida
        CO2: fracción molar de CO2 en el gas
        H2S: fracción molar de H2S en el gas
        """
        self.SG=SG
        self.wet=wet
        self.CO2=CO2
        self.H2S=H2S
        self.N2=N2
        if wet:
            self.tpc=unidades.Temperature(187.+330.*SG-72.5*SG**2, "R")
            self.ppc=unidades.Pressure(706-51.7*SG-11.1*SG**2, "psi")
        else:
            self.tpc=unidades.Temperature(168.+325.*SG-12.5*SG**2, "R")
            self.ppc=unidades.Pressure(677+15.*SG-37.5*SG**2, "psi")
        if N2!=0:
            self.tpc, self.ppc=self.Critical_Carr_Kobayashi_Burrows()
        if CO2+H2S!=0.:
            self.tpc, self.ppc=self.Critical_Wichert_Aziz()
        self.M=28.96*SG

    def Critical_Wichert_Aziz(self):
        """Wichert, E., and K. Aziz. “Calculation of Z’s for Sour Gases.” Hydrocarbon Processing 51, no. 5 (1972): 119–122."""
        """Wichert, E., Aziz, K., 1972. Calculation of Z’s for sour gases. Hydrocarb. Process. 51 (5), 119–122."""
        A=self.CO2+self.H2S
        e=120.*(A**0.9-A**1.6)+15*(self.H2S**0.5-self.H2S**4)
        tpc=self.tpc.R-e
        ppc=self.ppc.psi*tpc/(self.tpc.R+self.H2S*(1-self.H2S)*e)
        return unidades.Temperature(tpc, "R"), unidades.Pressure(ppc, "psi")

    def Critical_Carr_Kobayashi_Burrows(self):
        """Carr, N., Kobayashi, R., Burrows, D., 1954. Viscosity of hydrocarbon gases under pres-
        sure. Trans. AIME 201, 270–275."""
        tpc=self.tpc.R-80*self.CO2+130*self.H2S-250*self.N2
        ppc=self.ppc.psi+440*self.CO2+600*self.H2S-170*self.N2
        return unidades.Temperature(tpc, "R"), unidades.Pressure(ppc, "psi")

    def Critical_Whitson_Brule(self):
        """Whitson, C. H., and M. R. Brule. Phase Behavior. Richardson, TX: Society of Petroleum Engineers, 2000."""
        CO2=Componente(49)
        H2S=Componente(50)
        N2=Componente(46)
        g=(28.96*self.SG-(N2.M*self.N2+CO2.M*self.CO2+H2S.M*self.H2S))/28.96/(1-self.N2-self.CO2-self.H2S)
        tpcHC=168.+325.*g-12.5*g**2
        ppcHC=677+15.*g-37.5*g**2
        tpc=(1-self.N2-self.CO2-self.H2S)*tpcHC+N2.tc.R*self.N2+CO2.tc.R*self.CO2+H2S.tc.R*self.H2S
        ppc=(1-self.N2-self.CO2-self.H2S)*ppcHC+N2.pc.psi*self.N2+CO2.pc.psi*self.CO2+H2S.pc.psi*self.H2S
        return unidades.Temperature(tpc, "R"), unidades.Pressure(ppc, "psi")

    def tc_gas(self):
        """Cálculo de la temperatura crítica de un gas natural de composición conocida con metano como componente principal, API procedure 4C1.1 pag 329"""
        Tc1=exp(-5.624853)*exp(-0.0105852*self.MABP().R-1.4401126*self.SG+0.013200830*self.SG*self.MABP().R)
        Tc2=self.MABP().R**2.4289880
        Tc3=self.SG**-0.299808
        return unidades.Temperature(Tc1*Tc2*Tc3, "R")

    def Z_factor(self, T, P, Z_method=0):
        """Calculo del factor de compresibilidad del gas
        T: temperatura, en kelvin
        P: presión, en atm
        Z_method: método de cálculo del factor de compresibilidad:
            0   -   Hall_Yarborough
            1   -   Dranchuk_Abu_Kassem
            2   -   Dranchuk_Purvis_Robinson
            3   -   Shell-Oil Company
            4   -   Beggs_Brill
            5   -   Sarem
            6   -   Gopal
            7   -   Papay
        """
        Z=[Z_Hall_Yarborough, Z_Dranchuk_Abu_Kassem, Z_Dranchuk_Purvis_Robinson, Z_ShellOil, Z_Beggs_Brill, Z_Sarem, Z_Gopal, Z_Papay][Z_method]
        return Z(T/self.tpc, P/self.ppc.atm)

    def RhoG(self, T, P):
        Z=self.Z_factor(T, P)
        return unidades.Density(P*self.M/Z/R_atml/T, "gl")

    def Compressibility_Mattar_Brar_Aziz(self, T, P):
        """Mattar, L. G., S. Brar, and K. Aziz. “Compressibility of Natural Gases.” Journal of Canadian Petroleum Technology (October–November 1975): 77–80."""
        Tr=T/self.tpc
        Z=self.Z_factor(T, P)
        g=0.27*P/self.ppc.atm/Tr/Z
        T1=0.31506237-1.0467099/Tr-0.5783272/Tr**3
        T2=0.53530771-0.61232032/Tr
        T3=0.61232032*0.10488813/Tr
        T4=0.68157001/Tr**3
        T5=0.27*Pr/Tr
        dZ=T1+2*T2*g+5*T3*g**4+2*T4*g*(1+0.68446549*g**2-0.68446549**2*g**4)*exp(-0.68446549*g**2)-T5/g
        return self.ppc.atm/P-0.27/Z**2/Tr*dz/(1+g/Z*dz)

    def Gas_Formation_Volume_Factor(self, T, P):
        return Z*T/288.9/P

    def Viscosity_Carr_Kobayashi_Burrows(self, T):
        """Carr, N., R. Kobayashi, and D. Burrows. “Viscosity of Hydrocarbon Gases under Pressure.” Transactions of the AIME 201 (1954): 270–275."""
        muo=8.118e-3-6.15e-3*log10(self.SG)+(1.709e-5-2.062e-6*self.SG)*unidades.Temperature(T, "R").F
        muN2=self.N2*(8.49e-3*log10(self.SG)+9.59e-3)
        muCO2=self.CO2*(9.08e-3*log10(self.SG)+6.24e-3)
        muH2S=self.H2S*(8.49e-3*log10(self.SG)+3.73e-3)
        return unidades.Viscosity(muo+muN2+muCO2+muH2S, "cP")

    def Viscosity_Lee_Gonzalez_Eakin(self, T, P):
        """Lee, A. L., M. H. Gonzalez, and B. E. Eakin. “The Viscosity of Natural Gases.” Journal of Petroleum Technology (August 1966): 997–1000."""
        t=unidades.Temperature(T).R
        K=(9.4+0.02*self.M)*t**1.5/(209+19*self.M+t)
        X=3.5+986/t+0.01*self.M
        Y=2.4-0.2*X
        return unidades.Viscosity(1e-4*K*exp(X*(self.RhoG(T, P).lbft3/62.4)**Y), "cP")



if __name__ == '__main__':
    Crudo(index=1)