Exemplo n.º 1
0
    def to(self, zs, T=None, P=None, V=None):
        new = self.__class__.__new__(self.__class__)
        new.zs = zs
        new.N = self.N
        new.HeatCapacityGases = self.HeatCapacityGases
        new.model = model = self.model
        new.Hfs = self.Hfs
        new.Gfs = self.Gfs
        new.Sfs = self.Sfs
        if T is not None:
            new.T = T
            if P is not None:
                new.P = P
                Z = Z_from_virial_density_form(T, P, new.B(), new.C())
                new._V = Z * self.R * T / P
            elif V is not None:
                P = new.P = self.R * T * (V * V + V * new.B() +
                                          new.C()) / (V * V * V)
                new._V = V
        elif P is not None and V is not None:
            new.P = P

            # PV specified, solve for T
            def err(T):
                # Solve for P matching; probably there is a better solution here that does not
                # require the cubic solution but this works for now
                # TODO: instead of using self.to_TP_zs to allow calculating B and C,
                # they should be functional
                new_tmp = self.to_TP_zs(T=T, P=P, zs=zs)
                B = new_tmp.B()
                C = new_tmp.C()
                x2 = V * V + V * B + C
                x3 = self.R / (V * V * V)

                P_err = T * x2 * x3 - P
                dP_dT = x3 * (T * (V * new_tmp.dB_dT() + new_tmp.dC_dT()) + x2)
                return P_err, dP_dT

            T_ig = P * V / self.R  # guess
            T = newton(err, T_ig, fprime=True, xtol=1e-15)
            new.T = T
        else:
            raise ValueError("Two of T, P, or V are needed")

        return new
Exemplo n.º 2
0
    def solve_prop_poly_fit(self, goal):
        poly_fit_Tmin, poly_fit_Tmax = self.poly_fit_Tmin, self.poly_fit_Tmax
        poly_fit_Tmin_slope, poly_fit_Tmax_slope = self.poly_fit_Tmin_slope, self.poly_fit_Tmax_slope
        poly_fit_Tmin_value, poly_fit_Tmax_value = self.poly_fit_Tmin_value, self.poly_fit_Tmax_value
        coeffs = self.poly_fit_coeffs

        T_low = log(goal * exp(poly_fit_Tmin * poly_fit_Tmin_slope -
                               poly_fit_Tmin_value)) / poly_fit_Tmin_slope
        if T_low <= poly_fit_Tmin:
            return T_low
        T_high = log(goal * exp(poly_fit_Tmax * poly_fit_Tmax_slope -
                                poly_fit_Tmax_value)) / poly_fit_Tmax_slope
        if T_high >= poly_fit_Tmax:
            return T_high
        else:
            lnPGoal = log(goal)

            def to_solve(T):
                # dPsat and Psat are both in log basis
                dPsat = Psat = 0.0
                for c in coeffs:
                    dPsat = T * dPsat + Psat
                    Psat = T * Psat + c

                return Psat - lnPGoal, dPsat

            # Guess with the two extrapolations from the linear fits
            # By definition both guesses are in the range of they would have been returned
            if T_low > poly_fit_Tmax:
                T_low = poly_fit_Tmax
            if T_high < poly_fit_Tmin:
                T_high = poly_fit_Tmin
            T = newton(to_solve,
                       0.5 * (T_low + T_high),
                       fprime=True,
                       low=poly_fit_Tmin,
                       high=poly_fit_Tmax)
            return T
