def list_methods(): methods = [] if none_and_length_check([xs, sigmas, rhoms]): methods.append(WINTERFELDSCRIVENDAVIS) if T and none_and_length_check([xs, sigmas_Tb, Tbs, Tcs]): methods.append(DIGUILIOTEJA) if none_and_length_check([xs, sigmas]): methods.append(SIMPLE) methods.append(NONE) return methods
def list_methods(): methods = [] if none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') if none_and_length_check([Tcs]) and all([T >= i for i in Tcs]): methods.append('SUPERCRITICAL_T') if none_and_length_check([Pcs]) and all([P >= i for i in Pcs]): methods.append('SUPERCRITICAL_P') if none_and_length_check([zs, Tcs]) and any([T > Tc for Tc in Tcs]): methods.append('IDEAL_VLE_SUPERCRITICAL') methods.append('NONE') return methods
def list_methods(): methods = [] if none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') if none_and_length_check([Tcs]) and all([T >= i for i in Tcs]): methods.append('SUPERCRITICAL_T') if none_and_length_check([Pcs]) and all([P >= i for i in Pcs]): methods.append('SUPERCRITICAL_P') if none_and_length_check((zs, Tcs)) and any([T > Tc for Tc in Tcs]): methods.append('IDEAL_VLE_SUPERCRITICAL') methods.append('NONE') return methods
def list_methods(): methods = [] if none_and_length_check((Psats, zs)): methods.append(IDEALVLE) if none_and_length_check([Tcs]) and all([T >= i for i in Tcs]): methods.append(SUPERCRITICALT) if none_and_length_check([Pcs]) and all([P >= i for i in Pcs]): methods.append(SUPERCRITICALP) if none_and_length_check((zs, Tcs)) and any([T > Tc for Tc in Tcs]): methods.append(IDEALVLESUPERCRITICAL) methods.append(NONE) return methods
def load_all_methods(self): methods = [] methods.append(SIMPLE) # Needs sigma methods.append( WINTERFELDSCRIVENDAVIS) # Nothing to load, needs rhoms, sigma if none_and_length_check((self.Tbs, self.Tcs)): self.sigmas_Tb = [ i(Tb) for i, Tb in zip(self.SurfaceTensions, self.Tbs) ] # Unlikely but necessary to check all values were calculable if none_and_length_check([self.sigmas_Tb]): methods.append(DIGUILIOTEJA) self.all_methods = set(methods)
def flash(P, zs, Psats, fugacities=None, gammas=None): if not fugacities: fugacities = [1 for i in range(len(zs))] if not gammas: gammas = [1 for i in range(len(zs))] if not none_and_length_check((zs, Psats, fugacities, gammas)): raise Exception('Input dimentions are inconsistent or some input parameters are missing.') ks = [K(P, Psats[i], fugacities[i], gammas[i]) for i in range(len(zs))] def valid_range(zs, ks): valid = True if sum([zs[i]*ks[i] for i in range(len(ks))]) < 1: valid = False if sum([zs[i]/ks[i] for i in range(len(ks))]) < 1: valid = False return valid if not valid_range(zs, ks): raise Exception('Solution does not exist') # zs = [0.5, 0.3, 0.2] practice solution # ks = [1.685, 0.742, 0.532] x0 = np.array([.5]) V_over_F = fsolve(Rachford_Rice_flash_error, x0=x0, args=(zs, ks))[0] if V_over_F < 0: # print zs, ks raise Exception('V_over_F is negative!') xs = [zs[i]/(1+V_over_F*(ks[i]-1)) for i in range(len(zs))] ys = [ks[i]*xs[i] for i in range(len(zs))] return xs, ys, V_over_F
def list_methods(): methods = [] if none_and_length_check([Tms]): methods.append('Maximum') methods.append('Simple') methods.append('None') return methods
def Winterfeld_Scriven_Davis(xs, sigmas, rhoms): r'''Calculates surface tension of a liquid mixture according to mixing rules in [1]_ and also in [2]_. .. math:: \sigma_M = \sum_i \sum_j \frac{1}{V_L^{L2}}\left(x_i V_i \right) \left( x_jV_j\right)\sqrt{\sigma_i\cdot \sigma_j} Parameters ---------- xs : array-like Mole fractions of all components, [-] sigmas : array-like Surface tensions of all components, [N/m] rhoms : array-like Molar densities of all components, [mol/m^3] Returns ------- sigma : float Air-liquid surface tension of mixture, [N/m] Notes ----- DIPPR Procedure 7C: Method for the Surface Tension of Nonaqueous Liquid Mixtures Becomes less accurate as liquid-liquid critical solution temperature is approached. DIPPR Evaluation: 3-4% AARD, from 107 nonaqueous binary systems, 1284 points. Internally, densities are converted to kmol/m^3. The Amgat function is used to obtain liquid mixture density in this equation. Raises a ZeroDivisionError if either molar volume are zero, and a ValueError if a surface tensions of a pure component is negative. Examples -------- >>> Winterfeld_Scriven_Davis([0.1606, 0.8394], [0.01547, 0.02877], ... [8610., 15530.]) 0.024967388450439817 References ---------- .. [1] Winterfeld, P. H., L. E. Scriven, and H. T. Davis. "An Approximate Theory of Interfacial Tensions of Multicomponent Systems: Applications to Binary Liquid-Vapor Tensions." AIChE Journal 24, no. 6 (November 1, 1978): 1010-14. doi:10.1002/aic.690240610. .. [2] Danner, Ronald P, and Design Institute for Physical Property Data. Manual for Predicting Chemical Process Design Data. New York, N.Y, 1982. ''' if not none_and_length_check([xs, sigmas, rhoms]): raise Exception('Function inputs are incorrect format') rhoms = [i/1E3 for i in rhoms] Vms = [(i)**-1 for i in rhoms] rho = 1./mixing_simple(xs, Vms) sigma = 0 for i in range(len(xs)): for j in range(len(xs)): sigma += rho**2*xs[i]/rhoms[i]*xs[j]/rhoms[j]*(sigmas[j]*sigmas[i])**0.5 return sigma
def list_methods(): methods = [] if CASRNs: CASRNs2 = list(CASRNs) UFLs2 = list(UFLs) for i in inerts: if i in CASRNs2: ind = CASRNs.index(i) CASRNs2.remove(i) UFLs2.remove(UFLs[ind]) if none_and_length_check([UFLs2]): methods.append('Summed Inverse, inerts removed') if none_and_length_check([UFLs, ys]): methods.append('Summed Inverse') methods.append('None') return methods
def list_methods(): ''' List methods available to identify the phase of a mixture ''' methods = [] if Psats and none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') if (Tcs and none_and_length_check([Tcs]) and all([T >= i for i in Tcs])): methods.append('SUPERCRITICAL_T') if (Pcs and none_and_length_check([Pcs]) and all([P >= i for i in Pcs])): methods.append('SUPERCRITICAL_P') if (Tcs and none_and_length_check([zs, Tcs]) and any([T > Tc for Tc in Tcs])): methods.append('IDEAL_VLE_SUPERCRITICAL') methods.append('NONE') return methods
def flash(P, zs, Psats, fugacities=None, gammas=None): if not fugacities: fugacities = [1 for i in range(len(zs))] if not gammas: gammas = [1 for i in range(len(zs))] if not none_and_length_check((zs, Psats, fugacities, gammas)): raise Exception( 'Input dimentions are inconsistent or some input parameters are missing.' ) ks = [K(P, Psats[i], fugacities[i], gammas[i]) for i in range(len(zs))] def valid_range(zs, ks): valid = True if sum([zs[i] * ks[i] for i in range(len(ks))]) < 1: valid = False if sum([zs[i] / ks[i] for i in range(len(ks))]) < 1: valid = False return valid if not valid_range(zs, ks): raise Exception('Solution does not exist') # zs = [0.5, 0.3, 0.2] practice solution # ks = [1.685, 0.742, 0.532] x0 = np.array([.5]) V_over_F = fsolve(Rachford_Rice_flash_error, x0=x0, args=(zs, ks))[0] if V_over_F < 0: # print zs, ks raise Exception('V_over_F is negative!') xs = [zs[i] / (1 + V_over_F * (ks[i] - 1)) for i in range(len(zs))] ys = [ks[i] * xs[i] for i in range(len(zs))] return xs, ys, V_over_F
def list_methods(): ''' List methods available for calculating bubble pressure ''' methods = [] if none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') methods.append('NONE') return methods
def list_methods(): ''' List methods availble for calculating mixture dew point ''' methods = [] if none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') methods.append('NONE') return methods
def flash(P, zs, Psats): ''' Parameters ---------- P : list[float]? Pressure, [-] zs : list[float] Overall mole fractions of all species, [-] Psats : list[float]? Saturation pressure, [-] Returns ------- xs : list[float] Mole fractions of each species in the liquid phase, [-] ys : list[float] Mole fractions of each species in the vapor phase, [-] V_over_F : float Vapor fraction solution [-] ''' # if not fugacities: # fugacities = [1 for i in range(len(zs))] # if not gammas: # gammas = [1 for i in range(len(zs))] if not none_and_length_check((zs, Psats)): raise Exception('Input dimentions are inconsistent or some input ' 'parameters are missing.') Ks = [K_value(P=P, Psat=Psats[i]) for i in range(len(zs))] def valid_range(zs, Ks): ''' Determines if zs and Ks are valid for this calculation Parameters ---------- zs : list[float] Overall mole fractions of all species, [-] Ks : list[float] Equilibrium K-values, [-] Returns ------- valid : bool True if arguments are valid, False otherwise ''' valid = True if sum([zs[i] * Ks[i] for i in range(len(Ks))]) < 1: valid = False if sum([zs[i] / Ks[i] for i in range(len(Ks))]) < 1: valid = False return valid if not valid_range(zs, Ks): raise Exception('Solution does not exist') V_over_F, xs, ys = flash_inner_loop(zs=zs, Ks=Ks) if V_over_F < 0: raise Exception('V_over_F is negative!') return xs, ys, V_over_F
def list_methods(): ''' List methods available for calculating a mixture's acentric factor, omega ''' methods = [] if none_and_length_check([zs, omegas]): methods.append('SIMPLE') methods.append('NONE') return methods
def load_all_methods(self): r'''Method to initialize the object by precomputing any values which may be used repeatedly and by retrieving mixture-specific variables. All data are stored as attributes. This method also sets :obj:`Tmin`, :obj:`Tmax`, and :obj:`all_methods` as a set of methods which should work to calculate the property. Called on initialization only. See the source code for the variables at which the coefficients are stored. The coefficients can safely be altered once the class is initialized. This method can be called again to reset the parameters. ''' methods = [] methods.append(SIMPLE) # Needs sigma methods.append( WINTERFELDSCRIVENDAVIS) # Nothing to load, needs rhoms, sigma if none_and_length_check((self.Tbs, self.Tcs)): self.sigmas_Tb = [ i(Tb) for i, Tb in zip(self.SurfaceTensions, self.Tbs) ] if none_and_length_check([self.sigmas_Tb]): methods.append(DIGUILIOTEJA) self.all_methods = set(methods)
def dew_at_T(zs, Psats, fugacities=None, gammas=None): ''' >>> dew_at_T([0.5, 0.5], [1400, 7000]) 2333.3333333333335 >>> dew_at_T([0.5, 0.5], [1400, 7000], gammas=[1.1, .75]) 2381.443298969072 >>> dew_at_T([0.5, 0.5], [1400, 7000], gammas=[1.1, .75], fugacities=[.995, 0.98]) 2401.621874512658 ''' if not fugacities: fugacities = [1 for i in range(len(Psats))] if not gammas: gammas = [1 for i in range(len(Psats))] if not none_and_length_check((zs, Psats, fugacities, gammas)): raise Exception('Input dimentions are inconsistent or some input parameters are missing.') P = 1/sum(zs[i]*fugacities[i]/Psats[i]/gammas[i] for i in range(len(zs))) return P
def bubble_at_T(zs, Psats, fugacities=None, gammas=None): ''' >>> bubble_at_T([0.5, 0.5], [1400, 7000]) 4200.0 >>> bubble_at_T([0.5, 0.5], [1400, 7000], gammas=[1.1, .75]) 3395.0 >>> bubble_at_T([0.5, 0.5], [1400, 7000], gammas=[1.1, .75], fugacities=[.995, 0.98]) 3452.440775305097 ''' if not fugacities: fugacities = [1 for i in range(len(Psats))] if not gammas: gammas = [1 for i in range(len(Psats))] if not none_and_length_check((zs, Psats, fugacities, gammas)): raise Exception('Input dimentions are inconsistent or some input parameters are missing.') P = sum(zs[i]*Psats[i]*gammas[i]/fugacities[i] for i in range(len(zs))) return P
def flash(P, zs, Psats, fugacities=None, gammas=None): if not fugacities: fugacities = [1 for i in range(len(zs))] if not gammas: gammas = [1 for i in range(len(zs))] if not none_and_length_check((zs, Psats, fugacities, gammas)): raise Exception('Input dimentions are inconsistent or some input parameters are missing.') Ks = [K(P, Psats[i], fugacities[i], gammas[i]) for i in range(len(zs))] def valid_range(zs, Ks): valid = True if sum([zs[i]*Ks[i] for i in range(len(Ks))]) < 1: valid = False if sum([zs[i]/Ks[i] for i in range(len(Ks))]) < 1: valid = False return valid if not valid_range(zs, Ks): raise Exception('Solution does not exist') V_over_F, xs, ys = flash_inner_loop(zs=zs, Ks=Ks) if V_over_F < 0: raise Exception('V_over_F is negative!') return xs, ys, V_over_F
def Diguilio_Teja(T, xs, sigmas_Tb, Tbs, Tcs): r'''Calculates surface tension of a liquid mixture according to mixing rules in [1]_. .. math:: \sigma = 1.002855(T^*)^{1.118091} \frac{T}{T_b} \sigma_r T^* = \frac{(T_c/T)-1}{(T_c/T_b)-1} \sigma_r = \sum x_i \sigma_i T_b = \sum x_i T_{b,i} T_c = \sum x_i T_{c,i} Parameters ---------- T : float Temperature of fluid [K] xs : array-like Mole fractions of all components sigmas_Tb : array-like Surface tensions of all components at the boiling point, [N/m] Tbs : array-like Boiling temperatures of all components, [K] Tcs : array-like Critical temperatures of all components, [K] Returns ------- sigma : float Air-liquid surface tension of mixture, [N/m] Notes ----- Simple model, however it has 0 citations. Gives similar results to the `Winterfeld_Scriven_Davis` model. Raises a ValueError if temperature is greater than the mixture's critical temperature or if the given temperature is negative, or if the mixture's boiling temperature is higher than its critical temperature. Examples -------- >>> Diguilio_Teja(T=298.15, xs=[0.1606, 0.8394], ... sigmas_Tb=[0.01424, 0.02530], Tbs=[309.21, 312.95], Tcs=[469.7, 508.0]) 0.025716823875045505 References ---------- .. [1] Diguilio, Ralph, and Amyn S. Teja. "Correlation and Prediction of the Surface Tensions of Mixtures." The Chemical Engineering Journal 38, no. 3 (July 1988): 205-8. doi:10.1016/0300-9467(88)80079-0. ''' if not none_and_length_check([xs, sigmas_Tb, Tbs, Tcs]): raise Exception('Function inputs are incorrect format') Tc = mixing_simple(xs, Tcs) Tb = mixing_simple(xs, Tbs) sigmar = mixing_simple(xs, sigmas_Tb) Tst = (Tc/T - 1.)/(Tc/Tb - 1) sigma = 1.002855*Tst**1.118091*(T/Tb)*sigmar return sigma
def list_methods(): methods = [] if none_and_length_check((Psats, zs)): methods.append('IDEAL_VLE') methods.append('NONE') return methods
def list_methods(): methods = [] if none_and_length_check([zs, omegas]): methods.append('SIMPLE') methods.append('NONE') return methods
def list_methods(): methods = [] if none_and_length_check((Psats, zs)): methods.append(IDEALVLE) methods.append(NONE) return methods
def Diguilio_Teja(T, xs, sigmas_Tb, Tbs, Tcs): r'''Calculates surface tension of a liquid mixture according to mixing rules in [1]_. .. math:: \sigma = 1.002855(T^*)^{1.118091} \frac{T}{T_b} \sigma_r T^* = \frac{(T_c/T)-1}{(T_c/T_b)-1} \sigma_r = \sum x_i \sigma_i T_b = \sum x_i T_{b,i} T_c = \sum x_i T_{c,i} Parameters ---------- T : float Temperature of fluid [K] xs : array-like Mole fractions of all components sigmas_Tb : array-like Surface tensions of all components at the boiling point, [N/m] Tbs : array-like Boiling temperatures of all components, [K] Tcs : array-like Critical temperatures of all components, [K] Returns ------- sigma : float Air-liquid surface tension of mixture, [N/m] Notes ----- Simple model, however it has 0 citations. Gives similar results to the `Winterfeld_Scriven_Davis` model. Raises a ValueError if temperature is greater than the mixture's critical temperature or if the given temperature is negative, or if the mixture's boiling temperature is higher than its critical temperature. Examples -------- >>> Diguilio_Teja(T=298.15, xs=[0.1606, 0.8394], ... sigmas_Tb=[0.01424, 0.02530], Tbs=[309.21, 312.95], Tcs=[469.7, 508.0]) 0.025716823875045505 References ---------- .. [1] Diguilio, Ralph, and Amyn S. Teja. "Correlation and Prediction of the Surface Tensions of Mixtures." The Chemical Engineering Journal 38, no. 3 (July 1988): 205-8. doi:10.1016/0300-9467(88)80079-0. ''' if not none_and_length_check([xs, sigmas_Tb, Tbs, Tcs]): raise Exception('Function inputs are incorrect format') Tc = mixing_simple(xs, Tcs) Tb = mixing_simple(xs, Tbs) sigmar = mixing_simple(xs, sigmas_Tb) Tst = (Tc / T - 1.) / (Tc / Tb - 1) sigma = 1.002855 * Tst**1.118091 * (T / Tb) * sigmar return sigma