Example #1
0
def volume_solutions_numpy(T, P, b, delta, epsilon, a_alpha):
    r'''Calculate the molar volume solutions to a cubic equation of state using
    NumPy's `roots` function, which is a power series iterative matrix solution
    that is very stable but does not have full precision in some cases.

    Parameters
    ----------
    T : float
        Temperature, [K]
    P : float
        Pressure, [Pa]
    b : float
        Coefficient calculated by EOS-specific method, [m^3/mol]
    delta : float
        Coefficient calculated by EOS-specific method, [m^3/mol]
    epsilon : float
        Coefficient calculated by EOS-specific method, [m^6/mol^2]
    a_alpha : float
        Coefficient calculated by EOS-specific method, [J^2/mol^2/Pa]

    Returns
    -------
    Vs : list[float]
        Three possible molar volumes, [m^3/mol]

    Notes
    -----

    A sample region where this method does not obtain the correct solution
    (SRK EOS for ethane) is as follows:

    .. figure:: eos/volume_error_numpy_SRK_ethane.png
       :scale: 100 %
       :alt: numpy.roots error for SRK eos using ethane_


    References
    ----------
    .. [1] Reid, Robert C.; Prausnitz, John M.; Poling, Bruce E.
       Properties of Gases and Liquids. McGraw-Hill Companies, 1987.
    '''
    RT_inv = R_inv/T
    P_RT_inv = P*RT_inv
    B = etas = b*P_RT_inv
    deltas = delta*P_RT_inv
    thetas = a_alpha*P_RT_inv*RT_inv
    epsilons = epsilon*P_RT_inv*P_RT_inv

    b = (deltas - B - 1.0)
    c = (thetas + epsilons - deltas*(B + 1.0))
    d = -(epsilons*(B + 1.0) + thetas*etas)

    roots = np.roots([1.0, b, c, d]).tolist()
    RT_P = R*T/P
    return [V*RT_P for V in roots]
Example #2
0
def Z_from_virial_density_form(T, P, *args):
    r'''Calculates the compressibility factor of a gas given its temperature,
    pressure, and molar density-form virial coefficients. Any number of
    coefficients is supported.

    .. math::
        Z = \frac{PV}{RT} = 1 + \frac{B}{V} + \frac{C}{V^2} + \frac{D}{V^3}
        + \frac{E}{V^4} \dots

    Parameters
    ----------
    T : float
        Temperature, [K]
    P : float
        Pressure, [Pa]
    B to Z : float, optional
        Virial coefficients, [various]

    Returns
    -------
    Z : float
        Compressibility factor at T, P, and with given virial coefficients, [-]

    Notes
    -----
    For use with B or with B and C or with B and C and D, optimized equations
    are used to obtain the compressibility factor directly.
    If more coefficients are provided, uses numpy's roots function to solve
    this equation. This takes substantially longer as the solution is
    numerical.

    If no virial coefficients are given, returns 1, as per the ideal gas law.

    The units of each virial coefficient are as follows, where for B, n=1, and
    C, n=2, and so on.

    .. math::
        \left(\frac{\text{m}^3}{\text{mol}}\right)^n

    Examples
    --------
    >>> Z_from_virial_density_form(300, 122057.233762653, 1E-4, 1E-5, 1E-6, 1E-7)
    1.28434940526

    References
    ----------
    .. [1] Prausnitz, John M., Rudiger N. Lichtenthaler, and Edmundo Gomes de
       Azevedo. Molecular Thermodynamics of Fluid-Phase Equilibria. 3rd
       edition. Upper Saddle River, N.J: Prentice Hall, 1998.
    .. [2] Walas, Stanley M. Phase Equilibria in Chemical Engineering.
       Butterworth-Heinemann, 1985.
    '''
    l = len(args)
    if l == 1:
        return 1 / 2. + (4 * args[0] * P + R * T)**0.5 / (2 * (R * T)**0.5)


