示例#1
0
    def temperature_loop(temperature):
        """ Uses fixed point iteration with Aitkens sequence acceleration to
        find the vapor phase composition """
        assert temperature > 0, "Temperature must be greater than zero"
        mixture.temperature = temperature
        lnphiL = model.logfug(mixture, 'liquid')
        y0 = mixture.composition['liquid'] * psatguess(mixture.critical['acentric'], mixture.reduced['temperature']) / mixture.reduced['pressure']

        for count in range(MAX_ITER):
            mixture.composition['vapor'] = y0 / y0.sum()
            lnphiV = model.logfug(mixture, 'vapor')
            y1 = mixture.composition['liquid'] * np.exp(lnphiL - lnphiV)

            mixture.composition['vapor'] = y1 / y1.sum()
            lnphiV = model.logfug(mixture, 'vapor')
            y2 = mixture.composition['liquid'] * np.exp(lnphiL - lnphiV)

            d = y2 - 2.0 * y1 + y0
            y = np.where(np.absolute(d) < 1e-16, y2, y2 - (y2 - y1)**2 / d)

            if np.allclose(y, y2, atol=ERROR_TOL):
                mixture.composition['vapor'] = y2 / y2.sum()
                return 1 - y.sum()
            y0 = y

        raise SearchError("Temperature loop ({} K) failed to converge after {} iterations".format(temperature, MAX_ITER))
示例#2
0
def raoult_bubble_temperature(model, mixture, pressure, psat=None):
    """ Calculates the bubble temperature at a given pressure using Raoult's law
    and a saturation pressure routine. Defaults to an approximate saturation
    pressure calculated using the Clausius-Clapeyron equation.
    Requires that the mixture have an overall composition, this is the assumed
    composition of the liquid at the bubble point.
    Returns a mixture with the vapor and liquid compositions at the bubble point
    and all state values and departure functions completed.
    This algorithm is unstable in the region close to the mixture critial point.
    model: model that implements the Model interface
    mixture: instance of Mixture
    pressure: float in Pascals
    psat: function, mixture -> saturation pressure in Pascals
    """
    mixture.pressure = pressure
    mixture.quality = 1.0
    mixture.composition['liquid'] = mixture.composition['overall']
    mixture.normalize()

    if psat is None:
        mixture.temperature = _rt_bt(mixture)
        Ps = psatguess(mixture.critical['acentric'], mixture.reduced['temperature']) * mixture.critical['pressure']
    else:
        T0 = np.dot(tsatguess(mixture.critical['acentric'], mixture.reduced['pressure']) * mixture.critical['temperature'], mixture.composition['liquid'])

        def temperature_loop(temperature):
            mixture.temperature = temperature
            Ps = psat(mixture)
            return pressure - np.dot(Ps, mixture.composition['liquid'])

        mixture.temperature = opt.newton(temperature_loop, T0)
        Ps = psat(mixture)

    mixture.composition['vapor'] = mixture.composition['liquid'] * Ps / mixture.pressure
    return model(mixture)
示例#3
0
def raoult_isothermalflash(mixture, q0=0.5):
    """ Performs isothermal flash using Raoult's Law """
    K = psatguess(mixture.critical['acentric'], mixture.reduced['temperature']) / mixture.reduced['pressure']

    try:
        quality = opt.newton(rachford_rice, q0, args=(mixture.composition['overall'], K))
    except RuntimeError:
        raise SearchError("Isothermal flash failed to converge")

    return quality
示例#4
0
    def loop(q0):
        z = mix.composition['overall']
        K = psatguess(mix.critical['acentric'], mix.reduced['temperature']) / mix.reduced['pressure']
        for count in range(MAX_ITER):
            mix.composition['liquid'] = z / (K + q0 * (1 - K))
            lnphiL = model.logfug(mix, 'liquid')

            mix.composition['vapor'] = mix.composition['liquid'] * K
            lnphiV = model.logfug(mix, 'vapor')

            K = np.exp(lnphiL - lnphiV)
            q1 = opt.newton(rachford_rice, q0, args=(z, K))

            if np.allclose(q1, q0, atol=ERROR_TOL):
                return q1

            q0 = q1

        raise SearchError("Isothermal flash (q= {}) failed to converge after {} iterations".format(q0, MAX_ITER))
示例#5
0
def _rt_bp(mixture):
    """ Calculate the bubble pressure using Raoult's Law"""
    return np.dot(psatguess(mixture.critical['acentric'], mixture.reduced['temperature']) * mixture.critical['pressure'], mixture.composition['liquid'])
示例#6
0
def two_loop_bubble_pressure(model, mixture, temperature, bounds=None):
    """ Calculates the bubble pressure at a given temperature, uses Raoult's law
    for an initial guess of the bubble pressure, unless otherwise specified
    Requires that the mixture have an overall composition, this is the assumed
    composition of the liquid at the bubble point.
    Returns a mixture with the vapor and liquid compositions at the bubble point
    and all state values and departure functions completed.
    This algorithm is unstable in the region close to the mixture critial point.
    model: model that implements the Model interface
    mixture: instance of Mixture
    temperature: float in Kelvin
    bounds: tuple, boundary of pressure region to search, in Pascals
    """
    mixture.temperature = temperature
    mixture.quality = 1.0
    mixture.composition['liquid'] = mixture.composition['overall']
    mixture.normalize()
    psat0 = psatguess(mixture.critical['acentric'], mixture.reduced['temperature'])

    def pressure_loop(pressure):
        """ Uses fixed point iteration with Aitkens sequence acceleration to
        find the vapor phase composition """
        assert pressure > 0, "Pressure must be greater than zero"
        mixture.pressure = pressure
        lnphiL = model.logfug(mixture, 'liquid')
        y0 = mixture.composition['liquid'] * psat0 / mixture.reduced['pressure']

        for count in range(MAX_ITER):
            mixture.composition['vapor'] = y0 / y0.sum()
            lnphiV = model.logfug(mixture, 'vapor')
            y1 = mixture.composition['liquid'] * np.exp(lnphiL - lnphiV)

            mixture.composition['vapor'] = y1 / y1.sum()
            lnphiV = model.logfug(mixture, 'vapor')
            y2 = mixture.composition['liquid'] * np.exp(lnphiL - lnphiV)

            d = y2 - 2.0 * y1 + y0
            y = np.where(np.absolute(d) < 1e-16, y2, y2 - (y2 - y1)**2 / d)

            if np.allclose(y, y2, atol=ERROR_TOL):
                mixture.composition['vapor'] = y2 / y2.sum()
                return 1 - y.sum()
            y0 = y

        raise SearchError("Pressure loop ({} Pa) failed to converge after {} iterations".format(pressure, MAX_ITER))

    # Find bracket for pressure loop zero and solve for bubble pressure
    if bounds is None:
        # Use Raoult's Law to get an initial guess of the bubble pressure
        p0 = _rt_bp(mixture)
        y0 = pressure_loop(p0)
        dp = -0.5 * p0 if y0 > 0 else +0.5 * p0
        bounds = bounds_search(pressure_loop, p0, dp)

    mixture.pressure = bounds[0]
    if np.all(mixture.reduced['pressure'] > Prcrit):
        msg = "Pressure {} is too high, bubble point routine is unstable in this region".format(p0)
        warnings.warn(msg, RuntimeWarning)

    mixture.pressure = opt.brentq(pressure_loop, *bounds)
    return model(mixture)