#################################################################################
# The Institute for the Design of Advanced Energy Systems Integrated Platform
# Framework (IDAES IP) was produced under the DOE Institute for the
# Design of Advanced Energy Systems (IDAES), and is copyright (c) 2018-2021
# by the software owners: The Regents of the University of California, through
# Lawrence Berkeley National Laboratory, National Technology & Engineering
# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia University
# Research Corporation, et al. All rights reserved.
#
# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and
# license information.
#################################################################################
"""IDAES IAPWS-95 Steam properties
Dropped all critical enhancments and non-analytic terms ment to improve
accruacy near the critical point. These tend to cause singularities in the
equations, and it is assumend that we will try to avoid operating very close to
the critical point.
References: (some of this is only used in the C++ part)
International Association for the Properties of Water and Steam (2016).
IAPWS R6-95 (2016), "Revised Release on the IAPWS Formulation 1995 for
the Properties of Ordinary Water Substance for General Scientific Use,"
URL: http://iapws.org/relguide/IAPWS95-2016.pdf
Wagner, W., A. Pruss (2002). "The IAPWS Formulation 1995 for the
Thermodynamic Properties of Ordinary Water Substance for General and
Scientific Use." J. Phys. Chem. Ref. Data, 31, 387-535.
Wagner, W. et al. (2000). "The IAPWS Industrial Formulation 1997 for the
Thermodynamic Properties of Water and Steam," ASME J. Eng. Gas Turbines
and Power, 122, 150-182.
Akasaka, R. (2008). "A Reliable and Useful Method to Determine the
Saturation State from Helmholtz Energy Equations of State." Journal of
Thermal Science and Technology, 3(3), 442-451.
International Association for the Properties of Water and Steam (2011).
IAPWS R15-11, "Release on the IAPWS Formulation 2011 for the
Thermal Conductivity of Ordinary Water Substance,"
URL: http://iapws.org/relguide/ThCond.pdf
International Association for the Properties of Water and Steam (2008).
IAPWS R12-08, "Release on the IAPWS Formulation 2008 for the Viscosity
of Ordinary Water Substance,"
URL: http://iapws.org/relguide/visc.pdf
"""
__author__ = "John Eslick"
# Import Python libraries
import os
# Import Pyomo libraries
from pyomo.environ import Expression, Param, RangeSet, Set, exp, sqrt, units as pyunits
# Import IDAES
from idaes.core import declare_process_block_class
import idaes
import idaes.logger as idaeslog
from idaes.models.properties.helmholtz.helmholtz import (
_available,
_htpx,
HelmholtzParameterBlockData,
HelmholtzStateBlockData,
HelmholtzThermoExpressions,
PhaseType,
StateVars,
_StateBlock,
)
# Logger
_log = idaeslog.getLogger(__name__)
_so = os.path.join(idaes.bin_directory, "iapws95_external.so")
def iapws95_available():
"""Make sure the compiled IAPWS-95 functions are available. Yes, in Windows
the .so extention is still used.
"""
return _available(_so)
[docs]def htpx(T=None, P=None, x=None):
"""
Convenience function to calculate steam enthalpy from temperature and
either pressure or vapor fraction. This function can be used for inlet
streams and initialization where temperature is known instead of enthalpy.
User must provided values for two of T, P, or x.
Args:
T: Temperature with units (between 200 and 3000 K)
P: Pressure with units (between 1 and 1e9 Pa), None if saturated vapor
x: Vapor fraction [mol vapor/mol total] (between 0 and 1), None if
superheated or subcooled
Returns:
Total molar enthalpy [J/mol].
"""
prop = Iapws95StateBlock(parameters=Iapws95ParameterBlock())
return _htpx(
T=T,
P=P,
x=x,
prop=prop,
Tmin=270 * pyunits.K,
Tmax=3e3 * pyunits.K,
Pmin=1e-4 * pyunits.kPa,
Pmax=1e6 * pyunits.kPa,
)
[docs]@declare_process_block_class("Iapws95ParameterBlock")
class Iapws95ParameterBlockData(HelmholtzParameterBlockData):
CONFIG = HelmholtzParameterBlockData.CONFIG()
[docs] def build(self):
self._set_parameters(
library=_so,
eos_tag="iapws95",
state_block_class=Iapws95StateBlock,
component_list=Set(initialize=["H2O"]),
phase_equilibrium_idx=Set(initialize=[1]),
phase_equilibrium_list={1: ["H2O", ("Vap", "Liq")]},
mw=Param(
initialize=0.01801528,
doc="Molecular weight [kg/mol]",
units=pyunits.kg / pyunits.mol,
),
temperature_crit=Param(
initialize=647.096, doc="Critical temperature [K]", units=pyunits.K
),
pressure_crit=Param(
initialize=2.2064e7, doc="Critical pressure [Pa]", units=pyunits.Pa
),
dens_mass_crit=Param(
initialize=322,
doc="Critical density [kg/m3]",
units=pyunits.kg / pyunits.m**3,
),
specific_gas_constant=Param(
initialize=461.51805,
doc="Water Specific Gas Constant [J/kg/K]",
units=pyunits.J / pyunits.kg / pyunits.K,
),
pressure_bounds=(0.1, 1e9),
temperature_bounds=(250, 2500),
enthalpy_bounds=(0, 1e5),
)
super().build()
# Thermal conductivity parameters.
# "Release on the IAPWS Formulation 2011 for the Thermal Conductivity
# of Ordinary Water Substance"
self.tc_L0 = Param(
RangeSet(0, 4),
initialize={
0: 2.443221e0,
1: 1.323095e1,
2: 6.770357e0,
3: -3.454586e0,
4: 4.096266e-1,
},
doc="0th order thermal conductivity parameters",
units=pyunits.K * pyunits.m / pyunits.W,
)
self.tc_L1 = Param(
RangeSet(0, 4),
RangeSet(0, 5),
initialize={
(0, 0): 1.60397357,
(1, 0): 2.33771842,
(2, 0): 2.19650529,
(3, 0): -1.21051378,
(4, 0): -2.7203370,
(0, 1): -0.646013523,
(1, 1): -2.78843778,
(2, 1): -4.54580785,
(3, 1): 1.60812989,
(4, 1): 4.57586331,
(0, 2): 0.111443906,
(1, 2): 1.53616167,
(2, 2): 3.55777244,
(3, 2): -0.621178141,
(4, 2): -3.18369245,
(0, 3): 0.102997357,
(1, 3): -0.463045512,
(2, 3): -1.40944978,
(3, 3): 0.0716373224,
(4, 3): 1.1168348,
(0, 4): -0.0504123634,
(1, 4): 0.0832827019,
(2, 4): 0.275418278,
(3, 4): 0.0,
(4, 4): -0.19268305,
(0, 5): 0.00609859258,
(1, 5): -0.00719201245,
(2, 5): -0.0205938816,
(3, 5): 0.0,
(4, 5): 0.012913842,
},
doc="1st order thermal conductivity parameters",
)
# Viscosity parameters
# "Release on the IAPWS Formulation 2008 for the Viscosity of
# Ordinary Water Substance "
self.visc_H0 = Param(
RangeSet(0, 3),
initialize={0: 1.67752, 1: 2.20462, 2: 0.6366564, 3: -0.241605},
doc="0th order viscosity parameters",
units=1 / pyunits.s / pyunits.Pa,
)
self.visc_H1 = Param(
RangeSet(0, 5),
RangeSet(0, 6),
initialize={
(0, 0): 5.20094e-1,
(1, 0): 8.50895e-2,
(2, 0): -1.08374,
(3, 0): -2.89555e-1,
(4, 0): 0.0,
(5, 0): 0.0,
(0, 1): 2.22531e-1,
(1, 1): 9.99115e-1,
(2, 1): 1.88797,
(3, 1): 1.26613,
(4, 1): 0.0,
(5, 1): 1.20573e-1,
(0, 2): -2.81378e-1,
(1, 2): -9.06851e-1,
(2, 2): -7.72479e-1,
(3, 2): -4.89837e-1,
(4, 2): -2.57040e-1,
(5, 2): 0.0,
(0, 3): 1.61913e-1,
(1, 3): 2.57399e-1,
(2, 3): 0.0,
(3, 3): 0.0,
(4, 3): 0.0,
(5, 3): 0.0,
(0, 4): -3.25372e-2,
(1, 4): 0.0,
(2, 4): 0.0,
(3, 4): 6.98452e-2,
(4, 4): 0.0,
(5, 4): 0.0,
(0, 5): 0.0,
(1, 5): 0.0,
(2, 5): 0.0,
(3, 5): 0.0,
(4, 5): 8.72102e-3,
(5, 5): 0.0,
(0, 6): 0.0,
(1, 6): 0.0,
(2, 6): 0.0,
(3, 6): -4.35673e-3,
(4, 6): 0.0,
(5, 6): -5.93264e-4,
},
doc="1st order viscosity parameters",
)
self.set_default_scaling("therm_cond_phase", 1e2, index="Liq")
self.set_default_scaling("therm_cond_phase", 1e1, index="Vap")
self.set_default_scaling("visc_d_phase", 1e5, index="Liq")
self.set_default_scaling("visc_d_phase", 1e6, index="Vap")
self.set_default_scaling("visc_k_phase", 1e5, index="Liq")
self.set_default_scaling("visc_k_phase", 1e7, index="Vap")
[docs]@declare_process_block_class(
"Iapws95StateBlock",
block_class=_StateBlock,
doc="""This is some placeholder doc.""",
)
class Iapws95StateBlockData(HelmholtzStateBlockData):
"""
This is a property package for calculating thermophysical properties of
water.
"""
[docs] def build(self, *args):
"""
Callable method for Block construction
"""
super().build(*args)
phlist = self.config.parameters.private_phase_list
tau = self.tau
delta = self.dens_phase_red # this shorter name is from IAPWS
# Phase Thermal conductiviy
def rule_tc(b, p):
L0 = self.config.parameters.tc_L0
L1 = self.config.parameters.tc_L1
return (
sqrt(1.0 / tau)
/ sum(L0[i] * tau**i for i in L0)
* exp(
delta[p]
* sum(
(tau - 1) ** i
* sum(L1[i, j] * (delta[p] - 1) ** j for j in range(0, 6))
for i in range(0, 5)
)
)
)
self.therm_cond_phase = Expression(
phlist, rule=rule_tc, doc="Thermal conductivity [W/K/m]"
)
# Phase dynamic viscosity
def rule_mu(b, p):
H0 = self.config.parameters.visc_H0
H1 = self.config.parameters.visc_H1
# The units of this are really weird, so I am just going to append
# units to the expression rather than give units to the parameters
return (
1e-4
* sqrt(1.0 / tau)
/ sum(H0[i] * tau**i for i in H0)
* exp(
delta[p]
* sum(
(tau - 1) ** i
* sum(H1[i, j] * (delta[p] - 1) ** j for j in range(0, 7))
for i in range(0, 6)
)
)
)
self.visc_d_phase = Expression(phlist, rule=rule_mu, doc="Viscosity (dynamic)")
# Phase kinimatic viscosity
def rule_nu(b, p):
return self.visc_d_phase[p] / self.dens_mass_phase[p]
self.visc_k_phase = Expression(phlist, rule=rule_nu, doc="Kinematic viscosity")