#        return ((R*T*(4*args[0]*P + R*T))**0.5 + R*T)/(2*P)
    if l == 2:
        B, C = args[0], args[1]
        # A small imaginary part is ignored
        return (
            P *
            (-(3 * B * R * T / P + R**2 * T**2 / P**2) /
             (3 * (-1 / 2 + csqrt(3) * 1j / 2) *
              (-9 * B * R**2 * T**2 / (2 * P**2) - 27 * C * R * T /
               (2 * P) + csqrt(-4 * (3 * B * R * T / P + R**2 * T**2 / P**2)**
                               (3 + 0j) +
                               (-9 * B * R**2 * T**2 / P**2 -
                                27 * C * R * T / P - 2 * R**3 * T**3 / P**3)**
                               (2 + 0j)) / 2 - R**3 * T**3 / P**3)**
              (1 / 3. + 0j)) - (-1 / 2 + csqrt(3) * 1j / 2) *
             (-9 * B * R**2 * T**2 / (2 * P**2) - 27 * C * R * T /
              (2 * P) + csqrt(-4 * (3 * B * R * T / P + R**2 * T**2 / P**2)**
                              (3 + 0j) +
                              (-9 * B * R**2 * T**2 / P**2 -
                               27 * C * R * T / P - 2 * R**3 * T**3 / P**3)**
                              (2 + 0j)) / 2 - R**3 * T**3 / P**3)**
             (1 / 3. + 0j) / 3 + R * T / (3 * P)) / (R * T)).real
    if l == 3:
        # Huge mess. Ideally sympy could optimize a function for quick python
        # execution. Derived with kate's text highlighting
        B, C, D = args[0], args[1], args[2]
        P2 = P**2
        RT = R * T
        BRT = B * RT
        T2 = T**2
        R2 = R**2
        RT23 = 3 * R2 * T2
        mCRT = -C * RT
        P2256 = 256 * P2

        RT23P2256 = RT23 / (P2256)
        big1 = (D * RT / P - (-BRT / P - RT23 / (8 * P2))**2 / 12 - RT *
                (mCRT / (4 * P) - RT * (BRT / (16 * P) + RT23P2256) / P) / P)
        big3 = (-BRT / P - RT23 / (8 * P2))
        big4 = (mCRT / P - RT * (BRT / (2 * P) + R2 * T2 / (8 * P2)) / P)
        big5 = big3 * (-D * RT / P + RT * (mCRT / (4 * P) - RT *
                                           (BRT /
                                            (16 * P) + RT23P2256) / P) / P)
        big2 = 2 * big1 / (
            3 *
            (big3**3 / 216 - big5 / 6 + big4**2 / 16 +
             csqrt(big1**3 / 27 +
                   (-big3**3 / 108 + big5 / 3 - big4**2 / 8)**2 / 4))**(1 / 3))
        big7 = 2 * BRT / (3 * P) - big2 + 2 * (
            big3**3 / 216 - big5 / 6 + big4**2 / 16 +
            csqrt(big1**3 / 27 +
                  (-big3**3 / 108 + big5 / 3 - big4**2 / 8)**2 / 4))**(
                      1 / 3) + R2 * T2 / (4 * P2)
        return (P * ((
            (csqrt(big7) / 2 +
             csqrt(4 * BRT / (3 * P) -
                   (-2 * C * RT / P - 2 * RT *
                    (BRT / (2 * P) + R2 * T2 /
                     (8 * P2)) / P) / csqrt(big7) + big2 - 2 *
                   (big3**3 / 216 - big5 / 6 + big4**2 / 16 +
                    csqrt(big1**3 / 27 +
                          (-big3**3 / 108 + big5 / 3 - big4**2 / 8)**2 / 4))**
                   (1 / 3) + R2 * T2 / (2 * P2)) / 2 + RT / (4 * P)))) / R /
                T).real

    size = l + 2
    #    arr = np.ones(size, dtype=np.complex128) # numba: uncomment
    arr = [1.0] * size  # numba: delete
    arr[-1] = -P / R / T
    for i in range(l):
        arr[-3 - i] = args[i]
    solns = np.roots(arr)
    for rho in solns:
        if abs(rho.imag) < 1e-12 and rho.real > 0.0:
            return float(P / (R * T * rho.real))
    raise ValueError("Could not find real root")