def _custom_set_poly_fit(self): try: Tmin, Tmax = self.poly_fit_Tmin, self.poly_fit_Tmax poly_fit_coeffs = self.poly_fit_coeffs v_Tmin = horner(poly_fit_coeffs, Tmin) for T_trans in linspace(Tmin, Tmax, 25): v, d1, d2 = horner_and_der2(poly_fit_coeffs, T_trans) Psat = exp(v) dPsat_dT = Psat * d1 d2Psat_dT2 = Psat * (d1 * d1 + d2) A, B, C = Antoine_ABC = Antoine_coeffs_from_point(T_trans, Psat, dPsat_dT, d2Psat_dT2, base=e) self.poly_fit_AB = list( Antoine_AB_coeffs_from_point(T_trans, Psat, dPsat_dT, base=e)) self.DIPPR101_ABC = list( DIPPR101_ABC_coeffs_from_point(T_trans, Psat, dPsat_dT, d2Psat_dT2)) B_OK = B > 0.0 # B is negated in this implementation, so the requirement is reversed C_OK = -T_trans < C < 0.0 if B_OK and C_OK: self.poly_fit_Antoine = Antoine_ABC break else: continue # Calculate the extrapolation values v_Tmax = horner(poly_fit_coeffs, Tmax) v, d1, d2 = horner_and_der2(poly_fit_coeffs, Tmax) Psat = exp(v) dPsat_dT = Psat * d1 d2Psat_dT2 = Psat * (d1 * d1 + d2) # A, B, C = Antoine_ABC = Antoine_coeffs_from_point(T_trans, Psat, dPsat_dT, d2Psat_dT2, base=e) self.poly_fit_AB_high = list( Antoine_AB_coeffs_from_point(Tmax, Psat, dPsat_dT, base=e)) self.poly_fit_AB_high_ABC_compat = [ self.poly_fit_AB_high[0], -self.poly_fit_AB_high[1] ] self.DIPPR101_ABC_high = list( DIPPR101_ABC_coeffs_from_point(Tmax, Psat, dPsat_dT, d2Psat_dT2)) except: pass
def mul(self, T): r'''Computes liquid viscosity at a specified temperature of an organic compound using the Joback method as a function of chemical structure only. .. math:: \mu_{liq} = \text{MW} \exp\left( \frac{ \sum_i \mu_a - 597.82}{T} + \sum_i \mu_b - 11.202 \right) Parameters ---------- T : float Temperature, [K] Returns ------- mul : float Liquid viscosity, [Pa*s] Examples -------- >>> J = Joback('CC(=O)C') >>> J.mul(300) 0.0002940378347162687 ''' if self.calculated_mul_coeffs is None: self.calculated_mul_coeffs = Joback.mul_coeffs(self.counts) a, b = self.calculated_mul_coeffs return self.MW*exp(a/T + b)
def EQ115(T, A, B, C=0, D=0, E=0): r'''DIPPR Equation #115. No major uses; has been used as an alternate liquid viscosity expression, and as a model for vapor pressure. Only parameters A and B are required. .. math:: Y = \exp\left(A + \frac{B}{T} + C\log T + D T^2 + \frac{E}{T^2}\right) Parameters ---------- T : float Temperature, [K] A-E : float Parameter for the equation; chemical and property specific [-] Returns ------- Y : float Property [constant-specific] Notes ----- No coefficients found for this expression. This function is not integrable for either dT or Y/T dT. References ---------- .. [1] Design Institute for Physical Properties, 1996. DIPPR Project 801 DIPPR/AIChE ''' return exp(A + B / T + C * log(T) + D * T**2 + E / T**2)
def Lee_Kesler(T, Tc, Pc, omega): r'''Calculates vapor pressure of a fluid at arbitrary temperatures using a CSP relationship by [1]_; requires a chemical's critical temperature and acentric factor. The vapor pressure is given by: .. math:: \ln P^{sat}_r = f^{(0)} + \omega f^{(1)} .. math:: f^{(0)} = 5.92714-\frac{6.09648}{T_r}-1.28862\ln T_r + 0.169347T_r^6 .. math:: f^{(1)} = 15.2518-\frac{15.6875}{T_r} - 13.4721 \ln T_r + 0.43577T_r^6 Parameters ---------- T : float Temperature of fluid [K] Tc : float Critical temperature of fluid [K] Pc : float Critical pressure of fluid [Pa] omega : float Acentric factor [-] Returns ------- Psat : float Vapor pressure at T [Pa] Notes ----- This equation appears in [1]_ in expanded form. The reduced pressure form of the equation ensures predicted vapor pressure cannot surpass the critical pressure. Examples -------- Example from [2]_; ethylbenzene at 347.2 K. >>> Lee_Kesler(347.2, 617.1, 36E5, 0.299) 13078.694162949312 References ---------- .. [1] Lee, Byung Ik, and Michael G. Kesler. "A Generalized Thermodynamic Correlation Based on Three-Parameter Corresponding States." AIChE Journal 21, no. 3 (1975): 510-527. doi:10.1002/aic.690210313. .. [2] Reid, Robert C..; Prausnitz, John M.;; Poling, Bruce E. The Properties of Gases and Liquids. McGraw-Hill Companies, 1987. ''' Tr = T / Tc logTr = log(Tr) Tr6 = Tr * Tr Tr6 *= Tr6 * Tr6 f0 = 5.92714 - 6.09648 / Tr - 1.28862 * logTr + 0.169347 * Tr6 f1 = 15.2518 - 15.6875 / Tr - 13.4721 * logTr + 0.43577 * Tr6 return exp(f0 + omega * f1) * Pc
def gibbs_excess_dgammas_dT(xs, GE, dGE_dT, dG_dxs, d2GE_dTdxs, N, T, dgammas_dT=None): if dgammas_dT is None: dgammas_dT = [0.0] * N xdx_totF0 = dGE_dT for j in range(N): xdx_totF0 -= xs[j] * d2GE_dTdxs[j] xdx_totF1 = GE for j in range(N): xdx_totF1 -= xs[j] * dG_dxs[j] T_inv = 1.0 / T RT_inv = R_inv * T_inv for i in range(N): dG_dni = xdx_totF1 + dG_dxs[i] dgammas_dT[i] = RT_inv * (d2GE_dTdxs[i] - dG_dni * T_inv + xdx_totF0) * exp(dG_dni * RT_inv) return dgammas_dT
def gammas(self): r'''Calculate and return the activity coefficients of a liquid phase using an activity coefficient model. .. math:: \gamma_i = \exp\left(\frac{\frac{\partial n_i G^E}{\partial n_i }}{RT}\right) Returns ------- gammas : list[float] Activity coefficients, [-] Notes ----- ''' try: return self._gammas except: pass # Matches the gamma formulation perfectly GE = self.GE() dG_dxs = self.dGE_dxs() if self.scalar: dG_dns = dxs_to_dn_partials(dG_dxs, self.xs, GE) RT_inv = 1.0 / (R * self.T) gammas = [exp(i * RT_inv) for i in dG_dns] else: gammas = gibbs_excess_gammas(self.xs, dG_dxs, GE, self.T) self._gammas = gammas return gammas
def Antoine_AB_coeffs_from_point(T, Psat, dPsat_dT, base=10.0): r'''Calculates the antoine coefficients `A`, `B`, with `C` set to zero to improve low-temperature or high-temperature extrapolation, from a known vapor pressure and its first temperature derivative. Parameters ---------- T : float Temperature of fluid, [K] Psat : float Vapor pressure at specified `T` [Pa] dPsat_dT : float First temperature derivative of vapor pressure at specified `T` [Pa/K] Base : float, optional Base of logarithm; 10 by default Returns ------- A : float Antoine `A` parameter, [-] B : float Antoine `B` parameter, [K] Notes ----- Coefficients are for calculating vapor pressure in Pascal. This is primarily useful for interconverting vapor pressure models, not fitting experimental data. Derived with SymPy as follows: >>> from sympy import * # doctest: +SKIP >>> base, A, B, T = symbols('base, A, B, T') # doctest: +SKIP >>> v = base**(A - B/T) # doctest: +SKIP >>> d1, d2 = diff(v, T), diff(v, T, 2) # doctest: +SKIP >>> vk, d1k = symbols('vk, d1k') # doctest: +SKIP >>> solve([Eq(v, vk), Eq(d1, d1k)], [A, B]) # doctest: +SKIP Examples -------- Recalculate some coefficients from a calcualted value and its derivative: >>> T = 178.01 >>> A, B = (27.358925161569008, 5445.569591293226) >>> Psat = Antoine(T, A, B, C=0, base=exp(1)) >>> dPsat_dT = B*exp(1)**(A - B/T)*log(exp(1))/T**2 >>> Antoine_AB_coeffs_from_point(T, Psat, dPsat_dT, base=exp(1)) (27.35892516156901, 5445.569591293226) References ---------- .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' log_base_inv = 1.0 / log(base) Psat_inv = 1.0 / Psat A = log(Psat * exp(T * dPsat_dT * Psat_inv)) * log_base_inv B = T * T * dPsat_dT * log_base_inv * Psat_inv return (A, B)
def regular_solution_gammas(T, xs, Vs, SPs, lambda_coeffs, N, xsVs=None, Hi_sums=None, dGE_dxs=None, gammas=None): if xsVs is None: xsVs = [0.0] * N for i in range(N): xsVs[i] = xs[i] * Vs[i] xsVs_sum = 0.0 for i in range(N): xsVs_sum += xsVs[i] xsVs_sum_inv = 1.0 / xsVs_sum if Hi_sums is None: Hi_sums = [0.0] * N Hi_sums = regular_solution_Hi_sums(SPs=SPs, Vs=Vs, xsVs=xsVs, coeffs=lambda_coeffs, N=N, Hi_sums=Hi_sums) GE = regular_solution_GE(SPs=SPs, xsVs=xsVs, coeffs=lambda_coeffs, N=N, xsVs_sum_inv=xsVs_sum_inv) if dGE_dxs is None: dGE_dxs = [0.0] * N dG_dxs = regular_solution_dGE_dxs(Vs=Vs, Hi_sums=Hi_sums, N=N, xsVs_sum_inv=xsVs_sum_inv, GE=GE, dGE_dxs=dGE_dxs) xdx_totF = GE for i in range(N): xdx_totF -= xs[i] * dG_dxs[i] if gammas is None: gammas = [0.0] * N for i in range(N): gammas[i] = dG_dxs[i] + xdx_totF RT_inv = 1.0 / (R * T) for i in range(N): gammas[i] *= RT_inv for i in range(N): gammas[i] = exp(gammas[i]) return gammas
def Henry_pressure_mixture(Hs, weights=None, zs=None): r'''Mixing rule for Henry's law components. Applies a logarithmic average to all solvent components and mole fractions. Optionally, weight factors can be provided instead of using mole fractions - only specify one of them. A common weight factor is using volume fractions of powers of them, or using critical volumes. Parameters ---------- Hs : list[float or None] Henry's law constant between each gas and the solvent (None for other solvents of gases without parameters available), [Pa] weights : list[float], optional Weight factors, [-] zs : list[float] Mole fractions of all species in phase, [-] Returns ------- H : value Henry's law constant for the gas in the liquid phase, [-] Notes ----- The default weight factor formulation is from [1]_. Examples -------- >>> Henry_pressure_mixture([1072330.36341, 744479.751106, None], zs=[.48, .48, .04]) 893492.1611602883 References ---------- .. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation. Weinheim, Germany: Wiley-VCH, 2012. ''' N = len(Hs) if weights is None and zs is None: raise ValueError("Weights or mole fractions are required") if weights is None: z_solvent = 0.0 for i in range(N): if Hs[i] is not None: z_solvent += zs[i] # Default parameters - when weight specified only weight by that z_solvent_inv = 1.0/z_solvent weights = [0.0]*N for i in range(N): weights[i] = zs[i]*z_solvent_inv num = 0.0 for i in range(N): if Hs[i] is not None: num += weights[i]*log(Hs[i]) H = exp(num) return H
def Wagner_original(T, Tc, Pc, a, b, c, d): r'''Calculates vapor pressure using the Wagner equation (3, 6 form). Requires critical temperature and pressure as well as four coefficients specific to each chemical. .. math:: \ln P^{sat}= \ln P_c + \frac{a\tau + b \tau^{1.5} + c\tau^3 + d\tau^6} {T_r} .. math:: \tau = 1 - \frac{T}{T_c} Parameters ---------- T : float Temperature of fluid, [K] Tc : float Critical temperature, [K] Pc : float Critical pressure, [Pa] a, b, c, d : floats Parameters for wagner equation. Specific to each chemical. [-] Returns ------- Psat : float Vapor pressure at T [Pa] Notes ----- Warning: Pc is often treated as adjustable constant. Examples -------- Methane, coefficients from [2]_, at 100 K. >>> Wagner_original(100.0, 190.53, 4596420., a=-6.00435, b=1.1885, ... c=-0.834082, d=-1.22833) 34520.44601450499 References ---------- .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. .. [2] McGarry, Jack. "Correlation and Prediction of the Vapor Pressures of Pure Liquids over Large Pressure Ranges." Industrial & Engineering Chemistry Process Design and Development 22, no. 2 (April 1, 1983): 313-22. doi:10.1021/i200021a023. ''' Tr = T / Tc tau = 1.0 - Tr tau2 = tau * tau tau_Tr = tau / Tr return Pc * exp(((d * tau2 * tau + c) * tau2 + a + b * sqrt(tau)) * tau_Tr)
def calculate_derivative(self, T, method, order=1): r'''Method to calculate a derivative of a vapor pressure with respect to temperature, of a given order using a specified method. If the method is BESTFIT, an anlytical derivative is used; otherwise SciPy's derivative function, with a delta of 1E-6 K and a number of points equal to 2*order + 1. If the calculation does not succeed, returns the actual error encountered. Parameters ---------- T : float Temperature at which to calculate the derivative, [K] method : str Method for which to find the derivative order : int Order of the derivative, >= 1 Returns ------- derivative : float Calculated derivative property, [`units/K^order`] ''' if order == 1 and method == BESTFIT: # if T < self.poly_fit_Tmin: # return self.poly_fit_Tmin_slope*exp( # (T - self.poly_fit_Tmin)*self.poly_fit_Tmin_slope # + self.poly_fit_Tmin_value) # elif T > self.poly_fit_Tmax: # return self.poly_fit_Tmax_slope*exp((T - self.poly_fit_Tmax) # *self.poly_fit_Tmax_slope # + self.poly_fit_Tmax_value) # else: v, der = horner_and_der(self.poly_fit_coeffs, T) return der * exp(v) elif order == 2 and method == BESTFIT: v, der, der2 = horner_and_der2(self.poly_fit_coeffs, T) return (der * der + der2) * exp(v) return super(VaporPressure, self).calculate_derivative(T, method, order)
def gibbs_excess_gammas(xs, dG_dxs, GE, T, gammas=None): xdx_totF = GE N = len(xs) for i in range(N): xdx_totF -= xs[i] * dG_dxs[i] RT_inv = R_inv / T if gammas is None: gammas = [0.0] * N for i in range(N): gammas[i] = exp((dG_dxs[i] + xdx_totF) * RT_inv) return gammas
def Psub_Clapeyron(T, Tt, Pt, Hsub_t): r'''Calculates sublimation pressure of a solid at arbitrary temperatures using an approximate themodynamic identity - the Clapeyron equation as described in [1]_ and [2]_. Requires a chemical's triple temperature, triple pressure, and triple enthalpy of sublimation. The sublimation pressure of a chemical at `T` is given by: .. math:: \ln \frac{P}{P_{tp}} = -\frac{\Delta H_{sub}}{R} \left(\frac{1}{T}-\frac{1}{T_{tp}} \right) Parameters ---------- T : float Temperature of solid [K] Tt : float Triple temperature of solid [K] Pt : float Truple pressure of solid [Pa] Hsub_t : float Enthalpy of fusion at the triple point of the chemical, [J/mol] Returns ------- Psub : float Sublimation pressure, [Pa] Notes ----- Does not seem to capture the decrease in sublimation pressure quickly enough. Examples -------- >>> Psub_Clapeyron(250, Tt=273.15, Pt=611.0, Hsub_t=51100.0) 76.06457150831804 >>> Psub_Clapeyron(300, Tt=273.15, Pt=611.0, Hsub_t=51100.0) 4577.282832876156 References ---------- .. [1] Goodman, B. T., W. V. Wilding, J. L. Oscarson, and R. L. Rowley. "Use of the DIPPR Database for the Development of QSPR Correlations: Solid Vapor Pressure and Heat of Sublimation of Organic Compounds." International Journal of Thermophysics 25, no. 2 (March 1, 2004): 337-50. https://doi.org/10.1023/B:IJOT.0000028471.77933.80. .. [2] Feistel, Rainer, and Wolfgang Wagner. "Sublimation Pressure and Sublimation Enthalpy of H2O Ice Ih between 0 and 273.16K." Geochimica et Cosmochimica Acta 71, no. 1 (January 1, 2007): 36-45. https://doi.org/10.1016/j.gca.2006.08.034. ''' return Pt * exp(Hsub_t * (T - Tt) / (R * T * Tt))
def solubility_eutectic(T, Tm, Hm, Cpl=0, Cps=0, gamma=1): r'''Returns the maximum solubility of a solute in a solvent. .. math:: \ln x_i^L \gamma_i^L = \frac{\Delta H_{m,i}}{RT}\left( 1 - \frac{T}{T_{m,i}}\right) - \frac{\Delta C_{p,i}(T_{m,i}-T)}{RT} + \frac{\Delta C_{p,i}}{R}\ln\frac{T_m}{T} .. math:: \Delta C_{p,i} = C_{p,i}^L - C_{p,i}^S Parameters ---------- T : float Temperature of the system [K] Tm : float Melting temperature of the solute [K] Hm : float Heat of melting at the melting temperature of the solute [J/mol] Cpl : float, optional Molar heat capacity of the solute as a liquid [J/mol/K] Cpls: float, optional Molar heat capacity of the solute as a solid [J/mol/K] gamma : float, optional Activity coefficient of the solute as a liquid [-] Returns ------- x : float Mole fraction of solute at maximum solubility [-] Notes ----- gamma is of the solute in liquid phase Examples -------- From [1]_, matching example >>> solubility_eutectic(T=260., Tm=278.68, Hm=9952., Cpl=0, Cps=0, gamma=3.0176) 0.2434007130748 References ---------- .. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation. Weinheim, Germany: Wiley-VCH, 2012. ''' dCp = Cpl - Cps x = exp(-R_inv * ((Hm * (1.0 - T / Tm) - dCp * (Tm - T)) / T + dCp * log(Tm / T))) / gamma return x
def Wagner(T, Tc, Pc, a, b, c, d): r'''Calculates vapor pressure using the Wagner equation (2.5, 5 form). Requires critical temperature and pressure as well as four coefficients specific to each chemical. .. math:: \ln P^{sat}= \ln P_c + \frac{a\tau + b \tau^{1.5} + c\tau^{2.5} + d\tau^5} {T_r} .. math:: \tau = 1 - \frac{T}{T_c} Parameters ---------- T : float Temperature of fluid, [K] Tc : float Critical temperature, [K] Pc : float Critical pressure, [Pa] a, b, c, d : floats Parameters for wagner equation. Specific to each chemical. [-] Returns ------- Psat : float Vapor pressure at T [Pa] Notes ----- Warning: Pc is often treated as adjustable constant. Examples -------- Methane, coefficients from [2]_, at 100 K. >>> Wagner(100., 190.551, 4599200, -6.02242, 1.26652, -0.5707, -1.366) 34415.00476263708 References ---------- .. [1] Wagner, W. "New Vapour Pressure Measurements for Argon and Nitrogen and a New Method for Establishing Rational Vapour Pressure Equations." Cryogenics 13, no. 8 (August 1973): 470-82. doi:10.1016/0011-2275(73)90003-9 .. [2] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' Tr = T / Tc tau = 1.0 - T / Tc return Pc * exp((a * tau + b * tau**1.5 + c * tau**2.5 + d * tau**5) / Tr)
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
def Watson_sigma(T, Tc, a1, a2, a3=0.0, a4=0.0, a5=0.0): r'''Calculates air-water surface tension using the Watson [1]_ emperical (parameter-regressed) method developed by NIST. .. math:: \sigma = \exp\left[a_{1} + \ln(1 - T_r)\left( a_2 + a_3T_r + a_4T_r^2 + a_5T_r^3 \right)\right] Parameters ---------- T : float Temperature of fluid [K] Tc : float Critical temperature of fluid [K] a1 : float Regression parameter, [-] a2 : float Regression parameter, [-] a3 : float Regression parameter, [-] a4 : float Regression parameter, [-] a5 : float Regression parameter, [-] Returns ------- sigma : float Liquid surface tension, [N/m] Notes ----- This expression is also used for enthalpy of vaporization in [1]_. The coefficients from NIST TDE for enthalpy of vaporization are kJ/mol. Examples -------- Isooctane at 350 K from [1]_: >>> Watson_sigma(T=350.0, Tc=543.836, a1=-3.02417, a2=1.21792, a3=-5.26877e-9, a4=5.62659e-9, a5=-2.27553e-9) 0.0138340926605649 References ---------- .. [1] "ThermoData Engine (TDE103b V10.1) User’s Guide." https://trc.nist.gov/TDE/Help/TDE103b/Eqns-Pure-SurfaceTension/HVPExpansion-SurfaceTension.htm ''' Tr = T / Tc l = log(1.0 - Tr) return exp(a1 + l * (a2 + Tr * (a3 + Tr * (a4 + a5 * Tr))))
def boiling_critical_relation(T, Tb, Tc, Pc): r'''Calculates vapor pressure of a fluid at arbitrary temperatures using a CSP relationship as in [1]_; requires a chemical's critical temperature and pressure as well as boiling point. The vapor pressure is given by: .. math:: \ln P^{sat}_r = h\left( 1 - \frac{1}{T_r}\right) .. math:: h = T_{br} \frac{\ln(P_c/101325)}{1-T_{br}} Parameters ---------- T : float Temperature of fluid [K] Tb : float Boiling temperature of fluid [K] Tc : float Critical temperature of fluid [K] Pc : float Critical pressure of fluid [Pa] Returns ------- Psat : float Vapor pressure at T [Pa] Notes ----- Units are Pa. Formulation makes intuitive sense; a logarithmic form of interpolation. Examples -------- Example as in [1]_ for ethylbenzene >>> boiling_critical_relation(347.2, 409.3, 617.1, 36E5) 15209.467273093938 References ---------- .. [1] Reid, Robert C..; Prausnitz, John M.;; Poling, Bruce E. The Properties of Gases and Liquids. McGraw-Hill Companies, 1987. ''' Tbr = Tb / Tc Tr = T / Tc h = Tbr * log(Pc / 101325.) / (1 - Tbr) return exp(h * (1 - 1 / Tr)) * Pc
def Henry_pressure(T, A, B=0.0, C=0.0, D=0.0, E=0.0, F=0.0): r'''Calculates Henry's law constant as a function of temperature according to the SI units of `Pa` and using a common temperature dependence as used in many process simulation applications. Only the `A` parameter is required - which has no temperature dependence when used by itself. As the model is exponential, a sufficiently high temperature may cause an OverflowError. A negative temperature (or just low, if fit poorly) may cause a math domain error. .. math:: H_{12} = \exp\left(A_{12} + \frac{B_{12}}{T} + C_{12}\ln(T) + D_{12}T + \frac{E_{12}}{T^2} \right) Parameters ---------- T : float Temperature, [K] A-F : float Parameter for the equation; chemical and property specific [-] Returns ------- H12 : float Henry's constant [Pa] Notes ----- Add 11.51292 to the `A` constant if it is said to provide units of `bar`, so that it provides units of `Pa` instead. The `F` parameter is not often included in models. It is rare to fit all parameters. Examples -------- Random test example. >>> Henry_pressure(300.0, A=15.0, B=300.0, C=.04, D=1e-3, E=1e2, F=1e-5) 37105004.47898146 References ---------- .. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation. Weinheim, Germany: Wiley-VCH, 2012. ''' T_inv = 1.0/T return exp(A + T_inv*(B + E*T_inv) + C*log(T) + T*(D + F*T))
def dgammas_dT(self): r'''Calculate and return the temperature derivatives of activity coefficients of a liquid phase using an activity coefficient model. .. math:: \frac{\partial \gamma_i}{\partial T} = \left(\frac{\frac{\partial^2 n G^E}{\partial T \partial n_i}}{RT} - \frac{{\frac{\partial n_i G^E}{\partial n_i }}}{RT^2}\right) \exp\left(\frac{\frac{\partial n_i G^E}{\partial n_i }}{RT}\right) Returns ------- dgammas_dT : list[float] Temperature derivatives of activity coefficients, [1/K] Notes ----- ''' r''' from sympy import * R, T = symbols('R, T') f = symbols('f', cls=Function) diff(exp(f(T)/(R*T)), T) ''' try: return self._dgammas_dT except AttributeError: pass d2nGE_dTdns = self.d2nGE_dTdns() dG_dxs = self.dGE_dxs() GE = self.GE() dG_dns = dxs_to_dn_partials(dG_dxs, self.xs, GE) T_inv = 1.0/self.T RT_inv = R_inv*T_inv self._dgammas_dT = dgammas_dT = [] for i in self.cmps: x1 = dG_dns[i]*T_inv dgammas_dT.append(RT_inv*(d2nGE_dTdns[i] - x1)*exp(dG_dns[i]*RT_inv)) return dgammas_dT
def EQ101(T, A, B, C, D, E): r'''DIPPR Equation # 101. Used in calculating vapor pressure, sublimation pressure, and liquid viscosity. All 5 parameters are required. E is often an integer. As the model is exponential, a sufficiently high temperature will cause an OverflowError. A negative temperature (or just low, if fit poorly) may cause a math domain error. .. math:: Y = \exp\left(A + \frac{B}{T} + C\cdot \ln T + D \cdot T^E\right) Parameters ---------- T : float Temperature, [K] A-E : float Parameter for the equation; chemical and property specific [-] Returns ------- Y : float Property [constant-specific] Notes ----- This function is not integrable for either dT or Y/T dT. Examples -------- Water vapor pressure; DIPPR coefficients normally listed in Pa. >>> EQ101(300, 73.649, -7258.2, -7.3037, 4.1653E-6, 2) 3537.44834545549 References ---------- .. [1] Design Institute for Physical Properties, 1996. DIPPR Project 801 DIPPR/AIChE ''' return exp(A + B / T + C * log(T) + D * T**E)
def interaction_exp(T, N, A, B, C, D, E, F, lambdas=None): if lambdas is None: lambdas = [[0.0] * N for i in range(N)] # numba: delete # lambdas = zeros((N, N)) # numba: uncomment # # 87% of the time of this routine is the exponential. T2 = T * T Tinv = 1.0 / T T2inv = Tinv * Tinv logT = log(T) for i in range(N): Ai = A[i] Bi = B[i] Ci = C[i] Di = D[i] Ei = E[i] Fi = F[i] lambdais = lambdas[i] # Might be more efficient to pass over this matrix later, # and compute all the exps # Spoiler: it was not. # Also - it was tested the impact of using fewer terms # there was very little, to no impact from that # the exp is the huge time sink. for j in range(N): lambdais[j] = exp(Ai[j] + Bi[j] * Tinv + Ci[j] * logT + Di[j] * T + Ei[j] * T2inv + Fi[j] * T2) # lambdas[i][j] = exp(A[i][j] + B[i][j]*Tinv # + C[i][j]*logT + D[i][j]*T # + E[i][j]*T2inv + F[i][j]*T2) # 135 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) # without out specified numba # 129 µs ± 2.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) # with out specified numba # 118 µs ± 2.67 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) # without out specified numba 1 term # 115 µs ± 1.77 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) # with out specified numba 1 term return lambdas
def calculate(self, T, method): r'''Method to calculate sublimation pressure of a fluid at temperature `T` with a given method. This method has no exception handling; see :obj:`T_dependent_property <thermo.utils.TDependentProperty.T_dependent_property>` for that. Parameters ---------- T : float Temperature at calculate sublimation pressure, [K] method : str Name of the method to use Returns ------- Psub : float Sublimation pressure at T, [pa] ''' if method == BESTFIT: if T < self.poly_fit_Tmin: Psub = (T - self.poly_fit_Tmin ) * self.poly_fit_Tmin_slope + self.poly_fit_Tmin_value elif T > self.poly_fit_Tmax: Psub = (T - self.poly_fit_Tmax ) * self.poly_fit_Tmax_slope + self.poly_fit_Tmax_value else: Psub = horner(self.poly_fit_coeffs, T) Psub = exp(Psub) elif method == PSUB_CLAPEYRON: Psub = max( Psub_Clapeyron(T, Tt=self.Tt, Pt=self.Pt, Hsub_t=self.Hsub_t), 1e-200) elif method in self.tabular_data: Psub = self.interpolate(T, method) return Psub
def Edalat(T, Tc, Pc, omega): r'''Calculates vapor pressure of a fluid at arbitrary temperatures using a CSP relationship by [1]_. Requires a chemical's critical temperature, pressure, and acentric factor. Claimed to have a higher accuracy than the Lee-Kesler CSP relationship. The vapor pressure of a chemical at `T` is given by: .. math:: \ln(P^{sat}/P_c) = \frac{a\tau + b\tau^{1.5} + c\tau^3 + d\tau^6} {1-\tau} .. math:: a = -6.1559 - 4.0855\omega .. math:: b = 1.5737 - 1.0540\omega - 4.4365\times 10^{-3} d .. math:: c = -0.8747 - 7.8874\omega .. math:: d = \frac{1}{-0.4893 - 0.9912\omega + 3.1551\omega^2} .. math:: \tau = 1 - \frac{T}{T_c} Parameters ---------- T : float Temperature of fluid [K] Tc : float Critical temperature of fluid [K] Pc : float Critical pressure of fluid [Pa] omega : float Acentric factor [-] Returns ------- Psat : float Vapor pressure, [Pa] Notes ----- [1]_ found an average error of 6.06% on 94 compounds and 1106 data points. Examples -------- >>> Edalat(347.2, 617.1, 36E5, 0.299) 13461.273080743307 References ---------- .. [1] Edalat, M., R. B. Bozar-Jomehri, and G. A. Mansoori. "Generalized Equation Predicts Vapor Pressure of Hydrocarbons." Oil and Gas Journal; 91:5 (February 1, 1993). ''' tau = 1. - T / Tc a = -6.1559 - 4.0855 * omega c = -0.8747 - 7.8874 * omega d = 1. / (-0.4893 - 0.9912 * omega + 3.1551 * omega * omega) b = 1.5737 - 1.0540 * omega - 4.4365E-3 * d tau_15 = tau**1.5 tau3 = tau_15 * tau_15 lnPr = (a * tau + b * tau_15 + c * tau3 + d * tau3 * tau3) / (1. - tau) return exp(lnPr) * Pc
def Sanjari(T, Tc, Pc, omega): r'''Calculates vapor pressure of a fluid at arbitrary temperatures using a CSP relationship by [1]_. Requires a chemical's critical temperature, pressure, and acentric factor. Although developed for refrigerants, this model should have some general predictive ability. The vapor pressure of a chemical at `T` is given by: .. math:: P^{sat} = P_c\exp(f^{(0)} + \omega f^{(1)} + \omega^2 f^{(2)}) .. math:: f^{(0)} = a_1 + \frac{a_2}{T_r} + a_3\ln T_r + a_4 T_r^{1.9} .. math:: f^{(1)} = a_5 + \frac{a_6}{T_r} + a_7\ln T_r + a_8 T_r^{1.9} .. math:: f^{(2)} = a_9 + \frac{a_{10}}{T_r} + a_{11}\ln T_r + a_{12} T_r^{1.9} Parameters ---------- T : float Temperature of fluid [K] Tc : float Critical temperature of fluid [K] Pc : float Critical pressure of fluid [Pa] omega : float Acentric factor [-] Returns ------- Psat : float Vapor pressure, [Pa] Notes ----- a[1-12] are as follows: 6.83377, -5.76051, 0.90654, -1.16906, 5.32034, -28.1460, -58.0352, 23.57466, 18.19967, 16.33839, 65.6995, -35.9739. For a claimed fluid not included in the regression, R128, the claimed AARD was 0.428%. A re-calculation using 200 data points from 125.45 K to 343.90225 K evenly spaced by 1.09775 K as generated by NIST Webbook April 2016 produced an AARD of 0.644%. It is likely that the author's regression used more precision in its coefficients than was shown here. Nevertheless, the function is reproduced as shown in [1]_. For Tc=808 K, Pc=1100000 Pa, omega=1.1571, this function actually declines after 770 K. Examples -------- >>> Sanjari(347.2, 617.1, 36E5, 0.299) 13651.916109552523 References ---------- .. [1] Sanjari, Ehsan, Mehrdad Honarmand, Hamidreza Badihi, and Ali Ghaheri. "An Accurate Generalized Model for Predict Vapor Pressure of Refrigerants." International Journal of Refrigeration 36, no. 4 (June 2013): 1327-32. doi:10.1016/j.ijrefrig.2013.01.007. ''' Tr = T / Tc Tr_inv = 1.0 / Tr log_Tr = log(Tr) Tr_19 = Tr**1.9 f0 = 6.83377 + -5.76051 * Tr_inv + 0.90654 * log_Tr + -1.16906 * Tr_19 f1 = 5.32034 + -28.1460 * Tr_inv + -58.0352 * log_Tr + 23.57466 * Tr_19 f2 = 18.19967 + 16.33839 * Tr_inv + 65.6995 * log_Tr + -35.9739 * Tr_19 return Pc * exp(f0 + omega * f1 + omega * omega * f2)
def Ambrose_Walton(T, Tc, Pc, omega): r'''Calculates vapor pressure of a fluid at arbitrary temperatures using a CSP relationship by [1]_; requires a chemical's critical temperature and acentric factor. The vapor pressure is given by: .. math:: \ln P_r=f^{(0)}+\omega f^{(1)}+\omega^2f^{(2)} .. math:: f^{(0)}=\frac{-5.97616\tau + 1.29874\tau^{1.5}- 0.60394\tau^{2.5} -1.06841\tau^5}{T_r} .. math:: f^{(1)}=\frac{-5.03365\tau + 1.11505\tau^{1.5}- 5.41217\tau^{2.5} -7.46628\tau^5}{T_r} .. math:: f^{(2)}=\frac{-0.64771\tau + 2.41539\tau^{1.5}- 4.26979\tau^{2.5} +3.25259\tau^5}{T_r} .. math:: \tau = 1-T_{r} Parameters ---------- T : float Temperature of fluid [K] Tc : float Critical temperature of fluid [K] Pc : float Critical pressure of fluid [Pa] omega : float Acentric factor [-] Returns ------- Psat : float Vapor pressure at T [Pa] Notes ----- Somewhat more accurate than the :obj:`Lee_Kesler` formulation. Examples -------- Example from [2]_; ethylbenzene at 347.25 K. >>> Ambrose_Walton(347.25, 617.15, 36.09E5, 0.304) 13278.878504306222 References ---------- .. [1] Ambrose, D., and J. Walton. "Vapour Pressures up to Their Critical Temperatures of Normal Alkanes and 1-Alkanols." Pure and Applied Chemistry 61, no. 8 (1989): 1395-1403. doi:10.1351/pac198961081395. .. [2] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' Tr = T / Tc tau = 1.0 - Tr tau15 = tau**1.5 tau25 = tau * tau15 tau5 = tau25 * tau25 f0 = (-5.97616 * tau + 1.29874 * tau15 - 0.60394 * tau25 - 1.06841 * tau5) f1 = (-5.03365 * tau + 1.11505 * tau15 - 5.41217 * tau25 - 7.46628 * tau5) f2 = (-0.64771 * tau + 2.41539 * tau15 - 4.26979 * tau25 + 3.25259 * tau5) return Pc * exp((f0 + omega * (f1 + f2 * omega)) / Tr)
def mu(self): try: return self._mu except AttributeError: pass phase_fractions = self.phase_fractions phase_count = len(phase_fractions) result = self.result if phase_count == 1: self._mu = mu = self.phases[0].mu() return mu elif self.state == 'l' or self.result.gas is None: # Multiple liquids - either a bulk liquid, or a result with no gases method = self.settings.mu_LL if method == AS_ONE_LIQUID: mu = self.correlations.ViscosityLiquidMixture.mixture_property( self.T, self.P, self.zs, self.ws()) else: mus = [i.mu() for i in self.phases] if method in mole_methods: betas = self.phase_fractions elif method in mass_methods: betas = self.betas_mass elif method in volume_methods: betas = self.betas_volume mu = 0.0 if method in linear_methods: for i in range(len(self.phase_fractions)): mu += betas[i] * mus[i] elif method in prop_power_methods: exponent = self.settings.mu_LL_power_exponent for i in range(len(self.phase_fractions)): mu += betas[i] * mus[i]**exponent mu = mu**(1.0 / exponent) elif method in log_prop_methods: for i in range(len(self.phase_fractions)): mu += betas[i] * log(mus[i]) mu = exp(mu) self._mu = mu return mu method = self.settings.mu_VL if method == AS_ONE_LIQUID: self._mu = mu = self.correlations.ViscosityLiquidMixture.mixture_property( self.T, self.P, self.zs, self.ws()) return mu elif method == AS_ONE_GAS: self._mu = mu = self.correlations.ViscosityGasMixture.mixture_property( self.T, self.P, self.zs, self.ws()) return mu mug = result.gas.mu() if phase_count == 2: mul = result.liquids[0].mu() else: mul = result.liquid_bulk.mu() if method in MU_VL_CORRELATIONS_SET: x = result.betas_mass[0] rhog = result.gas.rho_mass() if phase_count == 2: rhol = result.liquids[0].rho_mass() else: rhol = result.liquid_bulk.rho_mass() mu = gas_liquid_viscosity(x, mul, mug, rhol, rhog, Method=method) else: mus = [mug, mul] if method in mole_methods: VF = self.result.beta_gas betas = [VF, 1.0 - VF] elif method in mass_methods: betas = self.betas_mass_states[:2] elif method in volume_methods: betas = self.betas_volume_states[:2] if method in linear_methods: mu = betas[0] * mus[0] + betas[1] * mus[1] elif method in prop_power_methods: exponent = self.settings.mu_LL_power_exponent mu = (betas[0] * mus[0]**exponent + betas[1] * mus[1]**exponent)**(1.0 / exponent) elif method in log_prop_methods: mu = exp(betas[0] * log(mus[0]) + betas[1] * log(mus[1])) self._mu = mu return mu
def calculate(self, T, method): r'''Method to calculate vapor pressure of a fluid at temperature `T` with a given method. This method has no exception handling; see :obj:`thermo.utils.TDependentProperty.T_dependent_property` for that. Parameters ---------- T : float Temperature at calculate vapor pressure, [K] method : str Name of the method to use Returns ------- Psat : float Vapor pressure at T, [pa] ''' if method == BESTFIT: if T < self.poly_fit_Tmin: Psat = (T - self.poly_fit_Tmin ) * self.poly_fit_Tmin_slope + self.poly_fit_Tmin_value elif T > self.poly_fit_Tmax: Psat = (T - self.poly_fit_Tmax ) * self.poly_fit_Tmax_slope + self.poly_fit_Tmax_value else: Psat = horner(self.poly_fit_coeffs, T) Psat = exp(Psat) elif method == BEST_FIT_AB: if T < self.poly_fit_Tmax: return self.calculate(T, BESTFIT) A, B = self.poly_fit_AB_high_ABC_compat return exp(A + B / T) elif method == BEST_FIT_ABC: if T < self.poly_fit_Tmax: return self.calculate(T, BESTFIT) A, B, C = self.DIPPR101_ABC_high return exp(A + B / T + C * log(T)) elif method == WAGNER_MCGARRY: Psat = Wagner_original(T, self.WAGNER_MCGARRY_Tc, self.WAGNER_MCGARRY_Pc, *self.WAGNER_MCGARRY_coefs) elif method == WAGNER_POLING: Psat = Wagner(T, self.WAGNER_POLING_Tc, self.WAGNER_POLING_Pc, *self.WAGNER_POLING_coefs) elif method == ANTOINE_EXTENDED_POLING: Psat = TRC_Antoine_extended(T, *self.ANTOINE_EXTENDED_POLING_coefs) elif method == ANTOINE_POLING: A, B, C = self.ANTOINE_POLING_coefs Psat = Antoine(T, A, B, C, base=10.0) elif method == DIPPR_PERRY_8E: Psat = EQ101(T, *self.Perrys2_8_coeffs) elif method == VDI_PPDS: Psat = Wagner(T, self.VDI_PPDS_Tc, self.VDI_PPDS_Pc, *self.VDI_PPDS_coeffs) elif method == COOLPROP: Psat = PropsSI('P', 'T', T, 'Q', 0, self.CASRN) elif method == BOILING_CRITICAL: Psat = boiling_critical_relation(T, self.Tb, self.Tc, self.Pc) elif method == LEE_KESLER_PSAT: Psat = Lee_Kesler(T, self.Tc, self.Pc, self.omega) elif method == AMBROSE_WALTON: Psat = Ambrose_Walton(T, self.Tc, self.Pc, self.omega) elif method == SANJARI: Psat = Sanjari(T, self.Tc, self.Pc, self.omega) elif method == EDALAT: Psat = Edalat(T, self.Tc, self.Pc, self.omega) elif method == EOS: Psat = self.eos[0].Psat(T) elif method == BESTFIT: Psat = exp(horner(self.poly_fit_coeffs, T)) else: return self._base_calculate(T, method) return Psat
def collision_integral_Neufeld_Janzen_Aziz(T_star, l=1, s=1): r'''Calculates Lennard-Jones collision integral for any of 16 values of (l,j) for the wide range of 0.3 < T_star < 100. Values are accurate to 0.1 % of actual values, but the calculation of actual values is computationally intensive and so these simplifications are used, developed in [1]_. .. math:: \Omega_D = \frac{A}{T^{*B}} + \frac{C}{\exp(DT^*)} + \frac{E}{\exp(FT^{*})} + \frac{G}{\exp(HT^*)} + RT^{*B}\sin(ST^{*W}-P) Parameters ---------- Tstar : float Reduced temperature of the fluid [-] l : int term s : int term Returns ------- Omega : float Collision integral of A and B Notes ----- Acceptable pairs of (l,s) are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), and (4, 4). .. math:: T^* = \frac{k_b T}{\epsilon} Results are very similar to those of the more modern formulation, `collision_integral_Kim_Monroe`. Calculations begin to yield overflow errors in some values of (l, 2) after T_star = 75, beginning with (1, 7). Also susceptible are (1, 5) and (1, 6). Examples -------- >>> collision_integral_Neufeld_Janzen_Aziz(100, 1, 1) 0.516717697672334 References ---------- .. [1] Neufeld, Philip D., A. R. Janzen, and R. A. Aziz. "Empirical Equations to Calculate 16 of the Transport Collision Integrals Omega(l, S)* for the Lennard-Jones (12-6) Potential." The Journal of Chemical Physics 57, no. 3 (August 1, 1972): 1100-1102. doi:10.1063/1.1678363 ''' if l == 1 and s == 1: A, B, C, D, E, F, G, H = 1.06036, 0.1561, 0.193, 0.47635, 1.03587, 1.52996, 1.76474, 3.89411 elif l == 1 and s == 2: A, B, C, D, E, F, G, H = 1.0022, 0.1553, 0.16105, 0.72751, 0.86125, 2.06848, 1.95162, 4.84492 elif l == 1 and s == 3: A, B, C, D, E, F, R, S, W, P = 0.96573, 0.15611, 0.44067, 1.5242, 2.38981, 5.08063, -0.0005373, 19.2866, -1.30775, 6.58711 elif l == 1 and s == 4: A, B, C, D, E, F, R, S, W, P = 0.93447, 0.15578, 0.39478, 1.85761, 2.45988, 6.15727, 0.0004246, 12.988, -1.36399, 3.3329 elif l == 1 and s == 5: A, B, C, D, E, F, R, S, W, P = 0.90972, 0.15565, 0.35967, 2.18528, 2.45169, 7.17936, -0.0003814, 9.38191, 0.14025, 9.93802 elif l == 1 and s == 6: A, B, C, D, E, F, R, S, W, P = 0.88928, 0.15562, 0.33305, 2.51303, 2.36298, 8.1169, -0.0004649, 9.86928, 0.12851, 9.82414 elif l == 1 and s == 7: A, B, C, D, E, F, R, S, W, P = 0.87208, 0.15568, 0.36583, 3.01399, 2.70659, 9.9231, -0.0004902, 10.2274, 0.12306, 9.97712 elif l == 2 and s == 2: A, B, C, D, E, F, R, S, W, P = 1.16145, 0.14874, 0.52487, 0.7732, 2.16178, 2.43787, -0.0006435, 18.0323, -0.7683, 7.27371 elif l == 2 and s == 3: A, B, C, D, E, F, R, S, W, P = 1.11521, 0.14796, 0.44844, 0.99548, 2.30009, 3.06031, 0.0004565, 38.5868, -0.69403, 2.56375 elif l == 2 and s == 4: A, B, C, D, E, F, R, S, W, P = 1.08228, 0.14807, 0.47128, 1.31596, 2.42738, 3.90018, -0.0005623, 3.08449, 0.28271, 3.22871 elif l == 2 and s == 5: A, B, C, D, E, F, R, S, W, P = 1.05581, 0.14822, 0.51203, 1.67007, 2.57317, 4.85939, -0.000712, 4.7121, 0.2173, 4.7353 elif l == 2 and s == 6: A, B, C, D, E, F, R, S, W, P = 1.03358, 0.14834, 0.53928, 2.01942, 2.7235, 5.84817, -0.0008576, 7.66012, 0.15493, 7.6011 elif l == 3 and s == 3: A, B, C, D, E, F, G, H, R, S, W, P = 1.05567, 0.1498, 0.30887, 0.86437, 1.35766, 2.44123, 1.2903, 5.55734, 0.0002339, 57.7757, -1.0898, 6.9475 elif l == 3 and s == 4: A, B, C, D, E, F, R, S, W, P = 1.02621, 0.1505, 0.55381, 1.4007, 2.06176, 4.26234, 0.0005227, 11.3331, -0.8209, 3.87185 elif l == 3 and s == 5: A, B, C, D, E, F, R, S, W, P = 0.99958, 0.15029, 0.50441, 1.64304, 2.06947, 4.87712, -0.0005184, 3.45031, 0.26821, 3.73348 elif l == 4 and s == 4: A, B, C, D, E, F, R, S, W, P = 1.12007, 0.14578, 0.53347, 1.11986, 2.28803, 3.27567, 0.0007427, 21.048, -0.28759, 6.69149 else: raise ValueError('Input values of l and s are not supported') omega = A / T_star**B + C / exp(D * T_star) + E / exp(F * T_star) if (l == 1 and (s == 1 or s == 2)) or (s == 3 and l == 3): omega += G / exp(H * T_star) if not (l == 1 and (s == 1 or s == 2)): omega += R * T_star**B * sin(S * T_star**W - P) return omega
def Antoine_coeffs_from_point(T, Psat, dPsat_dT, d2Psat_dT2, base=10.0): r'''Calculates the antoine coefficients `A`, `B`, and `C` from a known vapor pressure and its first and second temperature derivative. Parameters ---------- T : float Temperature of fluid, [K] Psat : float Vapor pressure at specified `T` [Pa] dPsat_dT : float First temperature derivative of vapor pressure at specified `T` [Pa/K] d2Psat_dT2 : float Second temperature derivative of vapor pressure at specified `T` [Pa/K^2] Base : float, optional Base of logarithm; 10 by default Returns ------- A : float Antoine `A` parameter, [-] B : float Antoine `B` parameter, [K] C : float Antoine `C` parameter, [K] Notes ----- Coefficients are for calculating vapor pressure in Pascal. This is primarily useful for interconverting vapor pressure models, not fitting experimental data. Derived with SymPy as follows: >>> from sympy import * # doctest: +SKIP >>> base, A, B, C, T = symbols('base, A, B, C, T') # doctest: +SKIP >>> v = base**(A - B/(T + C)) # doctest: +SKIP >>> d1, d2 = diff(v, T), diff(v, T, 2) # doctest: +SKIP >>> vk, d1k, d2k = symbols('vk, d1k, d2k') # doctest: +SKIP >>> solve([Eq(v, vk), Eq(d1, d1k), Eq(d2, d2k)], [A, B, C]) # doctest: +SKIP Examples -------- Recalculate some coefficients from a calcualted value and its derivative: >>> T = 178.01 >>> A, B, C = (24.0989474955895, 4346.793091137991, -18.96968471040141) >>> Psat = Antoine(T, A, B, C, base=exp(1)) >>> dPsat_dT, d2Psat_dT2 = (0.006781441203850251, 0.0010801244983894853) # precomputed >>> Antoine_coeffs_from_point(T, Psat, dPsat_dT, d2Psat_dT2, base=exp(1)) (24.098947495155453, 4346.793090994682, -18.969684713118813) References ---------- .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' A = log(Psat * exp(2 * dPsat_dT**2 / (dPsat_dT**2 - d2Psat_dT2 * Psat))) / log(base) B = 4 * dPsat_dT**3 * Psat / ( (dPsat_dT**4 - 2 * dPsat_dT**2 * d2Psat_dT2 * Psat + d2Psat_dT2**2 * Psat**2) * log(base)) C = (-T * dPsat_dT**2 + T * d2Psat_dT2 * Psat + 2 * dPsat_dT * Psat) / (dPsat_dT**2 - d2Psat_dT2 * Psat) return (A, B, C)