Exemplo n.º 3
0
def Thome(m,
          x,
          D,
          rhol,
          rhog,
          mul,
          mug,
          kl,
          kg,
          Cpl,
          Cpg,
          Hvap,
          sigma,
          Psat,
          Pc,
          q=None,
          Te=None):
    r'''Calculates heat transfer coefficient for film boiling of saturated
    fluid in any orientation of flow. Correlation
    is as developed in [1]_ and [2]_, and also reviewed [3]_. This is a 
    complicated model, but expected to have more accuracy as a result.
    
    Either the heat flux or excess temperature is required for the calculation
    of heat transfer coefficient. The solution for a specified excess 
    temperature is solved numerically, making it slow.
    
    .. math::
        h(z) = \frac{t_l}{\tau} h_l(z) +\frac{t_{film}}{\tau} h_{film}(z) 
        +  \frac{t_{dry}}{\tau} h_{g}(z) 
    
    .. math::
        h_{l/g}(z) = (Nu_{lam}^4 + Nu_{trans}^4)^{1/4} k/D
        
    .. math::
        Nu_{laminar} = 0.91 {Pr}^{1/3} \sqrt{ReD/L(z)}
        
    .. math::
        Nu_{trans} = \frac{ (f/8) (Re-1000)Pr}{1+12.7 (f/8)^{1/2} (Pr^{2/3}-1)}
        \left[ 1 + \left( \frac{D}{L(z)}\right)^{2/3}\right]
        
    .. math::
        f = (1.82 \log_{10} Re - 1.64 )^{-2}
        
    .. math::
        L_l = \frac{\tau G_{tp}}{\rho_l}(1-x)
        
    .. math::
        L_{dry} = v_p t_{dry}
        
    .. math::
        t_l = \frac{\tau}{1 + \frac{\rho_l}{\rho_g}\frac{x}{1-x}}
        
    .. math::
        t_v = \frac{\tau}{1 + \frac{\rho_g}{\rho_l}\frac{1-x}{x}}
        
    .. math::
        \tau = \frac{1}{f_{opt}}
        
    .. math::
        f_{opt} = \left(\frac{q}{q_{ref}}\right)^{n_f}
        
    .. math::
        q_{ref} = 3328\left(\frac{P_{sat}}{P_c}\right)^{-0.5}
        
    .. math::
        t_{dry,film} = \frac{\rho_l \Delta H_{vap}}{q}[\delta_0(z) - 
        \delta_{min}]
        
    .. math::
        \frac{\delta_0}{D} = C_{\delta 0}\left(3\sqrt{\frac{\nu_l}{v_p D}}
        \right)^{0.84}\left[(0.07Bo^{0.41})^{-8} + 0.1^{-8}\right]^{-1/8}
        
    .. math::
        Bo = \frac{\rho_l D}{\sigma} v_p^2
        
    .. math::
        v_p = G_{tp} \left[\frac{x}{\rho_g} + \frac{1-x}{\rho_l}\right]
        
    .. math::
        h_{film}(z) = \frac{2 k_l}{\delta_0(z) + \delta_{min}(z)}
        
    .. math::
        \delta_{min} = 0.3\cdot 10^{-6} \text{m}
        
    .. math::
        C_{\delta,0} = 0.29
        
    .. math::
        n_f = 1.74
        
    if t dry film > tv:
    
    .. math::
        \delta_{end}(x) = \delta(z, t_v)
        
    .. math::
        t_{film} = t_v
        
    .. math::
        t_{dry} = 0
    
    Otherwise:
    
    .. math::
        \delta_{end}(z) = \delta_{min}
        
    .. math::
        t_{film} = t_{dry,film}
        
    .. math::
        t_{dry} = t_v - t_{film}
    
    Parameters
    ----------
    m : float
        Mass flow rate [kg/s]
    x : float
        Quality at the specific tube interval []
    D : float
        Diameter of the tube [m]
    rhol : float
        Density of the liquid [kg/m^3]
    rhog : float
        Density of the gas [kg/m^3]
    mul : float
        Viscosity of liquid [Pa*s]
    mug : float
        Viscosity of gas [Pa*s]
    kl : float
        Thermal conductivity of liquid [W/m/K]
    kg : float
        Thermal conductivity of gas [W/m/K]
    Cpl : float
        Heat capacity of liquid [J/kg/K]
    Cpg : float
        Heat capacity of gas [J/kg/K]
    Hvap : float
        Heat of vaporization of liquid [J/kg]
    sigma : float
        Surface tension of liquid [N/m]
    Psat : float
        Vapor pressure of fluid, [Pa]
    Pc : float
        Critical pressure of fluid, [Pa]
    q : float, optional
        Heat flux to wall [W/m^2]
    Te : float, optional
        Excess temperature of wall, [K]

    Returns
    -------
    h : float
        Heat transfer coefficient [W/m^2/K]

    Notes
    -----
    [1]_ and [2]_ have been reviewed, and are accurately reproduced in [3]_.
    
    [1]_ used data from 7 studies, covering 7 fluids and Dh from 0.7-3.1 mm, 
    heat flux from 0.5-17.8 W/cm^2, x from 0.01-0.99, and G from 50-564 
    kg/m^2/s.
    
    Liquid and/or gas slugs are both considered, and are hydrodynamically
    developing. `Ll` is the calculated length of liquid slugs, and `L_dry` 
    is the same for vapor slugs.
    
    Because of the complexity of the model and that there is some logic in this
    function, `Te` as an input may lead to a different solution that the
    calculated `q` will in return.
    
    Examples
    --------
    >>> Thome(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2,
    ... mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5, 
    ... Psat=1E5, Pc=22E6, q=1E5)
    1633.008836502032

    References
    ----------
    .. [1] Thome, J. R., V. Dupont, and A. M. Jacobi. "Heat Transfer Model for 
       Evaporation in Microchannels. Part I: Presentation of the Model." 
       International Journal of Heat and Mass Transfer 47, no. 14-16 (July 
       2004): 3375-85. doi:10.1016/j.ijheatmasstransfer.2004.01.006.
    .. [2] Dupont, V., J. R. Thome, and A. M. Jacobi. "Heat Transfer Model for 
       Evaporation in Microchannels. Part II: Comparison with the Database." 
       International Journal of Heat and Mass Transfer 47, no. 14-16 (July 
       2004): 3387-3401. doi:10.1016/j.ijheatmasstransfer.2004.01.007.
    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella. 
       "Review and Comparative Analysis of Studies on Saturated Flow Boiling in
       Small Channels." Nanoscale and Microscale Thermophysical Engineering 12,
       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.
    '''
    if q is None and Te:
        to_solve = lambda q: q / Thome(m=m,
                                       x=x,
                                       D=D,
                                       rhol=rhol,
                                       rhog=rhog,
                                       kl=kl,
                                       kg=kg,
                                       mul=mul,
                                       mug=mug,
                                       Cpl=Cpl,
                                       Cpg=Cpg,
                                       sigma=sigma,
                                       Hvap=Hvap,
                                       Psat=Psat,
                                       Pc=Pc,
                                       q=q) - Te
        q = newton(to_solve, 1E4)
        return Thome(m=m,
                     x=x,
                     D=D,
                     rhol=rhol,
                     rhog=rhog,
                     kl=kl,
                     kg=kg,
                     mul=mul,
                     mug=mug,
                     Cpl=Cpl,
                     Cpg=Cpg,
                     sigma=sigma,
                     Hvap=Hvap,
                     Psat=Psat,
                     Pc=Pc,
                     q=q)
    elif q is None and Te is None:
        raise Exception('Either q or Te is needed for this correlation')
    C_delta0 = 0.3E-6
    G = m / (pi / 4 * D**2)
    Rel = G * D * (1 - x) / mul
    Reg = G * D * x / mug
    qref = 3328 * (Psat / Pc)**-0.5
    fopt = (q / qref)**1.74
    tau = 1. / fopt

    vp = G * (x / rhog + (1 - x) / rhol)
    Bo = rhol * D / sigma * vp**2  # Not standard definition
    nul = nu_mu_converter(rho=rhol, mu=mul)
    delta0 = D * 0.29 * (3 * (nul / vp / D)**0.5)**0.84 * (
        (0.07 * Bo**0.41)**-8 + 0.1**-8)**(-1 / 8.)

    tl = tau / (1 + rhol / rhog * (x / (1. - x)))
    tv = tau / (1 + +rhog / rhol * ((1. - x) / x))

    t_dry_film = rhol * Hvap / q * (delta0 - C_delta0)
    if t_dry_film > tv:
        t_film = tv
        delta_end = delta0 - q / rhol / Hvap * tv  # what could time possibly be?
        t_dry = 0
    else:
        t_film = t_dry_film
        delta_end = C_delta0
        t_dry = tv - t_film
    Ll = tau * G / rhol * (1 - x)
    Ldry = t_dry * vp

    Prg = Prandtl(Cp=Cpg, k=kg, mu=mug)
    Prl = Prandtl(Cp=Cpl, k=kl, mu=mul)
    fg = (1.82 * log10(Reg) - 1.64)**-2
    fl = (1.82 * log10(Rel) - 1.64)**-2

    Nu_lam_Zl = 2 * 0.455 * (Prl)**(1 / 3.) * (D * Rel / Ll)**0.5
    Nu_trans_Zl = turbulent_Gnielinski(Re=Rel, Pr=Prl,
                                       fd=fl) * (1 + (D / Ll)**(2 / 3.))
    if Ldry == 0:
        Nu_lam_Zg, Nu_trans_Zg = 0, 0
    else:
        Nu_lam_Zg = 2 * 0.455 * (Prg)**(1 / 3.) * (D * Reg / Ldry)**0.5
        Nu_trans_Zg = turbulent_Gnielinski(Re=Reg, Pr=Prg,
                                           fd=fg) * (1 + (D / Ldry)**(2 / 3.))

    h_Zg = kg / D * (Nu_lam_Zg**4 + Nu_trans_Zg**4)**0.25
    h_Zl = kl / D * (Nu_lam_Zl**4 + Nu_trans_Zl**4)**0.25

    h_film = 2 * kl / (delta0 + C_delta0)
    return tl / tau * h_Zl + t_film / tau * h_film + t_dry / tau * h_Zg
