Source code for armi.materials.water

# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Basic water material."""
import math

from armi.materials.material import Fluid
from armi.nucDirectory import elements
from armi.nucDirectory import nuclideBases as nb
from armi.nucDirectory import thermalScattering as tsl
from armi.utils import units
from armi.utils.units import getTk

_REF_SR1_86 = (
    "IAPWS SR1-86 Revised Supplementary Release on Saturation Properties of Ordinary Water and "
    "Steam"
)


[docs]class Water(Fluid): """ Water. This is a good faith implementation of the Revised Supplementary Properties of Ordinary Water Substance (1992) by IAPWS -- International Association for the Properties of Water and Steam . This is an abstract class implemented on the Saturated Water Material Class and the Saturated Steam Material Class, which should be good enough for most uses. http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ thermalScatteringLaws = (tsl.byNbAndCompound[nb.byName["H"], tsl.H2O],) references = { "vapor pressure": _REF_SR1_86, "enthalpy (saturated water)": _REF_SR1_86, "enthalpy (saturated steam)": _REF_SR1_86, "entropy (saturated water)": _REF_SR1_86, "entropy (saturated steam)": _REF_SR1_86, "density (saturated water)": _REF_SR1_86, "density (saturated steam)": _REF_SR1_86, } TEMPERATURE_CRITICAL_K = 647.096 DENSITY_CRITICAL_KGPERCUBICMETER = 322.0 DENSITY_CRITICAL_GPERCUBICCENTIMETER = ( DENSITY_CRITICAL_KGPERCUBICMETER * units.G_PER_KG / units.CM3_PER_M3 ) VAPOR_PRESSURE_CRITICAL_MPA = 22.064 VAPOR_PRESSURE_CRITICAL_PA = VAPOR_PRESSURE_CRITICAL_MPA * 1e6 ALPHA_0 = 1000 PHI_0 = ALPHA_0 / TEMPERATURE_CRITICAL_K # coefficients for auxiliary quantity for enthalpy and entropy # kept as d to match original source d = { 1: -5.65134998e-08, 2: 2690.66631, 3: 127.287297, 4: -135.003439, 5: 0.981825814, "alpha": -1135.905627715, "phi": 2319.5246, }
[docs] def setDefaultMassFracs(self) -> None: massHydrogen = elements.bySymbol["H"].standardWeight massOxygen = elements.bySymbol["O"].standardWeight totalMass = 2 * massHydrogen + massOxygen massFrac = {"H": 2.0 * massHydrogen / totalMass, "O": massOxygen / totalMass} for nucName, mfrac in massFrac.items(): self.setMassFrac(nucName, mfrac)
[docs] def theta(self, Tk: float = None, Tc: float = None) -> float: """Returns temperature normalized to the critical temperature.""" return getTk(Tc=Tc, Tk=Tk) / self.TEMPERATURE_CRITICAL_K
[docs] def tau(self, Tc: float = None, Tk: float = None) -> float: """ Returns 1 - temperature normalized to the critical temperature. Note ---- thermophysical correlations are give in Tau rather than Tk or Tc """ return 1.0 - self.theta(Tc=Tc, Tk=Tk)
[docs] def vaporPressure(self, Tk: float = None, Tc: float = None) -> float: """ Returns vapor pressure in (Pa). Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- vaporPressure: float vapor pressure in Pa Notes ----- IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ tau = self.tau(Tc=Tc, Tk=Tk) T_ratio = self.TEMPERATURE_CRITICAL_K / getTk(Tc=Tc, Tk=Tk) a1 = -7.85951783 a2 = 1.84408259 a3 = -11.7866497 a4 = 22.6807411 a5 = -15.9618719 a6 = 1.80122502 sum_coefficients = ( a1 * tau + a2 * tau**1.5 + a3 * tau**3 + a4 * tau**3.5 + a5 * tau**4 + a6 * tau**7.5 ) log_vapor_pressure = T_ratio * sum_coefficients vapor_pressure = self.VAPOR_PRESSURE_CRITICAL_PA * math.e ** ( log_vapor_pressure ) # past the supercritical point tau's raised to .5 cause complex #'s return vapor_pressure.real
[docs] def vaporPressurePrime( self, Tk: float = None, Tc: float = None, dT: float = 1e-6 ) -> float: """ Approximation of derivative of vapor pressure wrt temperature. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Note ---- This uses a numerical approximation """ Tcold = getTk(Tc=Tc, Tk=Tk) - dT / 2.0 Thot = Tcold + dT dp = self.vaporPressure(Tk=Thot) - self.vaporPressure(Tk=Tcold) return dp / dT
[docs] def auxiliaryQuantitySpecificEnthalpy( self, Tk: float = None, Tc: float = None ) -> float: """ Returns the auxiliary quantity for specific enthalpy. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- alpha: float specific quantity for enthalpy in J/kg Notes ----- IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry alpha is used in the relations for enthalpy h = alpha + T/pressure*dp/dT """ theta = self.theta(Tc=Tc, Tk=Tk) normalized_alpha = ( self.d["alpha"] + self.d[1] * theta**-19 + self.d[2] * theta + self.d[3] * theta**4.5 + self.d[4] * theta**5.0 + self.d[5] * theta**54.5 ) # past the supercritical point tau's raised to .5 cause complex #'s return normalized_alpha.real * self.ALPHA_0
[docs] def auxiliaryQuantitySpecificEntropy( self, Tk: float = None, Tc: float = None ) -> float: """ Returns the auxiliary quantity for specific entropy. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- phi: float specific quantity for entropy in J/(kgK) Notes ----- IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry alpha is used in the relations for enthalpy s = phi + 1/pressure*dp/dT """ theta = self.theta(Tc=Tc, Tk=Tk) normalized_phi = ( self.d["phi"] + 19.0 / 20.0 * self.d[1] * theta**-20.0 + self.d[2] * math.log(theta) + 9.0 / 7.0 * self.d[3] * theta**3.5 + 5.0 / 4.0 * self.d[4] * theta**4.0 + 109.0 / 107.0 * self.d[5] * theta**53.5 ) # past the supercritical point tau's raised to .5 cause complex #'s return normalized_phi.real * self.PHI_0
[docs] def enthalpy(self, Tk: float = None, Tc: float = None) -> float: """ Returns enthalpy of saturated water. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- enthalpy: float vapor pressure in J/kg Notes ----- IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ alpha = self.auxiliaryQuantitySpecificEnthalpy(Tc=Tc, Tk=Tk) T = getTk(Tc=Tc, Tk=Tk) rho = self.pseudoDensityKgM3(Tc=Tc, Tk=Tk) dp_dT = self.vaporPressurePrime(Tc=Tc, Tk=Tk) return alpha + T / rho * dp_dT
[docs] def entropy(self, Tk: float = None, Tc: float = None) -> float: """ Returns entropy of saturated water. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- entropy: float entropy in J/(kgK) Notes ----- IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ phi = self.auxiliaryQuantitySpecificEntropy(Tc=Tc, Tk=Tk) rho = self.pseudoDensityKgM3(Tc=Tc, Tk=Tk) dp_dT = self.vaporPressurePrime(Tc=Tc, Tk=Tk) return phi + 1.0 / rho * dp_dT
[docs] def pseudoDensity(self, Tk=None, Tc=None): """ Density for arbitrary forms of water. Notes ----- In ARMI, we define pseudoDensity() and density() as the same for Fluids. """ raise NotImplementedError( "Please use a concrete instance: SaturatedWater or SaturatedSteam." )
[docs]class SaturatedWater(Water): """ Saturated Water. This is a good faith implementation of the Revised Supplementary Properties of Ordinary Water Substance (1992) by IAPWS -- International Association for the Properties of Water and Steam . This is the Saturated Liquid Water Material Class. For steam look to the Saturated Steam Material Class. """
[docs] def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float: """ Returns density in g/cc. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- density: float density in g/cc Note ---- In ARMI, we define pseudoDensity() and density() as the same for Fluids. IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ tau = self.tau(Tc=Tc, Tk=Tk) b1 = 1.99274064 b2 = 1.09965342 b3 = -0.510839303 b4 = -1.75493479 b5 = -45.5170352 b6 = -6.74694450e5 normalized_rho = ( 1 + b1 * tau ** (1.0 / 3.0) + b2 * tau ** (2.0 / 3.0) + b3 * tau ** (5.0 / 3.0) + b4 * tau ** (16.0 / 3.0) + b5 * tau ** (43.0 / 3.0) + b6 * tau ** (111.0 / 3.0) ) # past the supercritical point tau's raised to .5 cause complex #'s return normalized_rho.real * self.DENSITY_CRITICAL_GPERCUBICCENTIMETER
[docs]class SaturatedSteam(Water): """ Saturated Steam. This is a good faith implementation of the Revised Supplementary Properties of Ordinary Water Substance (1992) by IAPWS -- International Association for the Properties of Water and Steam . This is the Saturated Liquid Water Material Class. For steam look to the Saturated Steam Material Class. """
[docs] def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float: """ Returns density in g/cc. Parameters ---------- Tk: float temperature in Kelvin Tc: float temperature in Celcius Returns ------- density: float density in g/cc Notes ----- In ARMI, we define pseudoDensity() and density() as the same for Fluids. IAPWS-IF97 http://www.iapws.org/relguide/supsat.pdf IAPWS-IF97 is now the international standard for calculations in the steam power industry """ tau = self.tau(Tc=Tc, Tk=Tk) c1 = -2.03150240 c2 = -2.68302940 c3 = -5.38626492 c4 = -17.2991605 c5 = -44.7586581 c6 = -63.9201063 log_normalized_rho = ( c1 * tau ** (2.0 / 6.0) + c2 * tau ** (4.0 / 6.0) + c3 * tau ** (8.0 / 6.0) + c4 * tau ** (18.0 / 6.0) + c5 * tau ** (37.0 / 6.0) + c6 * tau ** (71.0 / 6.0) ) # past the supercritical point tau's raised to .5 cause complex #'s return ( math.e**log_normalized_rho.real * self.DENSITY_CRITICAL_GPERCUBICCENTIMETER )