def speed_of_sound(self, p=None, T=None): """NOT IMPLEMENTED""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: pi = self.p / Pressure(16.53).unit('MPa') tau = Temperature(1386) / self.T inside_frac = (((self._basic_equation1('gamma_pi') - tau * self._basic_equation1('gamma_tau_pi'))**2) / ((tau**2) * self._basic_equation1('gamma_tau_tau'))) return sqrt( ((self._basic_equation1('gamma_pi')**2) / (inside_frac - self._basic_equation1('gamma_pi_pi'))) * self.R * self.T * 1000) elif self._is_in_region() == 2: pass elif self._is_in_region() == 3: pass elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass return -1
def heat_capacity_constant_v(self, p=None, T=None): """NOT IMPLEMENTED""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: pi = self.p / Pressure(16.53).unit('MPa') tau = Temperature(1386) / self.T return (-(tau**2) * self._basic_equation1('gamma_tau_tau') + ((self._basic_equation1('gamma_pi') - tau * self._basic_equation1('gamma_pi_tau'))**2) / self._basic_equation1('gamma_pi_pi')) * self.R elif self._is_in_region() == 2: pass elif self._is_in_region() == 3: pass elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass return -1
def entropy(self, p=None, T=None): """NOT IMPLEMENTED""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: pi = self.p / Pressure(16.53).unit('MPa') tau = Temperature(1386) / self.T return (tau * self._basic_equation1('gamma_tau') - self._basic_equation1('gamma')) * self.R elif self._is_in_region() == 2: pi = self.p / Pressure(1).unit('MPa') tau = 540 / self.T return ((tau * (self._basic_equation2('gamma_0_tau') + self._basic_equation2('gamma_r_tau')) - (self._basic_equation2('gamma_0') + self._basic_equation2('gamma_r'))) * self.R) elif self._is_in_region() == 3: pass elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass return -1
def test_units(): """Test units.""" Tkel = Temperature(273.15).unit('K') Tcel = Temperature(0).unit('C') assert Tkel == Tcel pressuremmhg = Pressure(760).unit('torr') pressureatm = Pressure(1).unit('atm') assert pressuremmhg == pressureatm
def temperature_saturation(self, p=None): """Yields Tsat given a pressure p.""" # module deals with pressure in MPa if p is None: p = self.p.MPa else: p = Pressure(p).MPa if p < Pressure(611.213).unit('Pa').MPa or p > self.pc: raise ValueError('Pressure out of range.') # table 34 ni = array([ 1167.0521452767, -724213.16703206, -17.073846940092, 12020.82470247, -3232555.0322333, 14.91510861353, -4823.2657361591, 405113.40542057, -0.23855557567849, 650.17534844798 ], dtype='d') beta = p**0.25 E = 1 * beta**2 + ni[2] * beta + ni[5] F = ni[0] * beta**2 + ni[3] * beta + ni[6] G = ni[1] * beta**2 + ni[4] * beta + ni[7] D = 2 * G / (-F - (F**2 - 4 * E * G)**0.5) return Temperature((ni[9] + D - ((ni[9] + D)**2 - 4 * (ni[8] + ni[9] * D))**0.5) * 0.5)
def heat_capacity(self, p=None, T=None): """Returns the isobaric heat capacity given p and T in kJ/(kg K).""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: tau = 1386 / T return (-1 * tau * tau * self.R * self._basic_equation1('gamma_tau_tau')) elif self._is_in_region() == 2: pass elif self._is_in_region() == 3: delta = rho / self.rhoc tau = self.Tc / self.T return ( -tau**2 / self._basic_equation3('PHI_tau_tau') + (delta * self._basic_equation3('PHI_delta') - delta * tau * self._basic_equation3('PHI_tau_delta'))**2 / (2 * delta * self._basic_equation3('PHI_delta') + delta**2 * self._basic_equation3('PHI_delta_delta'))) * self.R elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass return -1
def specific_volume(self, p=None, T=None): """Returns the specific volume in m³/kg""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: pi = self.p / Pressure(16.53).unit('MPa') return (self._basic_equation1('gamma_pi') * self.R * self.T * pi / self.p * 1e3) # because of kJ in R elif self._is_in_region() == 2: pi = self.p / Pressure(1).unit('MPa') return (pi * (self._basic_equation2('gamma_0_pi') + self._basic_equation2('gamma_r_pi')) * self.R * self.T / self.p * 1e3) elif self._is_in_region() == 3: return None elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass return -1
def __init__(self, p, T, massic_basis=False): u"""Initializes a Water object.""" self.p = Pressure(p) self.T = Temperature(T) # check if water is specified by IAPWS-IF97 for these values if self.T < Temperature(273.15) or self.T > Temperature(2273.15): raise ValueError('Temperature ' + str(T) + ' out of range (273.15 - 2273.15K)') if self.p > Pressure(100).unit('MPa') or self.p < 0: raise ValueError('Pressure ' + str(p) + ' out of range (0 - 100 MPa)') if self.T > 1073.15 and self.p > Pressure(50).unit('MPa'): raise ValueError('p or T value out of range') # adjust R to mass or molar basis if massic_basis is True: self.R = ideal_gas_constant_massic_basis[0] # kJ/(kg K); elif massic_basis is False: self.R = ideal_gas_constant[0]
def _is_in_region(self): """Finds a region for the (T, p) point (see IAPWS-IF97 for details). The usefulness of these regions are to divide the physical properties of water into different sets of coefficients and equations.""" # for the 2 - 3 boundary line ni = array([ 348.05185628969, -1.1671859879975, 0.0010192970039326, 572.54459862746, 13.91883977887 ], dtype='d') theta = self.T pressure23 = Pressure(ni[0] + ni[1] * theta + ni[2] * theta**2).unit('MPa') # exceptional cases if self.T == self.Tt and self.p == self.pt: return 1 # regular cases if self.T >= Temperature(273.15) and self.T <= Temperature(623.15): if self.T < self.temperature_saturation(self.p): return 1 else: return 2 elif self.T > Temperature(623.15) and self.T <= Temperature(1073.15): if self.p > pressure23: return 3 else: return 2 elif self.T >= Temperature(1073.15) and self.T <= Temperature(2273.15): return 5 else: raise Exception('Cannot assign region to the parameters p = ' + str(self.p) + 'T = ' + str(self.T) + 'given.')
def _basic_equation1(self, value='gamma'): """Returns basic equation 1 and its derivatives, ex: 'gamma', 'gamma_tau', 'gamma_tau_pi', etc.""" # region1 Ii = array([ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32 ], dtype='int') Ji = array([ -2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4, 0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41 ], dtype='int') ni = array([ 0.14632971213167, -0.84548187169114, -3.756360367204, 3.3855169168385, -0.95791963387872, 0.15772038513228, -0.016616417199501, 0.00081214629983568, 0.00028319080123804, -0.00060706301565874, -0.018990068218419, -0.032529748770505, -0.021841717175414, -5.283835796993e-05, -0.00047184321073267, -0.00030001780793026, 4.7661393906987e-05, -4.4141845330846e-06, -7.2694996297594e-16, -3.1679644845054e-05, -2.8270797985312e-06, -8.5205128120103e-10, -2.2425281908e-06, -6.5171222895601e-07, -1.4341729937924e-13, -4.0516996860117e-07, -1.2734301741641e-09, -1.7424871230634e-10, -6.8762131295531e-19, 1.4478307828521e-20, 2.6335781662795e-23, -1.1947622640071e-23, 1.8228094581404e-24, -9.3537087292458e-26 ], dtype='d') pi = self.p / Pressure(16.53).unit('MPa') tau = Temperature(1386) / self.T if value == 'gamma': return sum(ni * ((7.1 - pi)**Ii) * ((tau - 1.222)**Ji)) elif value == 'gamma_tau': return sum(ni * ((7.1 - pi)**Ii) * Ji * ((tau - 1.222)**(Ji - 1))) elif value == 'gamma_tau_tau': return sum(ni * ((7.1 - pi)**Ii) * Ji * (Ji - 1) * ((tau - 1.222)**(Ji - 2))) elif value == 'gamma_pi': return -1 * sum(ni * Ii * ((7.1 - pi)**(Ii - 1)) * (tau - 1.222)**Ji) elif value == 'gamma_pi_pi': return sum(ni * Ii * (Ii - 1) * (7.1 - pi)**(Ii - 2) * (tau - 1.222)**Ji) elif value == 'gamma_pi_tau' or value == 'gamma_tau_pi': return -1 * sum(ni * Ii * (7.1 - pi)**(Ii - 1) * Ji * (tau - 1.222)**(Ji - 1)) else: raise Exception('Function not assigned in _basic_equation1()')
def enthalpy(self, p=None, T=None): """Returns the enthalpy given p and T in kJ/kg.""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: return Enthalpy(self._basic_equation1('gamma_tau') * 1386 * self.R) elif self._is_in_region() == 2: return Enthalpy(540 * self.R * (self._basic_equation2('gamma_0_tau') + self._basic_equation2('gamma_r_tau'))) elif self._is_in_region() == 3: # for region 3 rho needs to be solved numerically reg3_solved = self._basic_equation3('PHI_delta') delta = reg3_solved[1] / self.rhoc tau = self.Tc / self.T return Enthalpy((tau * self._basic_equation3('PHI_tau')[0] + delta * reg3_solved[0]) * self.R * self.T) elif self._is_in_region() == 4: return None elif self._is_in_region() == 5: pi = self.p / Pressure(1).unit('MPa') tau = Temperature(1000) / self.T return (tau * (self._basic_equation5('gamma_0_tau') + self._basic_equation5('gamma_r_tau')) * self.R * self.T)
def _basic_equation5(self, value='gamma'): """Returns equation 1 and its derivatives, ex: 'gamma', 'gamma_tau', 'gamma_tau_pi', etc.""" J0 = array([0, 1, -3, -2, -1, 2], dtype='d') n0 = array([ -13.179983674201, 6.8540841634434, -0.024805148933466, 0.36901534980333, -3.1161318213925, -0.32961626538917 ], dtype='d') Ii = array([1, 1, 1, 2, 2, 3], dtype='d') Ji = array([1, 2, 3, 3, 9, 7], dtype='d') ni = array([ 0.0015736404855259, 0.00090153761673944, -0.0050270077677648, 2.2440037409485e-06, -4.1163275453471e-06, 3.7919454822955e-08 ], dtype='d') pi = self.p / Pressure(1).unit('MPa') tau = Temperature(1000) / self.T if value == 'gamma': return (self._basic_equation5('gamma_0') + self._basic_equation5('gamma_r')) elif value == 'gamma_0': return log(pi) + sum(n0 * (tau**J0)) elif value == 'gamma_r': return sum(ni * (pi**Ii) * (tau**Ji)) elif value == 'gamma_0_pi': return 1 / pi elif value == 'gamma_0_pi_pi': return -1 / (pi**2) elif value == 'gamma_0_tau': return sum(n0 * J0 * (tau**(J0 - 1))) elif value == 'gamma_0_tau_tau': sum(n0 * J0 * (J0 - 1) * (tau**(J0 - 2))) elif value == 'gamma_0_tau_pi' or value == 'gamma_0_pi_tau': return 0 + 0 elif value == 'gamma_r_pi': return sum(ni * Ii * (pi**(Ii - 1)) * (tau**Ji)) elif value == 'gamma_r_tau': return sum(ni * (pi**Ii) * Ji * (tau**(Ji - 1))) elif value == 'gamma_r_pi_pi': return sum(ni * Ii * (Ii - 1) * (pi**(Ii - 2)) * (tau**Ji)) elif value == 'gamma_r_tau_tau': return sum(ni * (pi**Ii) * Ji * (Ji - 1) * (tau**(Ji - 2))) elif value == 'gamma_r_tau_pi' or 'gamma_r_pi_tau': return sum(ni * Ii * (pi**(Ii - 1)) * Ji * (tau**(Ji - 1)))
def gibbs_energy(self, p=None, T=None): """Returns the Gibbs Energy given p and T in kJ/kg.""" if p is None: p = self.p else: p = Pressure(p) if T is None: T = self.T else: T = Temperature(T) if self._is_in_region() == 1: return self._basic_equation1('gamma') * self.R * T elif self._is_in_region() == 2: return self._basic_equation2('gamma') * self.R * T elif self._is_in_region() == 3: pass elif self._is_in_region() == 4: pass elif self._is_in_region() == 5: pass
def pressure_saturation(self, T=None): """Yields Psat given a temperature T""" if T is None: T = self.T else: T = Temperature(T) if T < 273.15 or T > self.Tc: raise ValueError('Temperature out of range.') # table 34 ni = array([ 1167.0521452767, -724213.16703206, -17.073846940092, 12020.82470247, -3232555.0322333, 14.91510861353, -4823.2657361591, 405113.40542057, -0.23855557567849, 650.17534844798 ], dtype='d') v = T + ni[8] / (T - ni[9]) A = 1 * v**2 + ni[0] * v + ni[1] B = ni[2] * v**2 + ni[3] * v + ni[4] C = ni[5] * v**2 + ni[6] * v + ni[7] return Pressure( (2 * C / (-B + (B**2 - 4 * A * C)**0.5))**4).unit('MPa')
def test_iapws(): """ Tests are given inside the IAPWS document. See references for more details. """ #test Tsat given P assert round(Water(1e5, 373.15).temperature_saturation(0.1e6), 6) == 372.755919 assert round(Water(1e5, 373.15).temperature_saturation(1e6), 6) == 453.035632 assert round(Water(1e5, 373.15).temperature_saturation(10e6), 6) == 584.149488 #test Psat given T assert round(Water(1e5, 373.15).pressure_saturation(300).MPa, 11) == 0.00353658941 assert round(Water(1e5, 373.15).pressure_saturation(500).MPa, 8) == 2.63889776 assert round(Water(1e5, 373.15).pressure_saturation(600).MPa, 7) == 12.3443146 #test regions # arbitrary points point_in_region1 = (Pressure(20e6), Temperature(300)) point_in_region2 = (Pressure(1e5), Temperature(373.15)) point_in_region3 = (Pressure(40e6), Temperature(700)) point_in_region4 = (Pressure(1).unit('atm'), Temperature(373.1243)) point_in_region5 = (Pressure(20e6), Temperature(1500)) assert Water(*point_in_region1)._is_in_region() == 1 assert Water(*point_in_region2)._is_in_region() == 2 assert Water(*point_in_region3)._is_in_region() == 3 # region 4 does not exist as a region; it is rather the saturation line assert Water(*point_in_region5)._is_in_region() == 5 #region 1 #assert specific volume assert round(Water(3e6, 300, massic_basis=True).specific_volume(), 11) == 0.00100215168 assert round(Water(80e6, 300, massic_basis=True).specific_volume(), 12) == 0.000971180894 assert round(Water(3e6, 500, massic_basis=True).specific_volume(), 11) == 0.00120241800 # # #assert internal energy assert round(Water(3e6, 300, massic_basis=True).internal_energy(), 6) == 112.324818 assert round(Water(80e6, 300, massic_basis=True).internal_energy(), 6) == 106.448356 assert round(Water(3e6, 500, massic_basis=True).internal_energy(), 6) == 971.934985 # # #assert enthropy assert round(Water(3e6, 300, massic_basis=True).entropy(), 9) == 0.392294792 assert round(Water(80e6, 300, massic_basis=True).entropy(), 9) == 0.368563852 assert round(Water(3e6, 500, massic_basis=True).entropy(), 8) == 2.58041912 #assert enthalpy assert round(Water(3e6, 300, massic_basis=True).enthalpy(), 6) == 115.331273 assert round(Water(80e6, 300, massic_basis=True).enthalpy(), 6) == 184.142828 assert round(Water(3e6, 500, massic_basis=True).enthalpy(), 6) == 975.542239 #assert cp assert round(Water(3e6, 300, massic_basis=True).heat_capacity(), 8) == 4.17301218 assert round(Water(80e6, 300, massic_basis=True).heat_capacity(), 8) == 4.01008987 assert round(Water(3e6, 500, massic_basis=True).heat_capacity(), 8) == 4.65580682 # #assert cv # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # #assert speed of sound assert round(Water(3e6, 300, massic_basis=True).speed_of_sound(), 5) == 1507.73921 assert round(Water(80e6, 300, massic_basis=True).speed_of_sound(), 5) == 1634.69054 assert round(Water(3e6, 500, massic_basis=True).speed_of_sound(), 5) == 1240.71337 #region 2 #assert specific volume assert round(Water(3500, 300, massic_basis=True).specific_volume(), 7) == 39.4913866 assert round(Water(3500, 700, massic_basis=True).specific_volume(), 7) == 92.3015898 assert round(Water(30e6, 700, massic_basis=True).specific_volume(), 11) == 0.00542946619 # # #assert internal energy assert round(Water(3500, 300, massic_basis=True).internal_energy(), 5) == 2411.69160 assert round(Water(3500, 700, massic_basis=True).internal_energy(), 5) == 3012.62819 assert round(Water(30e6, 700, massic_basis=True).internal_energy(), 5) == 2468.61076 # # #assert enthropy assert round(Water(3500, 300, massic_basis=True).entropy(), 8) == 8.52238967 assert round(Water(3500, 700, massic_basis=True).entropy(), 7) == 10.1749996 assert round(Water(30e6, 700, massic_basis=True).entropy(), 8) == 5.17540298 #assert enthalpy assert round(Water(3500, 300, massic_basis=True).enthalpy(), 5) == 2549.91145 assert round(Water(3500, 700, massic_basis=True).enthalpy(), 5) == 3335.68375 assert round(Water(30e6, 700, massic_basis=True).enthalpy(), 5) == 2631.49474 #assert cp # assert round(Water(3e6, 300).heat_capacity(),8) == 4.17301218 # assert round(Water(80e6, 300).heat_capacity(),8) == 4.01008987 # assert round(Water(3e6, 500).heat_capacity(),8) == 4.65580682 # #assert enthalpy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # # #assert enthalpy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 #region 3 #assert specific volume # assert round(Water(3500, 300).specific_volume(),7) == 39.4913866 # assert round(Water(3500, 700).specific_volume(),7) == 92.3015898 # assert round(Water(30e6, 700).specific_volume(),11) == 0.00542946619 # # #assert internal energy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # # #assert enthropy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 #assert enthalpy assert round(Water(25.5837018e6, 650, massic_basis=True).enthalpy(), 5) == 1863.43019 assert round(Water(22.2930643e6, 650, massic_basis=True).enthalpy(), 5) == round(2375.12401, 3) assert round(Water(78.3095639e6, 750, massic_basis=True).enthalpy(), 5) == 2258.68845 #assert cp # assert round(Water(3e6, 300).heat_capacity(),8) == 4.17301218 # assert round(Water(80e6, 300).heat_capacity(),8) == 4.01008987 # assert round(Water(3e6, 500).heat_capacity(),8) == 4.65580682 # #assert enthalpy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # # #assert enthalpy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # region 4 # There is no region 4; instead region 4 is the saturation line # region 5 #assert specific volume # assert round(Water(3500, 300).specific_volume(),7) == 39.4913866 # assert round(Water(3500, 700).specific_volume(),7) == 92.3015898 # assert round(Water(30e6, 700).specific_volume(),11) == 0.00542946619 # # #assert internal energy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 # # #assert enthropy # assert round(Water(3e6, 300).enthalpy(),6) == 115.331273 # assert round(Water(80e6, 300).enthalpy(),6) == 184.142828 # assert round(Water(3e6, 500).enthalpy(),6) == 975.542239 #assert enthalpy assert round(Water(0.5e6, 1500, massic_basis=True).enthalpy(), 5) == 5219.76855 assert round(Water(30e6, 1500, massic_basis=True).enthalpy(), 5) == 5167.23514 assert round(Water(30e6, 2000, massic_basis=True).enthalpy(), 5) == 6571.22604