Exemplo n.º 4
0
def v_terminal(D, rhop, rho, mu, Method=None):
    r'''Calculates terminal velocity of a falling sphere using any drag
    coefficient method supported by `drag_sphere`. The laminar solution for
    Re < 0.01 is first tried; if the resulting terminal velocity does not
    put it in the laminar regime, a numerical solution is used.

    .. math::
        v_t = \sqrt{\frac{4 g d_p (\rho_p-\rho_f)}{3 C_D \rho_f }}

    Parameters
    ----------
    D : float
        Diameter of the sphere, [m]
    rhop : float
        Particle density, [kg/m^3]
    rho : float
        Density of the surrounding fluid, [kg/m^3]
    mu : float
        Viscosity of the surrounding fluid [Pa*s]
    Method : string, optional
        A string of the function name to use, as in the dictionary
        drag_sphere_correlations

    Returns
    -------
    v_t : float
        Terminal velocity of falling sphere [m/s]

    Notes
    -----
    As there are no correlations implemented for Re > 1E6, an error will be
    raised if the numerical solver seeks a solution above that limit.

    The laminar solution is given in [1]_ and is:

    .. math::
        v_t = \frac{g d_p^2 (\rho_p - \rho_f)}{18 \mu_f}

    Examples
    --------
    >>> v_terminal(D=70E-6, rhop=2600., rho=1000., mu=1E-3)
    0.004142497244531304

    Example 7-1 in GPSA handbook, 13th edition:
        
    >>> from scipy.constants import *
    >>> v_terminal(D=150E-6, rhop=31.2*lb/foot**3, rho=2.07*lb/foot**3,  mu=1.2e-05)/foot
    0.4491992020345101
    
    The answer reported there is 0.46 ft/sec.

    References
    ----------
    .. [1] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,
       Eighth Edition. McGraw-Hill Professional, 2007.
    .. [2] Rushton, Albert, Anthony S. Ward, and Richard G. Holdich.
       Solid-Liquid Filtration and Separation Technology. 1st edition. Weinheim ;
       New York: Wiley-VCH, 1996.
    '''
    '''The following would be the ideal implementation. The actual function is
    optimized for speed, not readability
    def err(V):
        Re = rho*V*D/mu
        Cd = Barati_high(Re)
        V2 = (4/3.*g*D*(rhop-rho)/rho/Cd)**0.5
        return (V-V2)
    return fsolve(err, 1.)'''
    v_lam = g * D * D * (rhop - rho) / (18 * mu)
    Re_lam = Reynolds(V=v_lam, D=D, rho=rho, mu=mu)
    if Re_lam < 0.01 or Method == 'Stokes':
        return v_lam

    Re_almost = rho * D / mu
    main = 4 / 3. * g * D * (rhop - rho) / rho
    V_max = 1E6 / rho / D * mu  # where the correlation breaks down, Re=1E6

    def err(V):
        Cd = drag_sphere(Re_almost * V, Method=Method)
        return V - (main / Cd)**0.5

    # Begin the solver with 1/100 th the velocity possible at the maximum
    # Reynolds number the correlation is good for
    return float(newton(err, V_max / 100, tol=1E-12))
