Cantera  3.3.0a1
Loading...
Searching...
No Matches
WaterPropsIAPWS.cpp
Go to the documentation of this file.
1/**
2 * @file WaterPropsIAPWS.cpp
3 * Definitions for a class for calculating the equation of state of water
4 * from the IAPWS 1995 Formulation based on the steam tables thermodynamic
5 * basis (See class @link Cantera::WaterPropsIAPWS WaterPropsIAPWS@endlink).
6 */
7
8// This file is part of Cantera. See License.txt in the top-level directory or
9// at https://cantera.org/license.txt for license and copyright information.
10
14#include "cantera/base/global.h"
15
16namespace Cantera
17{
18// Critical Point values of water in mks units
19
20//! Critical Temperature value (kelvin)
21const double T_c = 647.096;
22//! Critical Pressure (Pascals)
23static const double P_c = 22.064E6;
24//! Value of the Density at the critical point (kg m-3)
25const double Rho_c = 322.;
26
27static const double R_water = 461.51805; // J/kg/K (Eq. 6.3)
28
29void WaterPropsIAPWS::calcDim(double temperature, double rho)
30{
32 delta = rho / Rho_c;
33
34 // Determine the internal state
35 if (temperature > T_c) {
36 iState = WATER_SUPERCRIT;
37 } else {
38 if (delta < 1.0) {
39 iState = WATER_GAS;
40 } else {
41 iState = WATER_LIQUID;
42 }
43 }
44}
45
47{
48 double retn = m_phi.pressureM_rhoRT(tau, delta);
49 double rho = delta * Rho_c;
50 double temperature = T_c / tau;
51 return retn * rho * R_water * temperature;
52}
53
54double WaterPropsIAPWS::density(double temperature, double pressure,
55 int phase, double rhoguess)
56{
57 if (fabs(pressure - P_c) / P_c < 1.e-8 &&
58 fabs(temperature - T_c) / T_c < 1.e-8) {
59 // Catch critical point, as no solution is found otherwise
61 return Rho_c;
62 }
63 double deltaGuess = 0.0;
64 if (rhoguess == -1.0) {
65 if (phase != -1) {
66 if (temperature > T_c) {
67 rhoguess = pressure / (R_water * temperature);
68 } else {
69 if (phase == WATER_GAS || phase == WATER_SUPERCRIT) {
70 rhoguess = pressure / (R_water * temperature);
71 } else if (phase == WATER_LIQUID) {
72 // Provide a guess about the liquid density that is
73 // relatively high -> convergence from above seems robust.
74 rhoguess = 1000.;
75 } else if (phase == WATER_UNSTABLELIQUID || phase == WATER_UNSTABLEGAS) {
76 throw CanteraError("WaterPropsIAPWS::density",
77 "Unstable Branch finder is untested");
78 } else {
79 throw CanteraError("WaterPropsIAPWS::density",
80 "unknown state: {}", phase);
81 }
82 }
83 } else {
84 // Assume the Gas phase initial guess, if nothing is specified to
85 // the routine
86 rhoguess = pressure / (R_water * temperature);
87 }
88 }
89 double p_red = pressure / (R_water * temperature * Rho_c);
90 deltaGuess = rhoguess / Rho_c;
91 setState_TD(temperature, rhoguess);
92 double delta_retn = m_phi.dfind(p_red, tau, deltaGuess);
93 if (delta_retn <= 0) {
94 // No solution found for first initial guess; perturb initial guess once
95 // to avoid spurious failures (band-aid fix)
96 delta_retn = m_phi.dfind(p_red, tau, 0.9 * deltaGuess);
97 }
98 double density_retn;
99 if (delta_retn > 0.0) {
100 delta = delta_retn;
101
102 // Dimensionalize the density before returning
103 density_retn = delta_retn * Rho_c;
104
105 // Set the internal state -> this may be a duplication. However, let's
106 // just be sure.
107 setState_TD(temperature, density_retn);
108 } else {
109 density_retn = -1.0;
110 }
111 return density_retn;
112}
113
115{
116 return delta * Rho_c;
117}
118
120{
121 return T_c / tau;
122}
123
124double WaterPropsIAPWS::psat_est(double temperature) const
125{
126 // Formula and constants from: "NBS/NRC Steam Tables: Thermodynamic and
127 // Transport Properties and Computer Programs for Vapor and Liquid States of
128 // Water in SI Units". L. Haar, J. S. Gallagher, G. S. Kell. Hemisphere
129 // Publishing. 1984.
130 static const double A[8] = {
131 -7.8889166E0,
132 2.5514255E0,
133 -6.716169E0,
134 33.2239495E0,
135 -105.38479E0,
136 174.35319E0,
137 -148.39348E0,
138 48.631602E0
139 };
140 double ps;
141 if (temperature < 314.) {
142 double pl = 6.3573118E0 - 8858.843E0 / temperature
143 + 607.56335E0 * pow(temperature, -0.6);
144 ps = 0.1 * exp(pl);
145 } else {
146 double v = temperature / 647.25;
147 double w = fabs(1.0-v);
148 double b = 0.0;
149 for (int i = 0; i < 8; i++) {
150 double z = i + 1;
151 b += A[i] * pow(w, ((z+1.0)/2.0));
152 }
153 double q = b / v;
154 ps = 22.093*exp(q);
155 }
156
157 // Original correlation was in cgs. Convert to mks
158 ps *= 1.0E6;
159 return ps;
160}
161
163{
164 double dpdrho_val = dpdrho();
165 double dens = delta * Rho_c;
166 return 1.0 / (dens * dpdrho_val);
167}
168
170{
171 double retn = m_phi.dimdpdrho(tau, delta);
172 double temperature = T_c/tau;
173 return retn * R_water * temperature;
174}
175
177{
178 return m_phi.dimdpdT(tau, delta);
179}
180
182{
183 double kappa = isothermalCompressibility();
184 double beta = coeffPresExp();
185 double dens = delta * Rho_c;
186 return kappa * dens * R_water * beta;
187}
188
189void WaterPropsIAPWS::corr(double temperature, double pressure,
190 double& densLiq, double& densGas, double& delGRT)
191{
192 densLiq = density(temperature, pressure, WATER_LIQUID, densLiq);
193 if (densLiq <= 0.0) {
194 throw CanteraError("WaterPropsIAPWS::corr",
195 "Error occurred trying to find liquid density at (T,P) = {} {}",
197 }
198 setState_TD(temperature, densLiq);
199 double gibbsLiqRT = m_phi.gibbs_RT();
200
201 densGas = density(temperature, pressure, WATER_GAS, densGas);
202 if (densGas <= 0.0) {
203 throw CanteraError("WaterPropsIAPWS::corr",
204 "Error occurred trying to find gas density at (T,P) = {} {}",
206 }
207 setState_TD(temperature, densGas);
208 double gibbsGasRT = m_phi.gibbs_RT();
209
210 delGRT = gibbsLiqRT - gibbsGasRT;
211}
212
213double WaterPropsIAPWS::psat(double temperature, int waterState)
214{
215 double densLiq = -1.0, densGas = -1.0, delGRT = 0.0;
216 if (temperature >= T_c) {
217 densGas = density(temperature, P_c, WATER_SUPERCRIT);
218 setState_TD(temperature, densGas);
219 return P_c;
220 }
221 double p = psat_est(temperature);
222 for (int i = 0; i < 30; i++) {
223 corr(temperature, p, densLiq, densGas, delGRT);
224 double delV = 1.0/densLiq - 1.0/densGas;
225 p -= delGRT * R_water * temperature / delV;
226 if (delGRT < 1.0E-8) {
227 break;
228 }
229 }
230 // Put the fluid in the desired end condition
231 if (waterState == WATER_LIQUID) {
232 setState_TD(temperature, densLiq);
233 } else if (waterState == WATER_GAS) {
234 setState_TD(temperature, densGas);
235 } else {
236 throw CanteraError("WaterPropsIAPWS::psat",
237 "unknown water state input: {}", waterState);
238 }
239 return p;
240}
241
242int WaterPropsIAPWS::phaseState(bool checkState) const
243{
244 if (checkState) {
245 if (tau <= 1.0) {
246 iState = WATER_SUPERCRIT;
247 } else {
248 double T = T_c / tau;
249 double rho = delta * Rho_c;
250 double rhoMidAtm = 0.5 * (OneAtm / (R_water * 373.15) + 1.0E3);
251 double rhoMid = Rho_c + (T - T_c) * (Rho_c - rhoMidAtm) / (T_c - 373.15);
252 int iStateGuess = WATER_LIQUID;
253 if (rho < rhoMid) {
254 iStateGuess = WATER_GAS;
255 }
256 double kappa = isothermalCompressibility();
257 if (kappa >= 0.0) {
258 iState = iStateGuess;
259 } else {
260 // When we are here we are between the spinodal curves
261 double rhoDel = rho * 1.000001;
262 double deltaSave = delta;
263 double deltaDel = rhoDel / Rho_c;
264 delta = deltaDel;
265 m_phi.tdpolycalc(tau, deltaDel);
266
267 double kappaDel = isothermalCompressibility();
268 double d2rhodp2 = (rhoDel * kappaDel - rho * kappa) / (rhoDel - rho);
269 if (d2rhodp2 > 0.0) {
270 iState = WATER_UNSTABLELIQUID;
271 } else {
272 iState = WATER_UNSTABLEGAS;
273 }
274 delta = deltaSave;
276 }
277 }
278 }
279 return iState;
280}
281
282void WaterPropsIAPWS::setState_TD(double temperature, double rho)
283{
284 calcDim(temperature, rho);
286}
287
289{
290 return m_phi.gibbs_RT() * R_water * T_c / tau;
291}
292
294{
295 return m_phi.enthalpy_RT() * R_water * T_c / tau;
296}
297
299{
300 return m_phi.intEnergy_RT() * R_water * T_c / tau;
301}
302
304{
305 return m_phi.entropy_R() * R_water;
306}
307
309{
310 return m_phi.cv_R() * R_water;
311}
312
314{
315 return m_phi.cp_R() * R_water;
316}
317
318}
Headers for a class for calculating the equation of state of water from the IAPWS 1995 Formulation ba...
Base class for exceptions thrown by Cantera classes.
double coeffThermExp() const
Returns the coefficient of thermal expansion.
double density() const
Returns the density (kg m-3)
void corr(double temperature, double pressure, double &densLiq, double &densGas, double &delGRT)
Utility routine in the calculation of the saturation pressure.
double pressure() const
Calculates the pressure (Pascals), given the current value of the temperature and density.
double gibbs_mass() const
Get the Gibbs free energy (J/kg) at the current temperature and density.
double isothermalCompressibility() const
Returns the coefficient of isothermal compressibility for the state of the object.
double psat(double temperature, int waterState=WATER_LIQUID)
This function returns the saturation pressure given the temperature as an input parameter,...
double temperature() const
Returns the temperature (Kelvin)
double cv_mass() const
Get the constant volume heat capacity (J/kg/K) at the current temperature and density.
double entropy_mass() const
Get the entropy (J/kg/K) at the current temperature and density.
double delta
Dimensionless density, delta = rho / rho_c.
double cp_mass() const
Get the constant pressure heat capacity (J/kg/K) at the current temperature and density.
double intEnergy_mass() const
Get the internal energy (J/kg) at the current temperature and density.
double coeffPresExp() const
Returns the isochoric pressure derivative wrt temperature.
int iState
Current state of the system.
void setState_TD(double temperature, double rho)
Set the internal state of the object wrt temperature and density.
double tau
Dimensionless temperature, tau = T_C / T.
WaterPropsIAPWSphi m_phi
pointer to the underlying object that does the calculations.
void calcDim(double temperature, double rho)
Calculate the dimensionless temp and rho and store internally.
int phaseState(bool checkState=false) const
Returns the Phase State flag for the current state of the object.
double dpdrho() const
Returns the value of dp / drho at constant T for the state of the object.
double psat_est(double temperature) const
This function returns an estimated value for the saturation pressure.
double enthalpy_mass() const
Get the enthalpy (J/kg) at the current temperature and density.
double gibbs_RT() const
Calculate the dimensionless Gibbs free energy.
double cv_R() const
Calculate the dimensionless constant volume heat capacity, Cv/R.
double intEnergy_RT() const
Calculate the dimensionless internal energy, u/RT.
double enthalpy_RT() const
Calculate the dimensionless enthalpy, h/RT.
double entropy_R() const
Calculate the dimensionless entropy, s/R.
double pressureM_rhoRT(double tau, double delta)
Calculate the dimensionless pressure at tau and delta;.
double dimdpdrho(double tau, double delta)
Dimensionless derivative of p wrt rho at constant T.
double dfind(double p_red, double tau, double deltaGuess)
This function computes the reduced density, given the reduced pressure and the reduced temperature,...
double dimdpdT(double tau, double delta)
Dimensionless derivative of p wrt T at constant rho.
double cp_R() const
Calculate the dimensionless constant pressure heat capacity, Cv/R.
void tdpolycalc(double tau, double delta)
Calculates internal polynomials in tau and delta.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
const double OneAtm
One atmosphere [Pa].
Definition ct_defs.h:96
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const double Rho_c
Value of the Density at the critical point (kg m-3)
const double T_c
Critical Temperature value (kelvin)
static const double P_c
Critical Pressure (Pascals)
Contains declarations for string manipulation functions within Cantera.