Cantera  2.0
PDSS_Water.cpp
Go to the documentation of this file.
1 /**
2  * @file PDSS_Water.cpp
3  *
4  */
5 /*
6  * Copyright (2006) Sandia Corporation. Under the terms of
7  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
8  * U.S. Government retains certain rights in this software.
9  */
10 #include "cantera/base/ct_defs.h"
11 
12 #include "cantera/base/xml.h"
13 #include "cantera/base/ctml.h"
15 
21 
22 #include <cmath>
23 #include <fstream>
24 
25 namespace Cantera
26 {
27 /**
28  * Basic list of constructors and duplicators
29  */
31  PDSS(),
32  m_sub(0),
33  m_waterProps(0),
34  m_dens(1000.0),
35  m_iState(WATER_LIQUID),
36  EW_Offset(0.0),
37  SW_Offset(0.0),
38  m_verbose(0),
39  m_allowGasPhase(false)
40 {
41  m_pdssType = cPDSS_WATER;
42  m_sub = new WaterPropsIAPWS();
44  m_spthermo = 0;
45  constructSet();
46  m_minTemp = 200.;
47  m_maxTemp = 10000.;
48 }
49 
51  PDSS(tp, spindex),
52  m_sub(0),
53  m_waterProps(0),
54  m_dens(1000.0),
55  m_iState(WATER_LIQUID),
56  EW_Offset(0.0),
57  SW_Offset(0.0),
58  m_verbose(0),
59  m_allowGasPhase(false)
60 {
61  m_pdssType = cPDSS_WATER;
62  m_sub = new WaterPropsIAPWS();
64  m_spthermo = 0;
65  constructSet();
66  m_minTemp = 200.;
67  m_maxTemp = 10000.;
68 }
69 
70 
72  std::string inputFile, std::string id) :
73  PDSS(tp, spindex),
74  m_sub(0),
75  m_waterProps(0),
76  m_dens(1000.0),
77  m_iState(WATER_LIQUID),
78  EW_Offset(0.0),
79  SW_Offset(0.0),
80  m_verbose(0),
81  m_allowGasPhase(false)
82 {
83  m_pdssType = cPDSS_WATER;
84  m_sub = new WaterPropsIAPWS();
86  constructPDSSFile(tp, spindex, inputFile, id);
87  m_spthermo = 0;
88  m_minTemp = 200.;
89  m_maxTemp = 10000.;
90 }
91 
93  const XML_Node& speciesNode,
94  const XML_Node& phaseRoot, bool spInstalled) :
95  PDSS(tp, spindex),
96  m_sub(0),
97  m_waterProps(0),
98  m_dens(1000.0),
99  m_iState(WATER_LIQUID),
100  EW_Offset(0.0),
101  SW_Offset(0.0),
102  m_verbose(0),
103  m_allowGasPhase(false)
104 {
105  m_pdssType = cPDSS_WATER;
106  m_sub = new WaterPropsIAPWS();
108  std::string id= "";
109  constructPDSSXML(tp, spindex, phaseRoot, id) ;
110  initThermo();
111  m_spthermo = 0;
112  m_minTemp = 200.;
113  m_maxTemp = 10000.;
114 }
115 
116 
117 
119  PDSS(),
120  m_sub(0),
121  m_waterProps(0),
122  m_dens(1000.0),
123  m_iState(WATER_LIQUID),
124  EW_Offset(b.EW_Offset),
125  SW_Offset(b.SW_Offset),
126  m_verbose(b.m_verbose),
127  m_allowGasPhase(b.m_allowGasPhase)
128 {
129  m_sub = new WaterPropsIAPWS();
130  /*
131  * Use the assignment operator to do the brunt
132  * of the work for the copy constructor.
133  */
134  *this = b;
135 }
136 
137 /**
138  * Assignment operator
139  */
141 {
142  if (&b == this) {
143  return *this;
144  }
145  /*
146  * Call the base class operator
147  */
148  PDSS::operator=(b);
149 
150  if (!m_sub) {
151  m_sub = new WaterPropsIAPWS();
152  }
153  m_sub->operator=(*(b.m_sub));
154 
155  if (!m_waterProps) {
157  }
158  m_waterProps->operator=(*(b.m_waterProps));
159 
160  m_dens = b.m_dens;
161  m_iState = b.m_iState;
162  EW_Offset = b.EW_Offset;
163  SW_Offset = b.SW_Offset;
164  m_verbose = b.m_verbose;
166 
167  return *this;
168 }
169 
171 {
172  delete m_waterProps;
173  delete m_sub;
174 }
175 
177 {
178  PDSS_Water* kPDSS = new PDSS_Water(*this);
179  return (PDSS*) kPDSS;
180 }
181 
182 /*
183  * constructPDSSXML:
184  *
185  * Initialization of a Debye-Huckel phase using an
186  * xml file.
187  *
188  * This routine is a precursor to constructSet
189  * routine, which does most of the work.
190  *
191  * @param infile XML file containing the description of the
192  * phase
193  *
194  * @param id Optional parameter identifying the name of the
195  * phase. If none is given, the first XML
196  * phase element will be used.
197  */
199  const XML_Node& phaseNode, std::string id)
200 {
201  constructSet();
202 }
203 
204 /*
205  * constructPDSSFile():
206  *
207  * Initialization of a Debye-Huckel phase using an
208  * xml file.
209  *
210  * This routine is a precursor to constructPDSSXML(XML_Node*)
211  * routine, which does most of the work.
212  *
213  * @param infile XML file containing the description of the
214  * phase
215  *
216  * @param id Optional parameter identifying the name of the
217  * phase. If none is given, the first XML
218  * phase element will be used.
219  */
221  std::string inputFile, std::string id)
222 {
223 
224  if (inputFile.size() == 0) {
225  throw CanteraError("PDSS_Water::constructPDSSFile",
226  "input file is null");
227  }
228  std::string path = findInputFile(inputFile);
229  std::ifstream fin(path.c_str());
230  if (!fin) {
231  throw CanteraError("PDSS_Water::initThermo","could not open "
232  +path+" for reading.");
233  }
234  /*
235  * The phase object automatically constructs an XML object.
236  * Use this object to store information.
237  */
238 
239  XML_Node* fxml = new XML_Node();
240  fxml->build(fin);
241  XML_Node* fxml_phase = findXMLPhase(fxml, id);
242  if (!fxml_phase) {
243  throw CanteraError("PDSS_Water::initThermo",
244  "ERROR: Can not find phase named " +
245  id + " in file named " + inputFile);
246  }
247  constructPDSSXML(tp, spindex, *fxml_phase, id);
248  delete fxml;
249 }
250 
251 
252 
254 {
255  if (m_sub) {
256  delete m_sub;
257  }
258  m_sub = new WaterPropsIAPWS();
259  if (m_sub == 0) {
260  throw CanteraError("PDSS_Water::initThermo",
261  "could not create new substance object.");
262  }
263  /*
264  * Calculate the molecular weight.
265  * hard coded to Cantera's elements and Water.
266  */
267  m_mw = 2 * 1.00794 + 15.9994;
268 
269  /*
270  * Set the baseline
271  */
272  doublereal T = 298.15;
273 
274  m_p0 = OneAtm;
275 
276  doublereal presLow = 1.0E-2;
277  doublereal oneBar = 1.0E5;
278  doublereal dens = 1.0E-9;
279  m_dens = m_sub->density(T, presLow, WATER_GAS, dens);
280  m_pres = presLow;
281  SW_Offset = 0.0;
282  doublereal s = entropy_mole();
283  s -= GasConstant * log(oneBar/presLow);
284  if (s != 188.835E3) {
285  SW_Offset = 188.835E3 - s;
286  }
287  s = entropy_mole();
288  s -= GasConstant * log(oneBar/presLow);
289  //printf("s = %g\n", s);
290 
291  doublereal h = enthalpy_mole();
292  if (h != -241.826E6) {
293  EW_Offset = -241.826E6 - h;
294  }
295  h = enthalpy_mole();
296  //printf("h = %g\n", h);
297 
298  /*
299  * Set the initial state of the system to 298.15 K and
300  * 1 bar.
301  */
302  setTemperature(298.15);
303  m_dens = m_sub->density(298.15, OneAtm, WATER_LIQUID);
304  m_pres = OneAtm;
305 }
306 
308 {
310 }
311 
312 void PDSS_Water::initThermoXML(const XML_Node& phaseNode, std::string& id)
313 {
314  PDSS::initThermoXML(phaseNode, id);
315 }
316 
317 doublereal PDSS_Water::enthalpy_mole() const
318 {
319  doublereal h = m_sub->enthalpy();
320  return (h + EW_Offset);
321 }
322 
323 doublereal PDSS_Water::intEnergy_mole() const
324 {
325  doublereal u = m_sub->intEnergy();
326  return (u + EW_Offset);
327 }
328 
329 doublereal PDSS_Water::entropy_mole() const
330 {
331  doublereal s = m_sub->entropy();
332  return (s + SW_Offset);
333 }
334 
335 doublereal PDSS_Water::gibbs_mole() const
336 {
337  doublereal g = m_sub->Gibbs();
338  return (g + EW_Offset - SW_Offset*m_temp);
339 }
340 
341 doublereal PDSS_Water::cp_mole() const
342 {
343  doublereal cp = m_sub->cp();
344  return cp;
345 }
346 
347 doublereal PDSS_Water::cv_mole() const
348 {
349  doublereal cv = m_sub->cv();
350  return cv;
351 }
352 
353 doublereal PDSS_Water::molarVolume() const
354 {
355  doublereal mv = m_sub->molarVolume();
356  return (mv);
357 }
358 
359 doublereal PDSS_Water::gibbs_RT_ref() const
360 {
361  doublereal T = m_temp;
362  m_sub->density(T, m_p0);
363  doublereal h = m_sub->enthalpy();
365  return ((h + EW_Offset - SW_Offset*T)/(T * GasConstant));
366 }
367 
368 doublereal PDSS_Water::enthalpy_RT_ref() const
369 {
370  doublereal T = m_temp;
371  m_sub->density(T, m_p0);
372  doublereal h = m_sub->enthalpy();
374  return ((h + EW_Offset)/(T * GasConstant));
375 }
376 
377 doublereal PDSS_Water::entropy_R_ref() const
378 {
379  doublereal T = m_temp;
380  m_sub->density(T, m_p0);
381  doublereal s = m_sub->entropy();
383  return ((s + SW_Offset)/GasConstant);
384 }
385 
386 doublereal PDSS_Water::cp_R_ref() const
387 {
388  doublereal T = m_temp;
389  m_sub->density(T, m_p0);
390  doublereal cp = m_sub->cp();
392  return (cp/GasConstant);
393 }
394 
395 doublereal PDSS_Water::molarVolume_ref() const
396 {
397  doublereal T = m_temp;
398  m_sub->density(T, m_p0);
399  doublereal mv = m_sub->molarVolume();
401  return (mv);
402 }
403 
404 
405 /**
406  * Calculate the pressure (Pascals), given the temperature and density
407  * Temperature: kelvin
408  * rho: density in kg m-3
409  */
410 doublereal PDSS_Water::pressure() const
411 {
412  doublereal p = m_sub->pressure();
413  m_pres = p;
414  return p;
415 }
416 
417 
418 // In this routine we must be sure to only find the water branch of the
419 // curve and not the gas branch
420 void PDSS_Water::setPressure(doublereal p)
421 {
422  doublereal T = m_temp;
423  doublereal dens = m_dens;
424  int waterState = WATER_LIQUID;
425  if (T > m_sub->Tcrit()) {
426  waterState = WATER_SUPERCRIT;
427  }
428 
429 
430 #ifdef DEBUG_HKM
431  //printf("waterPDSS: set pres = %g t = %g, waterState = %d\n",
432  // p, T, waterState);
433 #endif
434  doublereal dd = m_sub->density(T, p, waterState, dens);
435  if (dd <= 0.0) {
436  std::string stateString = "T = " +
437  fp2str(T) + " K and p = " + fp2str(p) + " Pa";
438  throw CanteraError("PDSS_Water:setPressure()",
439  "Failed to set water SS state: " + stateString);
440  }
441  m_dens = dd;
442  m_pres = p;
443 
444  // We are only putting the phase check here because of speed considerations.
445  m_iState = m_sub->phaseState(true);
446  if (! m_allowGasPhase) {
447  if (m_iState != WATER_SUPERCRIT && m_iState != WATER_LIQUID && m_iState != WATER_UNSTABLELIQUID) {
448  throw CanteraError("PDSS_Water::setPressure",
449  "Water State isn't liquid or crit");
450  }
451  }
452 }
453 
454 // Return the volumetric thermal expansion coefficient. Units: 1/K.
455 /*
456  * The thermal expansion coefficient is defined as
457  * \f[
458  * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
459  * \f]
460  */
462 {
463  doublereal val = m_sub->coeffThermExp();
464  return val;
465 }
466 
468 {
469  doublereal pres = pressure();
470  doublereal dens_save = m_dens;
471  doublereal tt = m_temp - 0.04;
472  doublereal dd = m_sub->density(tt, pres, m_iState, m_dens);
473  if (dd < 0.0) {
474  throw CanteraError("PDSS_Water::dthermalExpansionCoeffdT",
475  "unable to solve for the density at T = " + fp2str(tt) + ", P = " + fp2str(pres));
476  }
477  doublereal vald = m_sub->coeffThermExp();
478  m_sub->setState_TR(m_temp, dens_save);
479  doublereal val2 = m_sub->coeffThermExp();
480  doublereal val = (val2 - vald) / 0.04;
481  return val;
482 }
483 
485 {
486  doublereal val = m_sub->isothermalCompressibility();
487  return val;
488 }
489 
490 /// critical temperature
491 doublereal PDSS_Water::critTemperature() const
492 {
493  return m_sub->Tcrit();
494 }
495 
496 /// critical pressure
497 doublereal PDSS_Water::critPressure() const
498 {
499  return m_sub->Pcrit();
500 }
501 
502 /// critical density
503 doublereal PDSS_Water::critDensity() const
504 {
505  return m_sub->Rhocrit();
506 }
507 
508 void PDSS_Water::setDensity(doublereal dens)
509 {
510  m_dens = dens;
512 }
513 
514 doublereal PDSS_Water::density() const
515 {
516  return m_dens;
517 }
518 
519 void PDSS_Water::setTemperature(doublereal temp)
520 {
521  m_temp = temp;
522  doublereal dd = m_dens;
523  m_sub->setState_TR(temp, dd);
524 }
525 
526 void PDSS_Water::setState_TP(doublereal temp, doublereal pres)
527 {
528  m_temp = temp;
529  setPressure(pres);
530 }
531 
532 void PDSS_Water::setState_TR(doublereal temp, doublereal dens)
533 {
534  m_temp = temp;
535  m_dens = dens;
537 }
538 
539 doublereal PDSS_Water::pref_safe(doublereal temp) const
540 {
541  if (temp < m_sub->Tcrit()) {
542  doublereal pp = m_sub->psat_est(temp);
543  if (pp > OneAtm) {
544  return pp;
545  }
546  } else {
547  return m_sub->Pcrit();
548  }
549  return OneAtm;
550 }
551 
552 // saturation pressure
553 doublereal PDSS_Water::satPressure(doublereal t)
554 {
555  doublereal pp = m_sub->psat(t, WATER_LIQUID);
556  m_dens = m_sub->density();
557  m_temp = t;
558  return pp;
559 }
560 
561 }