Exemplo n.º 5
0
def flash_wilson(zs, Tcs, Pcs, omegas, T=None, P=None, VF=None):
    r'''PVT flash model using Wilson's equation - useful for obtaining initial
    guesses for more rigorous models, or it can be used as its own model.
    Capable of solving with two of `T`, `P`, and `VF` for the other one;
    that results in three solve modes, but for `VF=1` and `VF=0`, there are
    additional solvers; for a total of seven solvers implemented.

    This model uses `flash_inner_loop` to solve the Rachford-Rice problem.

    .. math::
        K_i = \frac{P_c}{P} \exp\left(5.37(1+\omega)\left[1 - \frac{T_c}{T}
        \right]\right)

    Parameters
    ----------
    zs : list[float]
        Mole fractions of the phase being flashed, [-]
    Tcs : list[float]
        Critical temperatures of all species, [K]
    Pcs : list[float]
        Critical pressures of all species, [Pa]
    omegas : list[float]
        Acentric factors of all species, [-]
    T : float, optional
        Temperature, [K]
    P : float, optional
        Pressure, [Pa]
    VF : float, optional
        Molar vapor fraction, [-]

    Returns
    -------
    T : float
        Temperature, [K]
    P : float
        Pressure, [Pa]
    VF : float
        Molar vapor fraction, [-]
    xs : list[float]
        Mole fractions of liquid phase, [-]
    ys : list[float]
        Mole fractions of vapor phase, [-]

    Notes
    -----
    For the cases where `VF` is 1 or 0 and T is known, an explicit solution is
    used. For the same cases where `P` and `VF` are known, there is no explicit
    solution available.

    There is an internal `Tmax` parameter, set to 50000 K; which, in the event
    of convergence of the Secant method, is used as a bounded for a bounded
    solver. It is used in the PVF solvers. This typically allows pressures
    up to 2 GPa to be converged to. However, for narrow-boiling mixtures, the
    PVF failure may occur at much lower pressures.

    Examples
    --------
    >>> Tcs = [305.322, 540.13]
    >>> Pcs = [4872200.0, 2736000.0]
    >>> omegas = [0.099, 0.349]
    >>> zs = [0.4, 0.6]
    >>> flash_wilson(zs=zs, Tcs=Tcs, Pcs=Pcs, omegas=omegas, T=300, P=1e5)
    (300, 100000.0, 0.42219453293637355, [0.020938815080034565, 0.9790611849199654], [0.9187741856225791, 0.08122581437742094])
    '''
    T_MAX = 50000.0
    N = len(zs)
    # Assume T and P to begin with
    if T is not None and P is not None:
        # numba is failing its type inferences
        P_inv = 1.0 / P
        T_inv = 1.0 / T
        Ks = [0.0] * N
        for i in range(N):
            Ks[i] = P_inv * Pcs[i] * exp(
                (5.37 * (1.0 + omegas[i]) * (1.0 - Tcs[i] * T_inv)))


