Cantera  2.0
WaterSSTP.cpp
Go to the documentation of this file.
1 /**
2  * @file WaterSSTP.cpp
3  * Definitions for a %ThermoPhase class consisting of pure water (see \ref thermoprops
4  * and class \link Cantera::WaterSSTP WaterSSTP\endlink).
5  */
6 /*
7  * Copyright (2006) Sandia Corporation. Under the terms of
8  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
9  * U.S. Government retains certain rights in this software.
10  */
11 
16 #include "cantera/base/xml.h"
18 
19 #include <cmath>
20 #include <fstream>
21 
22 using namespace std;
23 
24 namespace Cantera
25 {
26 /**
27  * Basic list of constructors and duplicators
28  */
29 
30 WaterSSTP::WaterSSTP() :
32  m_sub(0),
33  m_waterProps(0),
34  m_mw(0.0),
35  EW_Offset(0.0),
36  SW_Offset(0.0),
37  m_ready(false),
38  m_allowGasPhase(false)
39 {
40  //constructPhase();
41 }
42 
43 
44 WaterSSTP::WaterSSTP(std::string inputFile, std::string id) :
46  m_sub(0),
47  m_waterProps(0),
48  m_mw(0.0),
49  EW_Offset(0.0),
50  SW_Offset(0.0),
51  m_ready(false),
52  m_allowGasPhase(false)
53 {
54  constructPhaseFile(inputFile, id);
55 }
56 
57 
58 WaterSSTP::WaterSSTP(XML_Node& phaseRoot, std::string id) :
60  m_sub(0),
61  m_waterProps(0),
62  m_mw(0.0),
63  EW_Offset(0.0),
64  SW_Offset(0.0),
65  m_ready(false),
66  m_allowGasPhase(false)
67 {
68  constructPhaseXML(phaseRoot, id) ;
69 }
70 
71 
72 
74  SingleSpeciesTP(b),
75  m_sub(0),
76  m_waterProps(0),
77  m_mw(b.m_mw),
78  EW_Offset(b.EW_Offset),
79  SW_Offset(b.SW_Offset),
80  m_ready(false),
81  m_allowGasPhase(b.m_allowGasPhase)
82 {
83  m_sub = new WaterPropsIAPWS(*(b.m_sub));
85 
86  /*
87  * Use the assignment operator to do the brunt
88  * of the work for the copy constructor.
89  */
90  *this = b;
91 }
92 
93 /*
94  * Assignment operator
95  */
97 {
98  if (&b == this) {
99  return *this;
100  }
101  m_sub->operator=(*(b.m_sub));
102 
103  if (!m_waterProps) {
105  }
106  m_waterProps->operator=(*(b.m_waterProps));
107 
108 
109  m_mw = b.m_mw;
110  m_ready = b.m_ready;
112  return *this;
113 }
114 
115 
117 {
118  WaterSSTP* wtp = new WaterSSTP(*this);
119  return (ThermoPhase*) wtp;
120 }
121 
123 {
124  delete m_sub;
125  delete m_waterProps;
126 }
127 
128 
129 
130 
131 /*
132  * @param infile XML file containing the description of the
133  * phase
134  *
135  * @param id Optional parameter identifying the name of the
136  * phase. If none is given, the first XML
137  * phase element will be used.
138  */
139 void WaterSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id)
140 {
141 
142  /*
143  * Call the Cantera importPhase() function. This will import
144  * all of the species into the phase. This will also handle
145  * all of the solvent and solute standard states.
146  */
147  bool m_ok = importPhase(phaseNode, this);
148  if (!m_ok) {
149  throw CanteraError("initThermo","importPhase failed ");
150  }
151 
152 }
153 
154 /*
155  * constructPhaseFile
156  *
157  *
158  * This routine is a precursor to constructPhaseXML(XML_Node*)
159  * routine, which does most of the work.
160  *
161  * @param inputFile XML file containing the description of the
162  * phase
163  *
164  * @param id Optional parameter identifying the name of the
165  * phase. If none is given, the first XML
166  * phase element will be used.
167  */
168 void WaterSSTP::constructPhaseFile(std::string inputFile, std::string id)
169 {
170 
171  if (inputFile.size() == 0) {
172  throw CanteraError("WaterSSTP::constructPhaseFile",
173  "input file is null");
174  }
175  std::string path = findInputFile(inputFile);
176  std::ifstream fin(path.c_str());
177  if (!fin) {
178  throw CanteraError("WaterSSTP::constructPhaseFile","could not open "
179  +path+" for reading.");
180  }
181  /*
182  * The phase object automatically constructs an XML object.
183  * Use this object to store information.
184  */
185  XML_Node& phaseNode_XML = xml();
186  XML_Node* fxml = new XML_Node();
187  fxml->build(fin);
188  XML_Node* fxml_phase = findXMLPhase(fxml, id);
189  if (!fxml_phase) {
190  throw CanteraError("WaterSSTP::constructPhaseFile",
191  "ERROR: Can not find phase named " +
192  id + " in file named " + inputFile);
193  }
194  fxml_phase->copy(&phaseNode_XML);
195  constructPhaseXML(*fxml_phase, id);
196  delete fxml;
197 }
198 
199 
200 
202 {
204 }
205 
206 void WaterSSTP::
207 initThermoXML(XML_Node& phaseNode, std::string id)
208 {
209 
210  /*
211  * Do initializations that don't depend on knowing the XML file
212  */
213  initThermo();
214  if (m_sub) {
215  delete m_sub;
216  }
217  m_sub = new WaterPropsIAPWS();
218  if (m_sub == 0) {
219  throw CanteraError("WaterSSTP::initThermo",
220  "could not create new substance object.");
221  }
222  /*
223  * Calculate the molecular weight. Note while there may
224  * be a very good calculated weight in the steam table
225  * class, using this weight may lead to codes exhibiting
226  * mass loss issues. We need to grab the elemental
227  * atomic weights used in the Element class and calculate
228  * a consistent H2O molecular weight based on that.
229  */
230  size_t nH = elementIndex("H");
231  if (nH == npos) {
232  throw CanteraError("WaterSSTP::initThermo",
233  "H not an element");
234  }
235  double mw_H = atomicWeight(nH);
236  size_t nO = elementIndex("O");
237  if (nO == npos) {
238  throw CanteraError("WaterSSTP::initThermo",
239  "O not an element");
240  }
241  double mw_O = atomicWeight(nO);
242  m_mw = 2.0 * mw_H + mw_O;
244  double one = 1.0;
245  setMoleFractions(&one);
246 
247  /*
248  * Set the baseline
249  */
250  doublereal T = 298.15;
251  Phase::setDensity(7.0E-8);
253 
254  doublereal presLow = 1.0E-2;
255  doublereal oneBar = 1.0E5;
256  doublereal dd = m_sub->density(T, presLow, WATER_GAS, 7.0E-8);
257  setDensity(dd);
258  setTemperature(T);
259  SW_Offset = 0.0;
260  doublereal s = entropy_mole();
261  s -= GasConstant * log(oneBar/presLow);
262  if (s != 188.835E3) {
263  SW_Offset = 188.835E3 - s;
264  }
265  s = entropy_mole();
266  s -= GasConstant * log(oneBar/presLow);
267  //printf("s = %g\n", s);
268 
269  doublereal h = enthalpy_mole();
270  if (h != -241.826E6) {
271  EW_Offset = -241.826E6 - h;
272  }
273  h = enthalpy_mole();
274 
275  //printf("h = %g\n", h);
276 
277 
278  /*
279  * Set the initial state of the system to 298.15 K and
280  * 1 bar.
281  */
282  setTemperature(298.15);
283  double rho0 = m_sub->density(298.15, OneAtm, WATER_LIQUID);
284  setDensity(rho0);
285 
287 
288 
289  /*
290  * We have to do something with the thermo function here.
291  */
292  if (m_spthermo) {
293  delete m_spthermo;
294  m_spthermo = 0;
295  }
296 
297  /*
298  * Set the flag to say we are ready to calculate stuff
299  */
300  m_ready = true;
301 }
302 
303 void WaterSSTP::
305 {
306  eosdata._require("model","PureLiquidWater");
307 }
308 
309 /*
310  * Return the molar dimensionless enthalpy
311  */
312 void WaterSSTP::getEnthalpy_RT(doublereal* hrt) const
313 {
314  double T = temperature();
315  doublereal h = m_sub->enthalpy();
316  *hrt = (h + EW_Offset)/(GasConstant*T);
317 }
318 
319 /*
320  * Calculate the internal energy in mks units of
321  * J kmol-1
322  */
323 void WaterSSTP::getIntEnergy_RT(doublereal* ubar) const
324 {
325  doublereal u = m_sub->intEnergy();
326  *ubar = (u + EW_Offset)/GasConstant;
327 }
328 
329 /*
330  * Calculate the dimensionless entropy
331  */
332 void WaterSSTP::getEntropy_R(doublereal* sr) const
333 {
334  doublereal s = m_sub->entropy();
335  sr[0] = (s + SW_Offset) / GasConstant;
336 }
337 
338 /*
339  * Calculate the Gibbs free energy in mks units of
340  * J kmol-1 K-1.
341  */
342 void WaterSSTP::getGibbs_RT(doublereal* grt) const
343 {
344  double T = temperature();
345  doublereal g = m_sub->Gibbs();
346  *grt = (g + EW_Offset - SW_Offset*T) / (GasConstant * T);
347  if (!m_ready) {
348  throw CanteraError("waterSSTP::", "Phase not ready");
349  }
350 }
351 
352 /*
353  * Calculate the Gibbs free energy in mks units of
354  * J kmol-1 K-1.
355  */
356 void WaterSSTP::getStandardChemPotentials(doublereal* gss) const
357 {
358  double T = temperature();
359  doublereal g = m_sub->Gibbs();
360  *gss = (g + EW_Offset - SW_Offset*T);
361  if (!m_ready) {
362  throw CanteraError("waterSSTP::", "Phase not ready");
363  }
364 }
365 
366 void WaterSSTP::getCp_R(doublereal* cpr) const
367 {
368  doublereal cp = m_sub->cp();
369  cpr[0] = cp / GasConstant;
370 }
371 
372 /*
373  * Calculate the constant volume heat capacity
374  * in mks units of J kmol-1 K-1
375  */
376 doublereal WaterSSTP::cv_mole() const
377 {
378  doublereal cv = m_sub->cv();
379  return cv;
380 }
381 
382 // @name Thermodynamic Values for the Species Reference State
383 
384 
385 void WaterSSTP::getEnthalpy_RT_ref(doublereal* hrt) const
386 {
387  doublereal p = pressure();
388  double T = temperature();
389  double dens = density();
390  int waterState = WATER_GAS;
391  double rc = m_sub->Rhocrit();
392  if (dens > rc) {
393  waterState = WATER_LIQUID;
394  }
395  doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
396  if (dd <= 0.0) {
397  throw CanteraError("setPressure", "error");
398  }
399  doublereal h = m_sub->enthalpy();
400  *hrt = (h + EW_Offset) / (GasConstant * T);
401  dd = m_sub->density(T, p, waterState, dens);
402 }
403 
404 void WaterSSTP::getGibbs_RT_ref(doublereal* grt) const
405 {
406  doublereal p = pressure();
407  double T = temperature();
408  double dens = density();
409  int waterState = WATER_GAS;
410  double rc = m_sub->Rhocrit();
411  if (dens > rc) {
412  waterState = WATER_LIQUID;
413  }
414  doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
415  if (dd <= 0.0) {
416  throw CanteraError("setPressure", "error");
417  }
418  m_sub->setState_TR(T, dd);
419  doublereal g = m_sub->Gibbs();
420  *grt = (g + EW_Offset - SW_Offset*T)/ (GasConstant * T);
421  dd = m_sub->density(T, p, waterState, dens);
422 
423 }
424 
425 void WaterSSTP::getGibbs_ref(doublereal* g) const
426 {
427  getGibbs_RT_ref(g);
428  doublereal rt = _RT();
429  for (size_t k = 0; k < m_kk; k++) {
430  g[k] *= rt;
431  }
432 }
433 
434 void WaterSSTP::getEntropy_R_ref(doublereal* sr) const
435 {
436  doublereal p = pressure();
437  double T = temperature();
438  double dens = density();
439  int waterState = WATER_GAS;
440  double rc = m_sub->Rhocrit();
441  if (dens > rc) {
442  waterState = WATER_LIQUID;
443  }
444  doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
445 
446  if (dd <= 0.0) {
447  throw CanteraError("setPressure", "error");
448  }
449  m_sub->setState_TR(T, dd);
450 
451  doublereal s = m_sub->entropy();
452  *sr = (s + SW_Offset)/ (GasConstant);
453  dd = m_sub->density(T, p, waterState, dens);
454 
455 }
456 
457 void WaterSSTP::getCp_R_ref(doublereal* cpr) const
458 {
459  doublereal p = pressure();
460  double T = temperature();
461  double dens = density();
462  int waterState = WATER_GAS;
463  double rc = m_sub->Rhocrit();
464  if (dens > rc) {
465  waterState = WATER_LIQUID;
466  }
467  doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
468  m_sub->setState_TR(T, dd);
469  if (dd <= 0.0) {
470  throw CanteraError("setPressure", "error");
471  }
472  doublereal cp = m_sub->cp();
473  *cpr = cp / (GasConstant);
474  dd = m_sub->density(T, p, waterState, dens);
475 }
476 
477 void WaterSSTP::getStandardVolumes_ref(doublereal* vol) const
478 {
479  doublereal p = pressure();
480  double T = temperature();
481  double dens = density();
482  int waterState = WATER_GAS;
483  double rc = m_sub->Rhocrit();
484  if (dens > rc) {
485  waterState = WATER_LIQUID;
486  }
487  doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
488  if (dd <= 0.0) {
489  throw CanteraError("setPressure", "error");
490  }
491  *vol = meanMolecularWeight() /dd;
492  dd = m_sub->density(T, p, waterState, dens);
493 }
494 
495 /*
496  * Calculate the pressure (Pascals), given the temperature and density
497  * Temperature: kelvin
498  * rho: density in kg m-3
499  */
500 doublereal WaterSSTP::pressure() const
501 {
502  doublereal p = m_sub->pressure();
503  return p;
504 }
505 
506 void WaterSSTP::
507 setPressure(doublereal p)
508 {
509  double T = temperature();
510  double dens = density();
511  int waterState = WATER_GAS;
512  double rc = m_sub->Rhocrit();
513  if (dens > rc) {
514  waterState = WATER_LIQUID;
515  }
516  doublereal dd = m_sub->density(T, p, waterState, dens);
517  if (dd <= 0.0) {
518  throw CanteraError("setPressure", "error");
519  }
520  setDensity(dd);
521 }
522 
523 // Returns the isothermal compressibility. Units: 1/Pa.
524 /*
525  * The isothermal compressibility is defined as
526  * \f[
527  * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T
528  * \f]
529  * or
530  * \f[
531  * \kappa_T = \frac{1}{\rho}\left(\frac{\partial \rho}{\partial P}\right)_T
532  * \f]
533  */
535 {
536  doublereal val = m_sub->isothermalCompressibility();
537  return val;
538 }
539 
540 // Return the volumetric thermal expansion coefficient. Units: 1/K.
541 /*
542  * The thermal expansion coefficient is defined as
543  * \f[
544  * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
545  * \f]
546  */
548 {
549  doublereal val = m_sub->coeffThermExp();
550  return val;
551 }
552 
554 {
555  doublereal pres = pressure();
556  doublereal dens_save = density();
557  double T = temperature();
558  double tt = T - 0.04;
559  doublereal dd = m_sub->density(tt, pres, WATER_LIQUID, dens_save);
560  if (dd < 0.0) {
561  throw CanteraError("WaterSSTP::dthermalExpansionCoeffdT",
562  "Unable to solve for the density at T = " + fp2str(tt) + ", P = " + fp2str(pres));
563  }
564  doublereal vald = m_sub->coeffThermExp();
565  m_sub->setState_TR(T, dens_save);
566  doublereal val2 = m_sub->coeffThermExp();
567  doublereal val = (val2 - vald) / 0.04;
568  return val;
569 }
570 
571 
572 // critical temperature
573 doublereal WaterSSTP::critTemperature() const
574 {
575  return m_sub->Tcrit();
576 }
577 
578 // critical pressure
579 doublereal WaterSSTP::critPressure() const
580 {
581  return m_sub->Pcrit();
582 }
583 
584 // critical density
585 doublereal WaterSSTP::critDensity() const
586 {
587  return m_sub->Rhocrit();
588 }
589 
590 
591 void WaterSSTP::setTemperature(const doublereal temp)
592 {
593  Phase::setTemperature(temp);
594  doublereal dd = density();
595  m_sub->setState_TR(temp, dd);
596 }
597 
598 void WaterSSTP::setDensity(const doublereal dens)
599 {
600  Phase::setDensity(dens);
601  doublereal temp = temperature();
602  m_sub->setState_TR(temp, dens);
603 }
604 
605 // saturation pressure
606 doublereal WaterSSTP::satPressure(doublereal t) const
607 {
608  doublereal tsave = temperature();
609  doublereal dsave = density();
610  doublereal pp = m_sub->psat(t);
611  m_sub->setState_TR(tsave, dsave);
612  return pp;
613 }
614 
615 // Return the fraction of vapor at the current conditions
616 doublereal WaterSSTP::vaporFraction() const
617 {
618  if (temperature() >= m_sub->Tcrit()) {
619  double dens = density();
620  if (dens >= m_sub->Rhocrit()) {
621  return 0.0;
622  }
623  return 1.0;
624  }
625  /*
626  * If below tcrit we always return 0 from this class
627  */
628  return 0.0;
629 }
630 
631 
632 }