From ac59ebef5b902d6ff7d34d61be3cce1335e3b13b Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 27 Aug 2020 18:11:06 -0500 Subject: [PATCH 01/14] [thermo] Add convenience class for liquid-water-IAPWS95 --- data/liquidvapor.yaml | 12 ++++++++++++ interfaces/cython/cantera/liquidvapor.py | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/data/liquidvapor.yaml b/data/liquidvapor.yaml index 123a234cf89..084cec491a0 100644 --- a/data/liquidvapor.yaml +++ b/data/liquidvapor.yaml @@ -25,6 +25,18 @@ phases: T: 300.0 P: 1.01325e+05 pure-fluid-name: water +- name: liquid-water + elements: [O, H] + species: [H2O] + thermo: liquid-water-IAPWS95 + transport: water + state: + T: 300.0 + P: 1.01325e+05 + note: |- + Phase definition based on "The IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. - name: nitrogen thermo: pure-fluid elements: [N] diff --git a/interfaces/cython/cantera/liquidvapor.py b/interfaces/cython/cantera/liquidvapor.py index fbb1e40c9a3..ac57fb6a2c0 100644 --- a/interfaces/cython/cantera/liquidvapor.py +++ b/interfaces/cython/cantera/liquidvapor.py @@ -15,6 +15,19 @@ class WaterWithTransport(PureFluid, _cantera.Transport): return WaterWithTransport('liquidvapor.yaml', 'water', transport_model='Water') +def LiquidWater(): + """ + Create a `PureFluid` object using the IAPWS Formulation 1995 for + thermodynamic properties and the `WaterTransport` class for viscosity + and thermal conductivity. + """ + class WaterWithTransport(PureFluid, _cantera.Transport): + __slots__ = () + + return WaterWithTransport('liquidvapor.yaml', 'liquid-water', + transport_model='Water') + + def Nitrogen(): """Create a `PureFluid` object using the equation of state for nitrogen.""" return PureFluid('liquidvapor.yaml', 'nitrogen') From e6968361dfe11151ca193feb29ec55adb278fc30 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 27 Aug 2020 20:52:52 -0500 Subject: [PATCH 02/14] [thermo] Update docstrings for PureFluid convenience wrapper classes - Docstrings are updated to include information already available in MATLAB (or C++ base classes) --- data/liquidvapor.yaml | 13 +- interfaces/cython/cantera/liquidvapor.py | 152 +++++++++++++++++++++-- 2 files changed, 153 insertions(+), 12 deletions(-) diff --git a/data/liquidvapor.yaml b/data/liquidvapor.yaml index 084cec491a0..fe2269a1123 100644 --- a/data/liquidvapor.yaml +++ b/data/liquidvapor.yaml @@ -29,13 +29,12 @@ phases: elements: [O, H] species: [H2O] thermo: liquid-water-IAPWS95 - transport: water state: T: 300.0 P: 1.01325e+05 - note: |- - Phase definition based on "The IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and + note: >- + Phase definition based on W. Wagner, A. Pruss, "The IAPWS Formulation 1995 + for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. - name: nitrogen thermo: pure-fluid @@ -104,6 +103,12 @@ phases: T: 300.0 P: 1.01325e+05 pure-fluid-name: HFC-134a + note: >- + Phase definition based on R. Tillner-Roth and H. D. Baehr, "An International + Standard Formulation for The Thermodynamic Properties of + 1,1,1,2-Tetrafluoroethane (HFC-134a) for Temperatures From 170 K to 455 K + and Pressures up to 70 MPa". J. Phys. Chem. Ref. Data, Vol. 23, No. 5, 1994. + pp. 657--729. - name: hfc134a thermo: pure-fluid elements: [C, F, H] diff --git a/interfaces/cython/cantera/liquidvapor.py b/interfaces/cython/cantera/liquidvapor.py index ac57fb6a2c0..e60b7a1d096 100644 --- a/interfaces/cython/cantera/liquidvapor.py +++ b/interfaces/cython/cantera/liquidvapor.py @@ -8,11 +8,30 @@ def Water(): """ Create a `PureFluid` object using the equation of state for water and the `WaterTransport` class for viscosity and thermal conductivity. + + The object returned by this method implements an accurate equation of + state for water that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. + + whereas formulas for transport are taken from + + J. V. Sengers, J. T. R. Watson, *Improved International Formulations for + the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. Chem. + Ref. Data, 15, 1291, 1986. + + For more details, see classes Cantera::PureFluid, tpx::water and + Cantera::WaterTransport in the Cantera C++ source code documentation. """ class WaterWithTransport(PureFluid, _cantera.Transport): __slots__ = () - return WaterWithTransport('liquidvapor.yaml', 'water', transport_model='Water') + return WaterWithTransport('liquidvapor.yaml', 'water', + transport_model='Water') def LiquidWater(): @@ -20,6 +39,23 @@ def LiquidWater(): Create a `PureFluid` object using the IAPWS Formulation 1995 for thermodynamic properties and the `WaterTransport` class for viscosity and thermal conductivity. + + The object returned by this method implements an accurate equation of + state for water that can be used in the liquid and supercritical regions + of the phase diagram. The equation of state is taken from + + W. Wagner, A. Pruss, *The IAPWS Formulation 1995 for the Thermodynamic + Properties of Ordinary Water Substance for General and Scientific Use,* + J. Phys. Chem. Ref. Dat, 31, 387, 2002. + + whereas formulas for transport are taken from + + J. V. Sengers, J. T. R. Watson, *Improved International Formulations for + the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. Chem. + Ref. Data, 15, 1291, 1986. + + For more details, see classes Cantera::PureFluid, Cantera::WaterSSTP and + Cantera::WaterTransport in the Cantera C++ source code documentation. """ class WaterWithTransport(PureFluid, _cantera.Transport): __slots__ = () @@ -29,35 +65,135 @@ class WaterWithTransport(PureFluid, _cantera.Transport): def Nitrogen(): - """Create a `PureFluid` object using the equation of state for nitrogen.""" + """ + Create a `PureFluid` object using the equation of state for nitrogen. + + The object returned by this method implements an accurate equation of + state for nitrogen that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::nitrogen in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'nitrogen') def Methane(): - """Create a `PureFluid` object using the equation of state for methane.""" + """ + Create a `PureFluid` object using the equation of state for methane. + + The object returned by this method implements an accurate equation of + state for methane that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::methane in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'methane') def Hydrogen(): - """Create a `PureFluid` object using the equation of state for hydrogen.""" + """ + Create a `PureFluid` object using the equation of state for hydrogen. + + The object returned by this method implements an accurate equation of + state for hydrogen that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::hydrogen in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'hydrogen') def Oxygen(): - """Create a `PureFluid` object using the equation of state for oxygen.""" + """ + Create a `PureFluid` object using the equation of state for oxygen. + + The object returned by this method implements an accurate equation of + state for oxygen that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::oxygen in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'oxygen') def Hfc134a(): - """Create a `PureFluid` object using the equation of state for HFC-134a.""" + """ + Create a `PureFluid` object using the equation of state for HFC-134a. + + The object returned by this method implements an accurate equation of + state for refrigerant HFC134a (R134a) that can be used in the liquid, + vapor, saturated liquid/vapor, and supercritical regions of the phase + diagram. Implements the equation of state given in: + + R. Tillner-Roth and H. D. Baehr. *An International Standard Formulation for + The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for + Temperatures From 170 K to 455 K and Pressures up to 70 MPa.* J. Phys. + Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. + http://dx.doi.org/10.1063/1.555958 + + For more details, see classes Cantera::PureFluid and tpx::HFC134a in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'HFC-134a') def CarbonDioxide(): - """Create a `PureFluid` object using the equation of state for carbon dioxide.""" + """ + Create a `PureFluid` object using the equation of state for carbon dioxide. + + The object returned by this method implements an accurate equation of + state for carbon dioxide that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::CarbonDioxide in + the Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'carbon-dioxide') def Heptane(): - """Create a `PureFluid` object using the equation of state for heptane.""" + """ + Create a `PureFluid` object using the equation of state for heptane. + + The object returned by this method implements an accurate equation of + state for n-heptane that can be used in the liquid, vapor, saturated + liquid/vapor, and supercritical regions of the phase diagram. The + equation of state is taken from + + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. + + For more details, see classes Cantera::PureFluid and tpx::Heptane in the + Cantera C++ source code documentation. + """ return PureFluid('liquidvapor.yaml', 'heptane') From d08e0b1d3a021a7e48a7645d7774e8d85fc4ad1e Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 27 Aug 2020 21:47:24 -0500 Subject: [PATCH 03/14] Minor formatting changes --- interfaces/matlab/toolbox/HFC134a.m | 4 ++-- src/tpx/HFC134a.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interfaces/matlab/toolbox/HFC134a.m b/interfaces/matlab/toolbox/HFC134a.m index 3ebb902d309..61aa00d3cba 100644 --- a/interfaces/matlab/toolbox/HFC134a.m +++ b/interfaces/matlab/toolbox/HFC134a.m @@ -2,10 +2,10 @@ % HFC134A Return an object representing refrigerant HFC134a. % h = HFC134a() % The object returned by this method implements an accurate equation of -% state for refrigerant HFC134a (R134a) that can be used in the liquid, +% state for refrigerant HFC134a (R134a) that can be used in the liquid, % vapor, saturated liquid/vapor, and supercritical regions of the phase % diagram. Implements the equation of state given in: -% R. Tillner-Roth and H.D. Baehr. "An International Standard Formulation for +% R. Tillner-Roth and H. D. Baehr. "An International Standard Formulation for % The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for % Temperatures From 170 K to 455 K and Pressures up to 70 MPa". J. Phys. % Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. diff --git a/src/tpx/HFC134a.h b/src/tpx/HFC134a.h index 498facb4d95..0351279ec51 100644 --- a/src/tpx/HFC134a.h +++ b/src/tpx/HFC134a.h @@ -13,7 +13,7 @@ namespace tpx //! Equation of state for HFC-134a. //! //! Implements the equation of state given in: -//! R. Tillner-Roth and H.D. Baehr. "An International Standard Formulation for +//! R. Tillner-Roth and H. D. Baehr. "An International Standard Formulation for //! The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for //! Temperatures From 170 K to 455 K and Pressures up to 70 MPa". J. Phys. //! Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. From b929c029ea4aae1ec57bb9df74ff7a3542e9ed20 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Thu, 27 Aug 2020 22:10:57 -0500 Subject: [PATCH 04/14] [thermo] Improve documentation of WaterSSTP helper classes Co-authored by: Shekhar Shukla <47356149+24sharkS@users.noreply.github.com> --- include/cantera/thermo/WaterProps.h | 3 +++ include/cantera/thermo/WaterPropsIAPWS.h | 3 +++ include/cantera/thermo/WaterPropsIAPWSphi.h | 3 +++ 3 files changed, 9 insertions(+) diff --git a/include/cantera/thermo/WaterProps.h b/include/cantera/thermo/WaterProps.h index ec0520b2bee..fbaced025af 100644 --- a/include/cantera/thermo/WaterProps.h +++ b/include/cantera/thermo/WaterProps.h @@ -83,6 +83,9 @@ class PDSS_Water; //! The WaterProps class is used to house several approximation routines for //! properties of water. /*! + * This is a helper class for WaterSSTP and is not instantiable on its own + * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * * The class is also a wrapper around the WaterPropsIAPWS class which provides * the calculations for the equation of state properties for water. * diff --git a/include/cantera/thermo/WaterPropsIAPWS.h b/include/cantera/thermo/WaterPropsIAPWS.h index 85f14b9e5c4..a3db0af8994 100644 --- a/include/cantera/thermo/WaterPropsIAPWS.h +++ b/include/cantera/thermo/WaterPropsIAPWS.h @@ -37,6 +37,9 @@ namespace Cantera //! Class for calculating the equation of state of water. /*! + * This is a helper class for WaterSSTP and is not instantiable on its own + * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * * The reference is W. Wagner, A. Pruss, "The IAPWS Formulation 1995 for the * Thermodynamic Properties of Ordinary Water Substance for General and * Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. diff --git a/include/cantera/thermo/WaterPropsIAPWSphi.h b/include/cantera/thermo/WaterPropsIAPWSphi.h index fc274b1c347..db143d3d8cb 100644 --- a/include/cantera/thermo/WaterPropsIAPWSphi.h +++ b/include/cantera/thermo/WaterPropsIAPWSphi.h @@ -20,6 +20,9 @@ namespace Cantera //! Low level class for the real description of water. /*! + * This is a helper class for WaterSSTP and is not instantiable on its own + * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * * The reference is W. Wagner, A. Pruss, "The IAPWS Formulation 1995 for the * Thermodynamic Properties of Ordinary Water Substance for General and * Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. From 7a8407b3a4e481161846acda19030701c8c1adb0 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 11:29:24 -0500 Subject: [PATCH 05/14] [thermo] Ensure that WaterSSTP satisfies model assumptions --- src/thermo/ThermoPhase.cpp | 11 +++++++++-- src/thermo/WaterSSTP.cpp | 32 +++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/thermo/ThermoPhase.cpp b/src/thermo/ThermoPhase.cpp index 294cd0dc297..33aed0ad12e 100644 --- a/src/thermo/ThermoPhase.cpp +++ b/src/thermo/ThermoPhase.cpp @@ -135,8 +135,15 @@ void ThermoPhase::setState_TPY(doublereal t, doublereal p, const std::string& y) void ThermoPhase::setState_TP(doublereal t, doublereal p) { - setTemperature(t); - setPressure(p); + double tsave = temperature(); + double dsave = density(); + try { + setTemperature(t); + setPressure(p); + } catch (CanteraError&) { + setState_TR(tsave, dsave); + throw; + } } void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const doublereal* x) diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index a381c01aa87..28993d8e085 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -266,15 +266,27 @@ doublereal WaterSSTP::pressure() const void WaterSSTP::setPressure(doublereal p) { double T = temperature(); - double dens = density(); - int waterState = WATER_GAS; - double rc = m_sub.Rhocrit(); - if (dens > rc) { - waterState = WATER_LIQUID; + double dens = 1.; + double pp = m_sub.psat(T); + int waterState = WATER_SUPERCRIT; + if (T < m_sub.Tcrit()) { + if (p >= pp) { + waterState = WATER_LIQUID; + dens = 1000.; + } else { + throw CanteraError("WaterSSTP::setPressure", + "Pressure p = {} lies below the saturation " + "pressure\n(P_sat = {}), which violates model " + "assumptions.", p, pp); + } } - doublereal dd = m_sub.density(T, p, waterState, dens); + + double dd = m_sub.density(T, p, waterState, dens); if (dd <= 0.0) { - throw CanteraError("WaterSSTP::setPressure", "error"); + throw CanteraError("WaterSSTP::setPressure", + "error: T = {}, p = {}, psat = {}\n" + "density_guess = {}, density_fail = {}", + T, p, pp, dens, dd); } setDensity(dd); } @@ -323,6 +335,12 @@ doublereal WaterSSTP::critDensity() const void WaterSSTP::setTemperature(const doublereal temp) { + if (temp < 273.16) { + throw CanteraError("WaterSSTP::setTemperature", + "Temperature T = {} lies below the triple point " + "temperature,\nwhich violates model assumptions.", + temp); + } Phase::setTemperature(temp); m_sub.setState_TR(temp, density()); } From 721e6e01f3e0472ddc67177a8ee3d1102ce5b9ab Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 11:29:50 -0500 Subject: [PATCH 06/14] [thermo] Ensure that WaterPropsIAPWS::density works for critical point --- src/thermo/WaterPropsIAPWS.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/thermo/WaterPropsIAPWS.cpp b/src/thermo/WaterPropsIAPWS.cpp index 59aacaa68e1..3f373cef0d2 100644 --- a/src/thermo/WaterPropsIAPWS.cpp +++ b/src/thermo/WaterPropsIAPWS.cpp @@ -78,6 +78,15 @@ doublereal WaterPropsIAPWS::pressure() const doublereal WaterPropsIAPWS::density(doublereal temperature, doublereal pressure, int phase, doublereal rhoguess) { + if (fabs(pressure - P_c) / P_c < 1.e-8 && + fabs(temperature - T_c) / T_c < 1.e-8) { + // Catch critical point, as no solution is found otherwise + setState_TR(temperature, Rho_c); + return Rho_c; + } else if (fabs(rhoguess - Rho_c) / Rho_c < 1.e-8) { + // Starting a search with the critical density would fail + rhoguess *= .9; + } doublereal deltaGuess = 0.0; if (rhoguess == -1.0) { if (phase != -1) { @@ -109,7 +118,7 @@ doublereal WaterPropsIAPWS::density(doublereal temperature, doublereal pressure, setState_TR(temperature, rhoguess); doublereal delta_retn = m_phi.dfind(p_red, tau, deltaGuess); doublereal density_retn; - if (delta_retn >0.0) { + if (delta_retn > 0.0) { delta = delta_retn; // Dimensionalize the density before returning From 25dfb2b10a579599e1c43b284f47e3a6ea145dad Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 12:57:32 -0500 Subject: [PATCH 07/14] [thermo] Implement allowGasPhase override for WaterSSTP --- include/cantera/thermo/WaterSSTP.h | 3 +++ src/thermo/WaterSSTP.cpp | 4 ++-- test_problems/cathermo/testWaterTP/testWaterSSTP.cpp | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index 215304cbfb9..66f4feda72a 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -238,6 +238,9 @@ class WaterSSTP : public SingleSpeciesTP return m_waterProps.get(); } + //! Switch that enables calculations in the gas phase + void allowGasPhase(bool flag) { m_allowGasPhase = flag; } + protected: /** * @internal This internal routine must be overridden because it is not diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index 28993d8e085..8d37e28d3c4 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -266,14 +266,14 @@ doublereal WaterSSTP::pressure() const void WaterSSTP::setPressure(doublereal p) { double T = temperature(); - double dens = 1.; + double dens = density(); double pp = m_sub.psat(T); int waterState = WATER_SUPERCRIT; if (T < m_sub.Tcrit()) { if (p >= pp) { waterState = WATER_LIQUID; dens = 1000.; - } else { + } else if (!m_allowGasPhase) { throw CanteraError("WaterSSTP::setPressure", "Pressure p = {} lies below the saturation " "pressure\n(P_sat = {}), which violates model " diff --git a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp index 2e1a433a293..f885e170202 100644 --- a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp +++ b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp @@ -1,4 +1,5 @@ #include "cantera/thermo/ThermoFactory.h" +#include "cantera/thermo/WaterSSTP.h" #include using namespace std; @@ -21,6 +22,7 @@ int main() double pres; try { ThermoPhase* w = newPhase("liquid-water.xml"); + (dynamic_cast(w))->allowGasPhase(true); /* * Print out the triple point conditions From ffef9e30427cbc71f1f152b7ff5a54f33b5676da Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 11:52:04 -0500 Subject: [PATCH 08/14] [unittests] Add/update tests for LiquidWater object --- .../cython/cantera/test/test_composite.py | 3 +++ .../cython/cantera/test/test_convert.py | 8 +++--- .../cython/cantera/test/test_purefluid.py | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/interfaces/cython/cantera/test/test_composite.py b/interfaces/cython/cantera/test/test_composite.py index b63687f2735..06e1742d73f 100644 --- a/interfaces/cython/cantera/test/test_composite.py +++ b/interfaces/cython/cantera/test/test_composite.py @@ -87,6 +87,9 @@ def check(a, b): try: sol = ct.Solution(self.yml_file, ph_name) a = ct.SolutionArray(sol, 10) + if ph['thermo'] == 'liquid-water-IAPWS95': + # ensure that phase remains liquid + a.TP = sol.T, sol.critical_pressure # assign some state T = 373.15 + 100*np.random.rand(10) diff --git a/interfaces/cython/cantera/test/test_convert.py b/interfaces/cython/cantera/test/test_convert.py index 88b508e173f..228891d2afa 100644 --- a/interfaces/cython/cantera/test/test_convert.py +++ b/interfaces/cython/cantera/test/test_convert.py @@ -841,10 +841,10 @@ def checkConversion(self, basename, cls=ct.Solution, ctmlphases=(), return ctmlPhase, yamlPhase - def checkThermo(self, ctmlPhase, yamlPhase, temperatures, tol=1e-7): + def checkThermo(self, ctmlPhase, yamlPhase, temperatures, pressure=ct.one_atm, tol=1e-7): for T in temperatures: - ctmlPhase.TP = T, ct.one_atm - yamlPhase.TP = T, ct.one_atm + ctmlPhase.TP = T, pressure + yamlPhase.TP = T, pressure cp_ctml = ctmlPhase.partial_molar_cp cp_yaml = yamlPhase.partial_molar_cp h_ctml = ctmlPhase.partial_molar_enthalpies @@ -1134,7 +1134,7 @@ def test_water_IAPWS95_thermo(self): Path(self.test_work_dir).joinpath("liquid-water.yaml"), ) ctmlWater, yamlWater = self.checkConversion("liquid-water") - self.checkThermo(ctmlWater, yamlWater, [300, 500, 1300, 2000]) + self.checkThermo(ctmlWater, yamlWater, [300, 500, 1300, 2000], pressure=22064000.0) self.assertEqual(ctmlWater.transport_model, yamlWater.transport_model) dens = ctmlWater.density for T in [298, 1001, 2400]: diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 8cbe2c9aa60..271efe62bcc 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -357,6 +357,31 @@ def test_phase_of_matter(self): co2 = ct.CarbonDioxide() self.assertEqual(co2.phase_of_matter, "gas") + def test_liquidwater(self): + w = ct.LiquidWater() + self.assertNear(w.critical_density, 322.) + self.assertNear(w.critical_temperature, 647.096) + self.assertNear(w.critical_pressure, 22064000.0) + + # test internal TP setters (setters update temperature at constant + # density before updating pressure) + w.TP = 300, ct.one_atm + dens = w.density + w.TP = 2000, ct.one_atm # supercricial + w.TP = 300, ct.one_atm # state goes from supercritical -> gas -> liquid + self.assertNear(w.density, dens) + + # test setters for critical conditions + w.TP = w.critical_temperature, w.critical_pressure + self.assertNear(w.density, 322.) + w.TP = 2000, ct.one_atm # uses current density as initial guess + w.TP = 273.16, ct.one_atm # uses fixed density as initial guess + self.assertNear(w.density, 999.84376) + with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): + w.TP = 273.1599999, ct.one_atm + with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): + w.TP = 500, ct.one_atm + # To minimize errors when transcribing tabulated data, the input units here are: # T: K, P: MPa, rho: kg/m3, v: m3/kg, (u,h): kJ/kg, s: kJ/kg-K From b54ba6ea1f48501bb8bcfd3fa540de20fda190dc Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 15:49:59 -0500 Subject: [PATCH 09/14] [thermo] Implement phaseOfMatter for WaterSSTP class --- include/cantera/thermo/WaterSSTP.h | 8 +++++--- interfaces/cython/cantera/test/test_purefluid.py | 7 ++++++- src/thermo/WaterSSTP.cpp | 7 +++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index 66f4feda72a..156081581e8 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -20,7 +20,7 @@ namespace Cantera class WaterPropsIAPWS; class WaterProps; //! Class for single-component water. This is designed to cover just the liquid -//! part of water. +//! and supercritical phases of water. /*! * The reference is W. Wagner, A. Pruss, "The IAPWS Formulation 1995 for the * Thermodynamic Properties of Ordinary Water Substance for General and @@ -143,6 +143,8 @@ class WaterSSTP : public SingleSpeciesTP return "Water"; } + virtual std::string phaseOfMatter() const; + //! @name Molar Thermodynamic Properties of the Solution //! @{ @@ -281,8 +283,8 @@ class WaterSSTP : public SingleSpeciesTP bool m_ready; /** - * Since this phase represents a liquid phase, it's an error to - * return a gas-phase answer. However, if the below is true, then + * Since this phase represents a liquid (or supercritical) phase, it is an + * error to return a gas-phase answer. However, if the below is true, then * a gas-phase answer is allowed. This is used to check the thermodynamic * consistency with ideal-gas thermo functions for example. */ diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 271efe62bcc..2dc44a6173a 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -367,9 +367,11 @@ def test_liquidwater(self): # density before updating pressure) w.TP = 300, ct.one_atm dens = w.density - w.TP = 2000, ct.one_atm # supercricial + w.TP = 2000, ct.one_atm # supercritical + self.assertEqual(w.phase_of_matter, "supercritical") w.TP = 300, ct.one_atm # state goes from supercritical -> gas -> liquid self.assertNear(w.density, dens) + self.assertEqual(w.phase_of_matter, "liquid") # test setters for critical conditions w.TP = w.critical_temperature, w.critical_pressure @@ -377,6 +379,9 @@ def test_liquidwater(self): w.TP = 2000, ct.one_atm # uses current density as initial guess w.TP = 273.16, ct.one_atm # uses fixed density as initial guess self.assertNear(w.density, 999.84376) + self.assertEqual(w.phase_of_matter, "liquid") + w.TP = w.T, w.P_sat + self.assertEqual(w.phase_of_matter, "liquid") with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): w.TP = 273.1599999, ct.one_atm with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index 8d37e28d3c4..abbea3d8e3f 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -44,6 +44,13 @@ WaterSSTP::WaterSSTP(XML_Node& phaseRoot, const std::string& id) : importPhase(phaseRoot, this); } +std::string WaterSSTP::phaseOfMatter() const { + const vector phases = { + "gas", "liquid", "supercritical", "unstable-liquid", "unstable-gas" + }; + return phases[m_sub.phaseState()]; +} + void WaterSSTP::initThermo() { SingleSpeciesTP::initThermo(); From 3f1a3d1715a5bcabc31b20a0edae94683e755cfd Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 28 Aug 2020 20:36:03 -0500 Subject: [PATCH 10/14] [thermo] Add IAPWS as alternative backend to existing Water wrapper While the current 'liquid-water-IAPWS95' thermo model only implements liquid (and supercritical) states, the underlying IAPWS formulation can be extended beyond in future revisions. - avoid 'liquid' as part of the nomenclature - YAML phase name is updated to `water-iapws95` - Instead of creating a new wrapper, `iapws95` is added as an alternative backend to the existing `Water` class --- data/liquidvapor.yaml | 2 +- interfaces/cython/cantera/liquidvapor.py | 116 ++++++++---------- .../cython/cantera/test/test_purefluid.py | 17 ++- src/thermo/WaterSSTP.cpp | 14 +-- .../cathermo/testWaterTP/testWaterSSTP.cpp | 2 +- 5 files changed, 70 insertions(+), 81 deletions(-) diff --git a/data/liquidvapor.yaml b/data/liquidvapor.yaml index fe2269a1123..2c45fd14024 100644 --- a/data/liquidvapor.yaml +++ b/data/liquidvapor.yaml @@ -25,7 +25,7 @@ phases: T: 300.0 P: 1.01325e+05 pure-fluid-name: water -- name: liquid-water +- name: water-iapws95 elements: [O, H] species: [H2O] thermo: liquid-water-IAPWS95 diff --git a/interfaces/cython/cantera/liquidvapor.py b/interfaces/cython/cantera/liquidvapor.py index e60b7a1d096..078bd7a89c9 100644 --- a/interfaces/cython/cantera/liquidvapor.py +++ b/interfaces/cython/cantera/liquidvapor.py @@ -4,64 +4,48 @@ from . import PureFluid, _cantera -def Water(): +def Water(backend='default'): """ Create a `PureFluid` object using the equation of state for water and the `WaterTransport` class for viscosity and thermal conductivity. - The object returned by this method implements an accurate equation of - state for water that can be used in the liquid, vapor, saturated - liquid/vapor, and supercritical regions of the phase diagram. The - equation of state is taken from - - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances.* Stanford: Stanford - University, 1979. Print. - - whereas formulas for transport are taken from - - J. V. Sengers, J. T. R. Watson, *Improved International Formulations for - the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. Chem. - Ref. Data, 15, 1291, 1986. - - For more details, see classes Cantera::PureFluid, tpx::water and - Cantera::WaterTransport in the Cantera C++ source code documentation. - """ - class WaterWithTransport(PureFluid, _cantera.Transport): - __slots__ = () + The object returned by this method implements an accurate equation of state + for water, where implementations are selected using the *backend* switch. - return WaterWithTransport('liquidvapor.yaml', 'water', - transport_model='Water') + For the ``default`` backend, the equation of state is taken from + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. -def LiquidWater(): - """ - Create a `PureFluid` object using the IAPWS Formulation 1995 for - thermodynamic properties and the `WaterTransport` class for viscosity - and thermal conductivity. + which can be used in the liquid, vapor, saturated liquid/vapor, and + supercritical regions of the phase diagram. - The object returned by this method implements an accurate equation of - state for water that can be used in the liquid and supercritical regions - of the phase diagram. The equation of state is taken from - - W. Wagner, A. Pruss, *The IAPWS Formulation 1995 for the Thermodynamic - Properties of Ordinary Water Substance for General and Scientific Use,* - J. Phys. Chem. Ref. Dat, 31, 387, 2002. + The ``iapws95`` backend implements an IAPWS (International Association for + the Properties of Water and Steam) formulation for thermodynamic properties + taken from - whereas formulas for transport are taken from + J. V. Sengers, J. T. R. Watson, *Improved International Formulations for + the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. + Chem. Ref. Data, 15, 1291, 1986. - J. V. Sengers, J. T. R. Watson, *Improved International Formulations for - the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. Chem. - Ref. Data, 15, 1291, 1986. + which currently only implements liquid and supercritical regions. - For more details, see classes Cantera::PureFluid, Cantera::WaterSSTP and - Cantera::WaterTransport in the Cantera C++ source code documentation. + For more details, see classes Cantera::PureFluid, tpx::water, + Cantera::WaterSSTP and Cantera::WaterTransport in the Cantera C++ source + code documentation. """ class WaterWithTransport(PureFluid, _cantera.Transport): __slots__ = () - return WaterWithTransport('liquidvapor.yaml', 'liquid-water', - transport_model='Water') + if backend == 'default': + return WaterWithTransport('liquidvapor.yaml', 'water', + transport_model='Water') + if backend == 'iapws95': + return WaterWithTransport('liquidvapor.yaml', 'water-iapws95', + transport_model='Water') + + raise KeyError("Unknown backend '{}'".format(backend)) def Nitrogen(): @@ -73,9 +57,9 @@ def Nitrogen(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::nitrogen in the Cantera C++ source code documentation. @@ -92,9 +76,9 @@ def Methane(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::methane in the Cantera C++ source code documentation. @@ -111,9 +95,9 @@ def Hydrogen(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::hydrogen in the Cantera C++ source code documentation. @@ -130,9 +114,9 @@ def Oxygen(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::oxygen in the Cantera C++ source code documentation. @@ -149,11 +133,11 @@ def Hfc134a(): vapor, saturated liquid/vapor, and supercritical regions of the phase diagram. Implements the equation of state given in: - R. Tillner-Roth and H. D. Baehr. *An International Standard Formulation for - The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for - Temperatures From 170 K to 455 K and Pressures up to 70 MPa.* J. Phys. - Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. - http://dx.doi.org/10.1063/1.555958 + R. Tillner-Roth, H. D. Baehr. *An International Standard Formulation for + The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for + Temperatures From 170 K to 455 K and Pressures up to 70 MPa.* J. Phys. + Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. + http://dx.doi.org/10.1063/1.555958 For more details, see classes Cantera::PureFluid and tpx::HFC134a in the Cantera C++ source code documentation. @@ -170,9 +154,9 @@ def CarbonDioxide(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances.* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::CarbonDioxide in the Cantera C++ source code documentation. @@ -189,9 +173,9 @@ def Heptane(): liquid/vapor, and supercritical regions of the phase diagram. The equation of state is taken from - W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and - computational equations for forty substances.* Stanford: Stanford - University, 1979. Print. + W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and + computational equations for forty substances.* Stanford: Stanford + University, 1979. Print. For more details, see classes Cantera::PureFluid and tpx::Heptane in the Cantera C++ source code documentation. diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 2dc44a6173a..2b5ff884a9c 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -357,8 +357,17 @@ def test_phase_of_matter(self): co2 = ct.CarbonDioxide() self.assertEqual(co2.phase_of_matter, "gas") - def test_liquidwater(self): - w = ct.LiquidWater() + def test_water_backends(self): + w = ct.Water(backend='default') + self.assertEqual(w.thermo_model, 'PureFluid') + w = ct.Water(backend='iapws95') + self.assertEqual(w.thermo_model, 'Water') + with self.assertRaisesRegex(KeyError, 'Unknown backend'): + ct.Water('foobar') + + + def test_water_iapws(self): + w = ct.Water(backend='iapws95') self.assertNear(w.critical_density, 322.) self.assertNear(w.critical_temperature, 647.096) self.assertNear(w.critical_pressure, 22064000.0) @@ -382,9 +391,9 @@ def test_liquidwater(self): self.assertEqual(w.phase_of_matter, "liquid") w.TP = w.T, w.P_sat self.assertEqual(w.phase_of_matter, "liquid") - with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): + with self.assertRaisesRegex(ct.CanteraError, "Not implemented"): w.TP = 273.1599999, ct.one_atm - with self.assertRaisesRegex(ct.CanteraError, "violates model assumptions"): + with self.assertRaisesRegex(ct.CanteraError, "Not implemented"): w.TP = 500, ct.one_atm diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index abbea3d8e3f..b252746a2f4 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -282,18 +282,14 @@ void WaterSSTP::setPressure(doublereal p) dens = 1000.; } else if (!m_allowGasPhase) { throw CanteraError("WaterSSTP::setPressure", - "Pressure p = {} lies below the saturation " - "pressure\n(P_sat = {}), which violates model " - "assumptions.", p, pp); + "Not implemented: pressure p = {} lies below\n" + "the saturation pressure (P_sat = {}).", p, pp); } } double dd = m_sub.density(T, p, waterState, dens); if (dd <= 0.0) { - throw CanteraError("WaterSSTP::setPressure", - "error: T = {}, p = {}, psat = {}\n" - "density_guess = {}, density_fail = {}", - T, p, pp, dens, dd); + throw CanteraError("WaterSSTP::setPressure", "Error"); } setDensity(dd); } @@ -344,8 +340,8 @@ void WaterSSTP::setTemperature(const doublereal temp) { if (temp < 273.16) { throw CanteraError("WaterSSTP::setTemperature", - "Temperature T = {} lies below the triple point " - "temperature,\nwhich violates model assumptions.", + "Not implemented: temperature T = {} lies below\n" + "the triple point temperature (T_triple = 273.16).", temp); } Phase::setTemperature(temp); diff --git a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp index f885e170202..13a9530225b 100644 --- a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp +++ b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp @@ -21,7 +21,7 @@ int main() #endif double pres; try { - ThermoPhase* w = newPhase("liquid-water.xml"); + ThermoPhase* w = newPhase("liquidvapor.yaml", "water-iapws95"); (dynamic_cast(w))->allowGasPhase(true); /* From fbc2657bd5b2b52290e5704f8ec0a6c7ce5d12c0 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 30 Aug 2020 09:02:17 -0500 Subject: [PATCH 11/14] [thermo] Clarify WaterSSTP::type --- include/cantera/thermo/WaterSSTP.h | 2 +- interfaces/cython/cantera/test/test_purefluid.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index 156081581e8..fb949391cf3 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -140,7 +140,7 @@ class WaterSSTP : public SingleSpeciesTP explicit WaterSSTP(XML_Node& phaseRef, const std::string& id = ""); virtual std::string type() const { - return "Water"; + return "WaterSSTP"; } virtual std::string phaseOfMatter() const; diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 2b5ff884a9c..57198ea7832 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -361,11 +361,10 @@ def test_water_backends(self): w = ct.Water(backend='default') self.assertEqual(w.thermo_model, 'PureFluid') w = ct.Water(backend='iapws95') - self.assertEqual(w.thermo_model, 'Water') + self.assertEqual(w.thermo_model, 'WaterSSTP') with self.assertRaisesRegex(KeyError, 'Unknown backend'): ct.Water('foobar') - def test_water_iapws(self): w = ct.Water(backend='iapws95') self.assertNear(w.critical_density, 322.) From 7abfaa110a63b18347627f8936d1602c73237a00 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Tue, 1 Sep 2020 22:03:16 -0500 Subject: [PATCH 12/14] [thermo] Finalize liquid-water-IAPWS95 updates --- data/liquidvapor.yaml | 13 +++--- include/cantera/thermo/WaterProps.h | 6 ++- include/cantera/thermo/WaterPropsIAPWS.h | 6 ++- include/cantera/thermo/WaterPropsIAPWSphi.h | 6 ++- include/cantera/thermo/WaterSSTP.h | 8 +++- interfaces/cython/cantera/liquidvapor.py | 40 +++++++++++-------- .../cython/cantera/test/test_purefluid.py | 12 +++--- src/thermo/WaterSSTP.cpp | 9 ++--- .../cathermo/testWaterTP/testWaterSSTP.cpp | 2 +- 9 files changed, 60 insertions(+), 42 deletions(-) diff --git a/data/liquidvapor.yaml b/data/liquidvapor.yaml index 2c45fd14024..f06363dd3fb 100644 --- a/data/liquidvapor.yaml +++ b/data/liquidvapor.yaml @@ -25,7 +25,7 @@ phases: T: 300.0 P: 1.01325e+05 pure-fluid-name: water -- name: water-iapws95 +- name: liquid-water-IAPWS95 elements: [O, H] species: [H2O] thermo: liquid-water-IAPWS95 @@ -33,9 +33,10 @@ phases: T: 300.0 P: 1.01325e+05 note: >- - Phase definition based on W. Wagner, A. Pruss, "The IAPWS Formulation 1995 - for the Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. + Equation of state is based on W. Wagner, A. Pruss, "The IAPWS Formulation + 1995 for the Thermodynamic Properties of Ordinary Water Substance for + General and Scientific Use," J. Phys. Chem. Ref. Dat, 31, 387, 2002. + Important: Only liquid and supercritical states are currently implemented - name: nitrogen thermo: pure-fluid elements: [N] @@ -104,8 +105,8 @@ phases: P: 1.01325e+05 pure-fluid-name: HFC-134a note: >- - Phase definition based on R. Tillner-Roth and H. D. Baehr, "An International - Standard Formulation for The Thermodynamic Properties of + Equation of state is based on R. Tillner-Roth and H. D. Baehr, "An + International Standard Formulation for The Thermodynamic Properties of 1,1,1,2-Tetrafluoroethane (HFC-134a) for Temperatures From 170 K to 455 K and Pressures up to 70 MPa". J. Phys. Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. diff --git a/include/cantera/thermo/WaterProps.h b/include/cantera/thermo/WaterProps.h index fbaced025af..74fd66d7209 100644 --- a/include/cantera/thermo/WaterProps.h +++ b/include/cantera/thermo/WaterProps.h @@ -83,8 +83,10 @@ class PDSS_Water; //! The WaterProps class is used to house several approximation routines for //! properties of water. /*! - * This is a helper class for WaterSSTP and is not instantiable on its own - * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * This is a helper class for WaterSSTP and PDSS_Water and does not constitute + * a complete implementation of a thermo phase by itself (see \ref thermoprops + * and classes \link Cantera::WaterSSTP WaterSSTP\endlink and + * \link Cantera::PDSS_Water PDSS_Water\endlink). * * The class is also a wrapper around the WaterPropsIAPWS class which provides * the calculations for the equation of state properties for water. diff --git a/include/cantera/thermo/WaterPropsIAPWS.h b/include/cantera/thermo/WaterPropsIAPWS.h index a3db0af8994..b0d5a26b103 100644 --- a/include/cantera/thermo/WaterPropsIAPWS.h +++ b/include/cantera/thermo/WaterPropsIAPWS.h @@ -37,8 +37,10 @@ namespace Cantera //! Class for calculating the equation of state of water. /*! - * This is a helper class for WaterSSTP and is not instantiable on its own - * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * This is a helper class for WaterSSTP and PDSS_Water and does not constitute + * a complete implementation of a thermo phase by itself (see \ref thermoprops + * and classes \link Cantera::WaterSSTP WaterSSTP\endlink and + * \link Cantera::PDSS_Water PDSS_Water\endlink). * * The reference is W. Wagner, A. Pruss, "The IAPWS Formulation 1995 for the * Thermodynamic Properties of Ordinary Water Substance for General and diff --git a/include/cantera/thermo/WaterPropsIAPWSphi.h b/include/cantera/thermo/WaterPropsIAPWSphi.h index db143d3d8cb..e0faa94133f 100644 --- a/include/cantera/thermo/WaterPropsIAPWSphi.h +++ b/include/cantera/thermo/WaterPropsIAPWSphi.h @@ -20,8 +20,10 @@ namespace Cantera //! Low level class for the real description of water. /*! - * This is a helper class for WaterSSTP and is not instantiable on its own - * (see \ref thermoprops and class \link Cantera::WaterSSTP WaterSSTP\endlink). + * This is a helper class for WaterSSTP and PDSS_Water and does not constitute + * a complete implementation of a thermo phase by itself (see \ref thermoprops + * and classes \link Cantera::WaterSSTP WaterSSTP\endlink and + * \link Cantera::PDSS_Water PDSS_Water\endlink). * * The reference is W. Wagner, A. Pruss, "The IAPWS Formulation 1995 for the * Thermodynamic Properties of Ordinary Water Substance for General and diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index fb949391cf3..410a43b8342 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -140,7 +140,7 @@ class WaterSSTP : public SingleSpeciesTP explicit WaterSSTP(XML_Node& phaseRef, const std::string& id = ""); virtual std::string type() const { - return "WaterSSTP"; + return "liquid-water-IAPWS95"; } virtual std::string phaseOfMatter() const; @@ -241,6 +241,12 @@ class WaterSSTP : public SingleSpeciesTP } //! Switch that enables calculations in the gas phase + /** + * Since this phase represents a liquid (or supercritical) phase, it is an + * error to return a gas-phase answer. The sole intended use for this + * member function is to check the thermodynamic consistency of the + * underlying WaterProps class with ideal-gas thermo functions. + */ void allowGasPhase(bool flag) { m_allowGasPhase = flag; } protected: diff --git a/interfaces/cython/cantera/liquidvapor.py b/interfaces/cython/cantera/liquidvapor.py index 078bd7a89c9..8bf6a17d834 100644 --- a/interfaces/cython/cantera/liquidvapor.py +++ b/interfaces/cython/cantera/liquidvapor.py @@ -4,7 +4,7 @@ from . import PureFluid, _cantera -def Water(backend='default'): +def Water(backend='Reynolds'): """ Create a `PureFluid` object using the equation of state for water and the `WaterTransport` class for viscosity and thermal conductivity. @@ -12,7 +12,7 @@ def Water(backend='default'): The object returned by this method implements an accurate equation of state for water, where implementations are selected using the *backend* switch. - For the ``default`` backend, the equation of state is taken from + For the ``Reynolds`` backend, the equation of state is taken from W. C. Reynolds, *Thermodynamic Properties in SI: graphs, tables, and computational equations for forty substances.* Stanford: Stanford @@ -21,28 +21,34 @@ def Water(backend='default'): which can be used in the liquid, vapor, saturated liquid/vapor, and supercritical regions of the phase diagram. - The ``iapws95`` backend implements an IAPWS (International Association for + The ``IAPWS95`` backend implements an IAPWS (International Association for the Properties of Water and Steam) formulation for thermodynamic properties taken from + W. Wagner, A. Pruss, *The IAPWS Formulation 1995 for the Thermodynamic + Properties of Ordinary Water Substance for General and Scientific Use,* + J. Phys. Chem. Ref. Dat, 31, 387, 2002. + + which currently only implements liquid and supercritical regions. + + In both cases, formulas for transport are taken from + J. V. Sengers, J. T. R. Watson, *Improved International Formulations for the Viscosity and Thermal Conductivity of Water Substance,* J. Phys. Chem. Ref. Data, 15, 1291, 1986. - which currently only implements liquid and supercritical regions. - - For more details, see classes Cantera::PureFluid, tpx::water, - Cantera::WaterSSTP and Cantera::WaterTransport in the Cantera C++ source + For more details, see classes :ct:PureFluid, tpx::water, + :ct:WaterSSTP and :ct:WaterTransport in the Cantera C++ source code documentation. """ class WaterWithTransport(PureFluid, _cantera.Transport): __slots__ = () - if backend == 'default': + if backend == 'Reynolds': return WaterWithTransport('liquidvapor.yaml', 'water', transport_model='Water') - if backend == 'iapws95': - return WaterWithTransport('liquidvapor.yaml', 'water-iapws95', + if backend == 'IAPWS95': + return WaterWithTransport('liquidvapor.yaml', 'liquid-water-IAPWS95', transport_model='Water') raise KeyError("Unknown backend '{}'".format(backend)) @@ -61,7 +67,7 @@ def Nitrogen(): computational equations for forty substances* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::nitrogen in the + For more details, see classes :ct:PureFluid and tpx::nitrogen in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'nitrogen') @@ -80,7 +86,7 @@ def Methane(): computational equations for forty substances* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::methane in the + For more details, see classes :ct:PureFluid and tpx::methane in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'methane') @@ -99,7 +105,7 @@ def Hydrogen(): computational equations for forty substances* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::hydrogen in the + For more details, see classes :ct:PureFluid and tpx::hydrogen in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'hydrogen') @@ -118,7 +124,7 @@ def Oxygen(): computational equations for forty substances* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::oxygen in the + For more details, see classes :ct:PureFluid and tpx::oxygen in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'oxygen') @@ -139,7 +145,7 @@ def Hfc134a(): Chem. Ref. Data, Vol. 23, No. 5, 1994. pp. 657--729. http://dx.doi.org/10.1063/1.555958 - For more details, see classes Cantera::PureFluid and tpx::HFC134a in the + For more details, see classes :ct:PureFluid and tpx::HFC134a in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'HFC-134a') @@ -158,7 +164,7 @@ def CarbonDioxide(): computational equations for forty substances.* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::CarbonDioxide in + For more details, see classes :ct:PureFluid and tpx::CarbonDioxide in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'carbon-dioxide') @@ -177,7 +183,7 @@ def Heptane(): computational equations for forty substances.* Stanford: Stanford University, 1979. Print. - For more details, see classes Cantera::PureFluid and tpx::Heptane in the + For more details, see classes :ct:PureFluid and tpx::Heptane in the Cantera C++ source code documentation. """ return PureFluid('liquidvapor.yaml', 'heptane') diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 57198ea7832..8913204f76a 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -358,15 +358,15 @@ def test_phase_of_matter(self): self.assertEqual(co2.phase_of_matter, "gas") def test_water_backends(self): - w = ct.Water(backend='default') + w = ct.Water(backend='Reynolds') self.assertEqual(w.thermo_model, 'PureFluid') - w = ct.Water(backend='iapws95') - self.assertEqual(w.thermo_model, 'WaterSSTP') + w = ct.Water(backend='IAPWS95') + self.assertEqual(w.thermo_model, 'liquid-water-IAPWS95') with self.assertRaisesRegex(KeyError, 'Unknown backend'): ct.Water('foobar') def test_water_iapws(self): - w = ct.Water(backend='iapws95') + w = ct.Water(backend='IAPWS95') self.assertNear(w.critical_density, 322.) self.assertNear(w.critical_temperature, 647.096) self.assertNear(w.critical_pressure, 22064000.0) @@ -390,9 +390,9 @@ def test_water_iapws(self): self.assertEqual(w.phase_of_matter, "liquid") w.TP = w.T, w.P_sat self.assertEqual(w.phase_of_matter, "liquid") - with self.assertRaisesRegex(ct.CanteraError, "Not implemented"): + with self.assertRaisesRegex(ct.CanteraError, "assumes liquid phase"): w.TP = 273.1599999, ct.one_atm - with self.assertRaisesRegex(ct.CanteraError, "Not implemented"): + with self.assertRaisesRegex(ct.CanteraError, "assumes liquid phase"): w.TP = 500, ct.one_atm diff --git a/src/thermo/WaterSSTP.cpp b/src/thermo/WaterSSTP.cpp index b252746a2f4..85926fcfd38 100644 --- a/src/thermo/WaterSSTP.cpp +++ b/src/thermo/WaterSSTP.cpp @@ -282,8 +282,8 @@ void WaterSSTP::setPressure(doublereal p) dens = 1000.; } else if (!m_allowGasPhase) { throw CanteraError("WaterSSTP::setPressure", - "Not implemented: pressure p = {} lies below\n" - "the saturation pressure (P_sat = {}).", p, pp); + "Model assumes liquid phase; pressure p = {} lies below\n" + "the saturation pressure (P_sat = {}).", p, pp); } } @@ -340,9 +340,8 @@ void WaterSSTP::setTemperature(const doublereal temp) { if (temp < 273.16) { throw CanteraError("WaterSSTP::setTemperature", - "Not implemented: temperature T = {} lies below\n" - "the triple point temperature (T_triple = 273.16).", - temp); + "Model assumes liquid phase; temperature T = {} lies below\n" + "the triple point temperature (T_triple = 273.16).", temp); } Phase::setTemperature(temp); m_sub.setState_TR(temp, density()); diff --git a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp index 13a9530225b..26c9683bec4 100644 --- a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp +++ b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp @@ -21,7 +21,7 @@ int main() #endif double pres; try { - ThermoPhase* w = newPhase("liquidvapor.yaml", "water-iapws95"); + ThermoPhase* w = newPhase("liquidvapor.yaml", "liquid-water-IAPWS95"); (dynamic_cast(w))->allowGasPhase(true); /* From 4b3bf78ca07b109d52cbad577003ec8e3da53f5b Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Sun, 6 Sep 2020 14:01:12 -0500 Subject: [PATCH 13/14] [thermo] Avoid spurious WaterPropsIAPWS::density failures Some initial guesses fail (see GitHUb issue #577, or starting with an initial density guess equl to the critical density); running an alternative initial guess prevents spurious failures (fix is a band-aid). --- src/thermo/WaterPropsIAPWS.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/thermo/WaterPropsIAPWS.cpp b/src/thermo/WaterPropsIAPWS.cpp index 3f373cef0d2..9eee1dfc33d 100644 --- a/src/thermo/WaterPropsIAPWS.cpp +++ b/src/thermo/WaterPropsIAPWS.cpp @@ -83,9 +83,6 @@ doublereal WaterPropsIAPWS::density(doublereal temperature, doublereal pressure, // Catch critical point, as no solution is found otherwise setState_TR(temperature, Rho_c); return Rho_c; - } else if (fabs(rhoguess - Rho_c) / Rho_c < 1.e-8) { - // Starting a search with the critical density would fail - rhoguess *= .9; } doublereal deltaGuess = 0.0; if (rhoguess == -1.0) { @@ -117,6 +114,11 @@ doublereal WaterPropsIAPWS::density(doublereal temperature, doublereal pressure, deltaGuess = rhoguess / Rho_c; setState_TR(temperature, rhoguess); doublereal delta_retn = m_phi.dfind(p_red, tau, deltaGuess); + if (delta_retn <= 0) { + // No solution found for first initial guess; perturb initial guess once + // to avoid spurious failures (band-aid fix) + delta_retn = m_phi.dfind(p_red, tau, 0.9 * deltaGuess); + } doublereal density_retn; if (delta_retn > 0.0) { delta = delta_retn; From 62f9d7d1a631126592d5045e8e57126739eee8c1 Mon Sep 17 00:00:00 2001 From: Ingmar Schoegl Date: Fri, 29 Jan 2021 10:24:09 -0600 Subject: [PATCH 14/14] Mark _allowGasPhase override as not intended for general use --- include/cantera/thermo/WaterSSTP.h | 2 +- test_problems/cathermo/testWaterTP/testWaterSSTP.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cantera/thermo/WaterSSTP.h b/include/cantera/thermo/WaterSSTP.h index 410a43b8342..e6850d5a9a7 100644 --- a/include/cantera/thermo/WaterSSTP.h +++ b/include/cantera/thermo/WaterSSTP.h @@ -247,7 +247,7 @@ class WaterSSTP : public SingleSpeciesTP * member function is to check the thermodynamic consistency of the * underlying WaterProps class with ideal-gas thermo functions. */ - void allowGasPhase(bool flag) { m_allowGasPhase = flag; } + void _allowGasPhase(bool flag) { m_allowGasPhase = flag; } protected: /** diff --git a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp index 26c9683bec4..54066c47ee4 100644 --- a/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp +++ b/test_problems/cathermo/testWaterTP/testWaterSSTP.cpp @@ -22,7 +22,7 @@ int main() double pres; try { ThermoPhase* w = newPhase("liquidvapor.yaml", "liquid-water-IAPWS95"); - (dynamic_cast(w))->allowGasPhase(true); + (dynamic_cast(w))->_allowGasPhase(true); /* * Print out the triple point conditions