#        all_under_1, all_over_1 = True, True
#        for K in Ks:
#            if K < 1.0:
#                all_over_1 = False
#            else:
#                all_under_1 = False
#            if all_over_1:
#                raise ValueError("Fail")
#            elif all_under_1:
#                raise ValueError("Fail")
        ans = (T, P) + flash_inner_loop(zs=zs, Ks=Ks)
        return ans
    elif T is not None and VF is not None and VF == 0.0:
        ys = [0.0] * N
        P_bubble = 0.0
        T_inv = 1.0 / T
        for i in range(N):
            v = zs[i] * Pcs[i] * exp(
                (5.37 * (1.0 + omegas[i]) * (1.0 - Tcs[i] * T_inv)))
            P_bubble += v
            ys[i] = v
        P_inv = 1.0 / P_bubble
        for i in range(N):
            ys[i] *= P_inv
        return (T, P_bubble, 0.0, zs, ys)
    elif T is not None and VF is not None and VF == 1.0:
        xs = [0.0] * N
        P_dew = 0.
        T_inv = 1.0 / T
        for i in range(N):
            v = zs[i] / (Pcs[i] * exp(
                (5.37 * (1.0 + omegas[i]) * (1.0 - Tcs[i] * T_inv))))
            P_dew += v
            xs[i] = v
        P_dew = 1. / P_dew
        for i in range(N):
            xs[i] *= P_dew
        return (T, P_dew, 1.0, xs, zs)
    elif T is not None and VF is not None:
        # Solve for the pressure to create the desired vapor fraction
        P_bubble = 0.0
        P_dew = 0.
        T_inv = 1.0 / T
        K_Ps = [0.0] * N
        for i in range(N):
            K_P = Pcs[i] * exp(
                (5.37 * (1.0 + omegas[i]) * (1.0 - Tcs[i] * T_inv)))
            P_bubble += zs[i] * K_P
            P_dew += zs[i] / K_P
            K_Ps[i] = K_P
        P_dew = 1. / P_dew
        '''Rachford-Rice esque solution in terms of pressure.
        from sympy import *
        N = 1
        cmps = range(N)
        zs = z0, z1, z2, z3 = symbols('z0, z1, z2, z3')
        Ks_P = K0_P, K1_P, K2_P, K3_P = symbols('K0_P, K1_P, K2_P, K3_P')
        VF, P = symbols('VF, P')
        tot = 0
        for i in cmps:
            tot += zs[i]*(Ks_P[i]/P - 1)/(1 + VF*(Ks_P[i]/P - 1))
        cse([tot, diff(tot, P)], optimizations='basic')
        '''
        P_guess = P_bubble + VF * (P_dew - P_bubble)  # Linear interpolation
        P_calc = newton(err_Wilson_TVF,
                        P_guess,
                        fprime=True,
                        bisection=True,
                        low=P_dew,
                        high=P_bubble,
                        args=(N, VF, zs, K_Ps))
        P_inv = 1.0 / P_calc
        xs = K_Ps
        ys = [0.0] * N
        for i in range(N):
            Ki = K_Ps[i] * P_inv
            xi = zs[i] / (1.0 + VF * (Ki - 1.0))
            ys[i] = Ki * xi
            xs[i] = xi
        return (T, P_calc, VF, xs, ys)
    elif P is not None and VF is not None:
        P_inv = 1.0 / P
        Ks = [0.0] * N
        xs = [0.0] * N
        x50s = [5.37] * N
        for i in range(N):
            x50s[i] *= omegas[i] + 1.0
        T_low, T_high = 1e100, 0.0
        logP = log(P)
        for i in range(N):
            T_K_1 = Tcs[i] * x50s[i] / (x50s[i] - logP + log(Pcs[i]))
            if T_K_1 < T_low:
                T_low = T_K_1
            if T_K_1 > T_high:
                T_high = T_K_1
        if T_low < 0.0:
            T_low = 1e-12
        if T_high <= 0.0:
            raise ValueError(
                "No temperature exists which makes Wilson K factor above 1 - decrease pressure"
            )
        if T_high < 0.1 * T_MAX:
            T_guess = 0.5 * (T_low + T_high)
        else:
            T_guess = 0.0
            for i in range(N):
                T_guess += zs[i] * Tcs[i]
            T_guess *= 0.666666
            if T_guess < T_low:
                T_guess = T_low + 1.0  # Take a nominal step
        T_calc = newton(
            err_Wilson_PVF,
            T_guess,
            fprime=True,
            low=T_low,
            xtol=1e-13,
            bisection=True,
            args=(N, P_inv, VF, Tcs, Pcs, Ks, zs, xs,
                  x50s))  # High bound not actually a bound, only low bound
        if 1e-10 < T_calc < T_MAX:
            ys = x50s
            for i in range(N):
                ys[i] = xs[i] * Ks[i]
            return (T_calc, P, VF, xs, ys)
    else:
        raise ValueError("Provide two of P, T, and VF")
Exemplo n.º 6
0
def v_terminal(D, rhop, rho, mu, Method=None):
    r'''Calculates terminal velocity of a falling sphere using any drag
    coefficient method supported by `drag_sphere`. The laminar solution for
    Re < 0.01 is first tried; if the resulting terminal velocity does not
    put it in the laminar regime, a numerical solution is used.

    .. math::
        v_t = \sqrt{\frac{4 g d_p (\rho_p-\rho_f)}{3 C_D \rho_f }}

    Parameters
    ----------
    D : float
        Diameter of the sphere, [m]
    rhop : float
        Particle density, [kg/m^3]
    rho : float
        Density of the surrounding fluid, [kg/m^3]
    mu : float
        Viscosity of the surrounding fluid [Pa*s]
    Method : string, optional
        A string of the function name to use, as in the dictionary
        drag_sphere_correlations

    Returns
    -------
    v_t : float
        Terminal velocity of falling sphere [m/s]

    Notes
    -----
    As there are no correlations implemented for Re > 1E6, an error will be
    raised if the numerical solver seeks a solution above that limit.

    The laminar solution is given in [1]_ and is:

    .. math::
        v_t = \frac{g d_p^2 (\rho_p - \rho_f)}{18 \mu_f}

    Examples
    --------
    >>> v_terminal(D=70E-6, rhop=2600., rho=1000., mu=1E-3)
    0.004142497244531304

    Example 7-1 in GPSA handbook, 13th edition:
        
    >>> from scipy.constants import *
    >>> v_terminal(D=150E-6, rhop=31.2*lb/foot**3, rho=2.07*lb/foot**3,  mu=1.2e-05)/foot
    0.4491992020345101
    
    The answer reported there is 0.46 ft/sec.

    References
    ----------
    .. [1] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,
       Eighth Edition. McGraw-Hill Professional, 2007.
    .. [2] Rushton, Albert, Anthony S. Ward, and Richard G. Holdich.
       Solid-Liquid Filtration and Separation Technology. 1st edition. Weinheim ;
       New York: Wiley-VCH, 1996.
    '''
    '''The following would be the ideal implementation. The actual function is
    optimized for speed, not readability
    def err(V):
        Re = rho*V*D/mu
        Cd = Barati_high(Re)
        V2 = (4/3.*g*D*(rhop-rho)/rho/Cd)**0.5
        return (V-V2)
    return fsolve(err, 1.)'''
    v_lam = g*D*D*(rhop-rho)/(18*mu)
    Re_lam = Reynolds(V=v_lam, D=D, rho=rho, mu=mu)
    if Re_lam < 0.01 or Method == 'Stokes':
        return v_lam

    Re_almost = rho*D/mu
    main = 4/3.*g*D*(rhop-rho)/rho
    V_max = 1E6/rho/D*mu  # where the correlation breaks down, Re=1E6

    def err(V):
        Cd = drag_sphere(Re_almost*V, Method=Method)
        return V - (main/Cd)**0.5
    # Begin the solver with 1/100 th the velocity possible at the maximum
    # Reynolds number the correlation is good for
    return float(newton(err, V_max/100, tol=1E-12))
Exemplo n.º 7
0
def liquid_jet_pump_ancillary(rhop, rhos, Kp, Ks, d_nozzle=None, d_mixing=None, 
                              Qp=None, Qs=None, P1=None, P2=None):
    r'''Calculates the remaining variable in a liquid jet pump when solving for
    one if the inlet variables only and the rest of them are known. The
    equation comes from conservation of energy and momentum in the mixing
    chamber.
    
    The variable to be solved for must be one of `d_nozzle`, `d_mixing`,
    `Qp`, `Qs`, `P1`, or `P2`.
    
    .. math::
        P_1 - P_2 = \frac{1}{2}\rho_pV_n^2(1+K_p)
        - \frac{1}{2}\rho_s V_3^2(1+K_s)
        
    Rearrange to express V3 in terms of Vn, and using the density ratio `C`,  
    the expression becomes:
        
    .. math::
        P_1 - P_2 = \frac{1}{2}\rho_p V_n^2\left[(1+K_p) - C(1+K_s) 
        \left(\frac{MR}{1-R}\right)^2\right]

    Using the primary nozzle area and flow rate:
        
    .. math::
        P_1 - P_2 = \frac{1}{2}\rho_p \left(\frac{Q_p}{A_n}\right)^2
        \left[(1+K_p) - C(1+K_s) \left(\frac{MR}{1-R}\right)^2\right]

    For `P`, `P2`, `Qs`, and `Qp`, the equation can be rearranged explicitly 
    for them. For `d_mixing` and `d_nozzle`, a bounded solver is used searching
    between 1E-9 m and 20 times the other diameter which was specified.

    Parameters
    ----------
    rhop : float
        The density of the primary (motive) fluid, [kg/m^3]
    rhos : float
        The density of the secondary fluid (drawn from the vacuum chamber),
        [kg/m^3]
    Kp : float
        The primary nozzle loss coefficient, [-]
    Ks : float
        The secondary inlet loss coefficient, [-]
    d_nozzle : float, optional
        The inside diameter of the primary fluid's nozle, [m]
    d_mixing : float, optional
        The diameter of the mixing chamber, [m]
    Qp : float, optional
        The volumetric flow rate of the primary fluid, [m^3/s]
    Qs : float, optional
        The volumetric flow rate of the secondary fluid, [m^3/s]
    P1 : float, optional
        The pressure of the primary fluid entering its nozzle, [Pa]
    P2 : float, optional
        The pressure of the secondary fluid at the entry of the ejector, [Pa]
        
    Returns
    -------
    solution : float
        The parameter not specified (one of `d_nozzle`, `d_mixing`,
        `Qp`, `Qs`, `P1`, or `P2`), (units of `m`, `m`, `m^3/s`, `m^3/s`,
        `Pa`, or `Pa` respectively)

    Notes
    -----
    The following SymPy code was used to obtain the analytical formulas (
    they are not shown here due to their length):
    
    >>> from sympy import *
    >>> A_nozzle, A_mixing, Qs, Qp, P1, P2, rhos, rhop, Ks, Kp = symbols('A_nozzle, A_mixing, Qs, Qp, P1, P2, rhos, rhop, Ks, Kp')
    >>> R = A_nozzle/A_mixing
    >>> M = Qs/Qp
    >>> C = rhos/rhop
    >>> rhs = rhop/2*(Qp/A_nozzle)**2*((1+Kp) - C*(1 + Ks)*((M*R)/(1-R))**2 )
    >>> new = Eq(P1 - P2,  rhs)
    >>> #solve(new, Qp)
    >>> #solve(new, Qs)
    >>> #solve(new, P1)
    >>> #solve(new, P2)

    Examples
    --------
    Calculating primary fluid nozzle inlet pressure P1:
    
    >>> liquid_jet_pump_ancillary(rhop=998., rhos=1098., Ks=0.11, Kp=.04, 
    ... P2=133600, Qp=0.01, Qs=0.01, d_mixing=0.045, d_nozzle=0.02238)
    426434.60314398084

    References
    ----------
    .. [1] Ejectors and Jet Pumps. Design and Performance for Incompressible 
       Liquid Flow. 85032. ESDU International PLC, 1985.
    '''
    unknowns = sum(i is None for i in (d_nozzle, d_mixing, Qs, Qp, P1, P2))
    if unknowns > 1:
        raise Exception('Too many unknowns')
    elif unknowns < 1:
        raise Exception('Overspecified')
    C = rhos/rhop
    
    if Qp is not None and Qs is not None:
        M = Qs/Qp
    if d_nozzle is not None:
        A_nozzle = pi/4*d_nozzle*d_nozzle
        if d_mixing is not None:
            A_mixing = pi/4*d_mixing*d_mixing
            R = A_nozzle/A_mixing
            
    if P1 is None:        
        return rhop/2*(Qp/A_nozzle)**2*((1+Kp) - C*(1 + Ks)*((M*R)/(1-R))**2 ) + P2
    elif P2 is None:
        return -rhop/2*(Qp/A_nozzle)**2*((1+Kp) - C*(1 + Ks)*((M*R)/(1-R))**2 ) + P1
    elif Qs is None:
        try:
            return ((-2*A_nozzle**2*P1 + 2*A_nozzle**2*P2 + Kp*Qp**2*rhop + Qp**2*rhop)/(C*rhop*(Ks + 1)))**0.5*(A_mixing - A_nozzle)/A_nozzle
        except ValueError:
            return -1j
    elif Qp is None:
        return A_nozzle*((2*A_mixing**2*P1 - 2*A_mixing**2*P2 - 4*A_mixing*A_nozzle*P1 + 4*A_mixing*A_nozzle*P2 + 2*A_nozzle**2*P1 - 2*A_nozzle**2*P2 + C*Ks*Qs**2*rhop + C*Qs**2*rhop)/(rhop*(Kp + 1)))**0.5/(A_mixing - A_nozzle)
    elif d_nozzle is None:
        def err(d_nozzle):
            return P1 - liquid_jet_pump_ancillary(rhop=rhop, rhos=rhos, Kp=Kp, Ks=Ks, d_nozzle=d_nozzle, d_mixing=d_mixing, Qp=Qp, Qs=Qs, 
                              P1=None, P2=P2)
        return brenth(err, 1E-9, d_mixing*20)
    elif d_mixing is None:
        def err(d_mixing):
            return P1 - liquid_jet_pump_ancillary(rhop=rhop, rhos=rhos, Kp=Kp, Ks=Ks, d_nozzle=d_nozzle, d_mixing=d_mixing, Qp=Qp, Qs=Qs, 
                              P1=None, P2=P2)
        try:
            return brenth(err, 1E-9, d_nozzle*20)
        except:
            return newton(err, d_nozzle*2)
Exemplo n.º 8
0
def Stichlmair_wet(Vg, Vl, rhog, rhol, mug, voidage, specific_area, C1, C2, C3, H=1):
    r'''Calculates dry pressure drop across a packed column, using the
    Stichlmair [1]_ correlation. Uses three regressed constants for each
    type of packing, and voidage and specific area. This model is for irrigated
    columns only.

    Pressure drop is given by:

    .. math::
        \frac{\Delta P_{irr}}{H} = \frac{\Delta P_{dry}}{H}\left(\frac
        {1-\epsilon + h_T}{1-\epsilon}\right)^{(2+c)/3}
        \left(\frac{\epsilon}{\epsilon-h_T}\right)^{4.65}

    .. math::
        h_T = h_0\left[1 + 20\left(\frac{\Delta Pirr}{H\rho_L g}\right)^2\right]

    .. math::
        Fr_L = \frac{V_L^2 a}{g \epsilon^{4.65}}

    .. math::
        h_0 = 0.555 Fr_L^{1/3}

    .. math::
        c = \frac{-C_1/Re_g - C_2/(2Re_g^{0.5})}{f_0}

    .. math::
        \Delta P_{dry} = \frac{3}{4} f_0 \frac{1-\epsilon}{\epsilon^{4.65}}
        \rho_G \frac{H}{d_p}V_g^2

    .. math::
        f_0 = \frac{C_1}{Re_g} + \frac{C_2}{Re_g^{0.5}} + C_3

    .. math::
        d_p = \frac{6(1-\epsilon)}{a}

    Parameters
    ----------
    Vg : float
        Superficial velocity of gas, Q/A [m/s]
    Vl : float
        Superficial velocity of liquid, Q/A [m/s]
    rhog : float
        Density of gas [kg/m^3]
    rhol : float
        Density of liquid [kg/m^3]
    mug : float
        Viscosity of gas [Pa*s]
    voidage : float
        Voidage of bed of packing material []
    specific_area : float
        Specific area of the packing material [m^2/m^3]
    C1 : float
        Packing-specific constant []
    C2 : float
        Packing-specific constant []
    C3 : float
        Packing-specific constant []
    H : float, optional
        Height of packing [m]

    Returns
    -------
    dP : float
        Pressure drop across irrigated packing [Pa]

    Notes
    -----
    This model is used by most process simulation tools. If H is not provided,
    it defaults to 1. If Z is not provided, it defaults to 1.
    A numerical solver is used and needed by this model. Its initial guess
    is the dry pressure drop. Convergence problems may occur.
    The model as described in [1]_ appears to have a typo, and could not match
    the example. As described in [2]_, however, the model works.

    Examples
    --------
    Example is from [1]_, matches.

    >>> Stichlmair_wet(Vg=0.4, Vl = 5E-3, rhog=5., rhol=1200., mug=5E-5,
    ... voidage=0.68, specific_area=260., C1=32., C2=7., C3=1.)
    539.8768237253518

    References
    ----------
    .. [1] Stichlmair, J., J. L. Bravo, and J. R. Fair. "General Model for
       Prediction of Pressure Drop and Capacity of Countercurrent Gas/liquid
       Packed Columns." Gas Separation & Purification 3, no. 1 (March 1989):
       19-28. doi:10.1016/0950-4214(89)80016-7.
    .. [2] Piche, Simon R., Faical Larachi, and Bernard P. A. Grandjean.
       "Improving the Prediction of Irrigated Pressure Drop in Packed
       Absorption Towers." The Canadian Journal of Chemical Engineering 79,
       no. 4 (August 1, 2001): 584-94. doi:10.1002/cjce.5450790417.
    '''
    dp = 6.0*(1.0 - voidage)/specific_area
    Re = Vg*rhog*dp/mug
    f0 = C1/Re + C2/Re**0.5 + C3
    dP_dry = 3/4.*f0*(1-voidage)/voidage**4.65*rhog*H/dp*Vg*Vg
    c = (-C1/Re - C2/(2*Re**0.5))/f0
    Frl = Vl**2*specific_area/(g*voidage**4.65)
    h0 = 0.555*Frl**(1/3.)
    def to_zero(dP_irr):
        hT = h0*(1.0 + 20.0*(dP_irr/H/rhol/g)**2)
        err = dP_dry/H*((1-voidage+hT)/(1.0 - voidage))**((2.0 + c)/3.)*(voidage/(voidage-hT))**4.65 -dP_irr/H
        return err
    return float(newton(to_zero, dP_dry))