Cantera  2.1.2
HMWSoln_input.cpp
Go to the documentation of this file.
1 /**
2  * @file HMWSoln_input.cpp
3  * Definitions for the %HMWSoln ThermoPhase object, which models concentrated
4  * electrolyte solutions
5  * (see \ref thermoprops and \link Cantera::HMWSoln HMWSoln \endlink) .
6  *
7  * This file contains definitions for reading in the interaction terms
8  * in the formulation.
9  */
10 /*
11  * Copyright (2006) Sandia Corporation. Under the terms of
12  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
13  * U.S. Government retains certain rights in this software.
14  */
15 #include "cantera/thermo/HMWSoln.h"
20 
21 #include <fstream>
22 
23 using namespace std;
24 using namespace ctml;
25 
26 namespace Cantera
27 {
28 int HMWSoln::interp_est(const std::string& estString)
29 {
30  const char* cc = estString.c_str();
31  string lcs = lowercase(estString);
32  const char* ccl = lcs.c_str();
33  if (!strcmp(ccl, "solvent")) {
34  return cEST_solvent;
35  } else if (!strcmp(ccl, "chargedspecies")) {
36  return cEST_chargedSpecies;
37  } else if (!strcmp(ccl, "weakacidassociated")) {
38  return cEST_weakAcidAssociated;
39  } else if (!strcmp(ccl, "strongacidassociated")) {
40  return cEST_strongAcidAssociated;
41  } else if (!strcmp(ccl, "polarneutral")) {
42  return cEST_polarNeutral;
43  } else if (!strcmp(ccl, "nonpolarneutral")) {
44  return cEST_nonpolarNeutral;
45  }
46  int retn, rval;
47  if ((retn = sscanf(cc, "%d", &rval)) != 1) {
48  return -1;
49  }
50  return rval;
51 }
52 
53 void HMWSoln::readXMLBinarySalt(XML_Node& BinSalt)
54 {
55  string xname = BinSalt.name();
56  if (xname != "binarySaltParameters") {
57  throw CanteraError("HMWSoln::readXMLBinarySalt",
58  "Incorrect name for processing this routine: " + xname);
59  }
60  string stemp;
61  size_t nParamsFound, i;
62  vector_fp vParams;
63  string iName = BinSalt.attrib("cation");
64  if (iName == "") {
65  throw CanteraError("HMWSoln::readXMLBinarySalt", "no cation attrib");
66  }
67  string jName = BinSalt.attrib("anion");
68  if (jName == "") {
69  throw CanteraError("HMWSoln::readXMLBinarySalt", "no anion attrib");
70  }
71  /*
72  * Find the index of the species in the current phase. It's not
73  * an error to not find the species
74  */
75  size_t iSpecies = speciesIndex(iName);
76  if (iSpecies == npos) {
77  return;
78  }
79  string ispName = speciesName(iSpecies);
80  if (charge(iSpecies) <= 0) {
81  throw CanteraError("HMWSoln::readXMLBinarySalt", "cation charge problem");
82  }
83  size_t jSpecies = speciesIndex(jName);
84  if (jSpecies == npos) {
85  return;
86  }
87  string jspName = speciesName(jSpecies);
88  if (charge(jSpecies) >= 0) {
89  throw CanteraError("HMWSoln::readXMLBinarySalt", "anion charge problem");
90  }
91 
92  size_t n = iSpecies * m_kk + jSpecies;
93  int counter = m_CounterIJ[n];
94  for (size_t iChild = 0; iChild < BinSalt.nChildren(); iChild++) {
95  XML_Node& xmlChild = BinSalt.child(iChild);
96  stemp = xmlChild.name();
97  string nodeName = lowercase(stemp);
98  /*
99  * Process the binary salt child elements
100  */
101  if (nodeName == "beta0") {
102  /*
103  * Get the string containing all of the values
104  */
105  getFloatArray(xmlChild, vParams, false, "", "beta0");
106  nParamsFound = vParams.size();
107  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
108  if (nParamsFound != 1) {
109  throw CanteraError("HMWSoln::readXMLBinarySalt::beta0 for " + ispName
110  + "::" + jspName,
111  "wrong number of params found");
112  }
113  m_Beta0MX_ij[counter] = vParams[0];
114  m_Beta0MX_ij_coeff(0,counter) = m_Beta0MX_ij[counter];
115  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
116  if (nParamsFound != 2) {
117  throw CanteraError("HMWSoln::readXMLBinarySalt::beta0 for " + ispName
118  + "::" + jspName,
119  "wrong number of params found");
120  }
121  m_Beta0MX_ij_coeff(0,counter) = vParams[0];
122  m_Beta0MX_ij_coeff(1,counter) = vParams[1];
123  m_Beta0MX_ij[counter] = vParams[0];
124  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
125  if (nParamsFound != 5) {
126  throw CanteraError("HMWSoln::readXMLBinarySalt::beta0 for " + ispName
127  + "::" + jspName,
128  "wrong number of params found");
129  }
130  for (i = 0; i < nParamsFound; i++) {
131  m_Beta0MX_ij_coeff(i, counter) = vParams[i];
132  }
133  m_Beta0MX_ij[counter] = vParams[0];
134  }
135  }
136  if (nodeName == "beta1") {
137 
138  /*
139  * Get the string containing all of the values
140  */
141  getFloatArray(xmlChild, vParams, false, "", "beta1");
142  nParamsFound = vParams.size();
143  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
144  if (nParamsFound != 1) {
145  throw CanteraError("HMWSoln::readXMLBinarySalt::beta1 for " + ispName
146  + "::" + jspName,
147  "wrong number of params found");
148  }
149  m_Beta1MX_ij[counter] = vParams[0];
150  m_Beta1MX_ij_coeff(0,counter) = m_Beta1MX_ij[counter];
151  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
152  if (nParamsFound != 2) {
153  throw CanteraError("HMWSoln::readXMLBinarySalt::beta1 for " + ispName
154  + "::" + jspName,
155  "wrong number of params found");
156  }
157  m_Beta1MX_ij_coeff(0,counter) = vParams[0];
158  m_Beta1MX_ij_coeff(1,counter) = vParams[1];
159  m_Beta1MX_ij[counter] = vParams[0];
160  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
161  if (nParamsFound != 5) {
162  throw CanteraError("HMWSoln::readXMLBinarySalt::beta1 for " + ispName
163  + "::" + jspName,
164  "wrong number of params found");
165  }
166  for (i = 0; i < nParamsFound; i++) {
167  m_Beta1MX_ij_coeff(i, counter) = vParams[i];
168  }
169  m_Beta1MX_ij[counter] = vParams[0];
170  }
171  }
172  if (nodeName == "beta2") {
173  getFloatArray(xmlChild, vParams, false, "", "beta2");
174  nParamsFound = vParams.size();
175  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
176  if (nParamsFound != 1) {
177  throw CanteraError("HMWSoln::readXMLBinarySalt::beta2 for " + ispName
178  + "::" + jspName,
179  "wrong number of params found");
180  }
181  m_Beta2MX_ij[counter] = vParams[0];
182  m_Beta2MX_ij_coeff(0,counter) = m_Beta2MX_ij[counter];
183  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
184  if (nParamsFound != 2) {
185  throw CanteraError("HMWSoln::readXMLBinarySalt::beta2 for " + ispName
186  + "::" + jspName,
187  "wrong number of params found");
188  }
189  m_Beta2MX_ij_coeff(0,counter) = vParams[0];
190  m_Beta2MX_ij_coeff(1,counter) = vParams[1];
191  m_Beta2MX_ij[counter] = vParams[0];
192  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
193  if (nParamsFound != 5) {
194  throw CanteraError("HMWSoln::readXMLBinarySalt::beta2 for " + ispName
195  + "::" + jspName,
196  "wrong number of params found");
197  }
198  for (i = 0; i < nParamsFound; i++) {
199  m_Beta2MX_ij_coeff(i, counter) = vParams[i];
200  }
201  m_Beta2MX_ij[counter] = vParams[0];
202  }
203 
204  }
205  if (nodeName == "cphi") {
206  /*
207  * Get the string containing all of the values
208  */
209  getFloatArray(xmlChild, vParams, false, "", "Cphi");
210  nParamsFound = vParams.size();
211  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
212  if (nParamsFound != 1) {
213  throw CanteraError("HMWSoln::readXMLBinarySalt::Cphi for " + ispName
214  + "::" + jspName,
215  "wrong number of params found");
216  }
217  m_CphiMX_ij[counter] = vParams[0];
218  m_CphiMX_ij_coeff(0,counter) = m_CphiMX_ij[counter];
219  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
220  if (nParamsFound != 2) {
221  throw CanteraError("HMWSoln::readXMLBinarySalt::Cphi for " + ispName
222  + "::" + jspName,
223  "wrong number of params found");
224  }
225  m_CphiMX_ij_coeff(0,counter) = vParams[0];
226  m_CphiMX_ij_coeff(1,counter) = vParams[1];
227  m_CphiMX_ij[counter] = vParams[0];
228  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
229  if (nParamsFound != 5) {
230  throw CanteraError("HMWSoln::readXMLBinarySalt::Cphi for " + ispName
231  + "::" + jspName,
232  "wrong number of params found");
233  }
234  for (i = 0; i < nParamsFound; i++) {
235  m_CphiMX_ij_coeff(i, counter) = vParams[i];
236  }
237  m_CphiMX_ij[counter] = vParams[0];
238  }
239  }
240 
241  if (nodeName == "alpha1") {
242  stemp = xmlChild.value();
243  m_Alpha1MX_ij[counter] = fpValueCheck(stemp);
244  }
245 
246  if (nodeName == "alpha2") {
247  stemp = xmlChild.value();
248  m_Alpha2MX_ij[counter] = fpValueCheck(stemp);
249  }
250  }
251 }
252 
253 void HMWSoln::readXMLThetaAnion(XML_Node& BinSalt)
254 {
255  string xname = BinSalt.name();
256  vector_fp vParams;
257  size_t nParamsFound = 0;
258  if (xname != "thetaAnion") {
259  throw CanteraError("HMWSoln::readXMLThetaAnion",
260  "Incorrect name for processing this routine: " + xname);
261  }
262  string stemp;
263  string ispName = BinSalt.attrib("anion1");
264  if (ispName == "") {
265  throw CanteraError("HMWSoln::readXMLThetaAnion", "no anion1 attrib");
266  }
267  string jspName = BinSalt.attrib("anion2");
268  if (jspName == "") {
269  throw CanteraError("HMWSoln::readXMLThetaAnion", "no anion2 attrib");
270  }
271  /*
272  * Find the index of the species in the current phase. It's not
273  * an error to not find the species
274  */
275  size_t iSpecies = speciesIndex(ispName);
276  if (iSpecies == npos) {
277  return;
278  }
279  if (charge(iSpecies) >= 0) {
280  throw CanteraError("HMWSoln::readXMLThetaAnion", "anion1 charge problem");
281  }
282  size_t jSpecies = speciesIndex(jspName);
283  if (jSpecies == npos) {
284  return;
285  }
286  if (charge(jSpecies) >= 0) {
287  throw CanteraError("HMWSoln::readXMLThetaAnion", "anion2 charge problem");
288  }
289 
290  size_t n = iSpecies * m_kk + jSpecies;
291  int counter = m_CounterIJ[n];
292  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
293  XML_Node& xmlChild = BinSalt.child(i);
294  stemp = xmlChild.name();
295  string nodeName = lowercase(stemp);
296  if (nodeName == "theta") {
297  getFloatArray(xmlChild, vParams, false, "", stemp);
298  nParamsFound = vParams.size();
299  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
300  if (nParamsFound != 1) {
301  throw CanteraError("HMWSoln::readXMLThetaAnion::Theta for " + ispName
302  + "::" + jspName,
303  "wrong number of params found");
304  }
305  m_Theta_ij_coeff(0,counter) = vParams[0];
306  m_Theta_ij[counter] = vParams[0];
307  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
308  if (nParamsFound != 2) {
309  throw CanteraError("HMWSoln::readXMLThetaAnion::Theta for " + ispName
310  + "::" + jspName,
311  "wrong number of params found");
312  }
313  m_Theta_ij_coeff(0,counter) = vParams[0];
314  m_Theta_ij_coeff(1,counter) = vParams[1];
315  m_Theta_ij[counter] = vParams[0];
316  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
317  if (nParamsFound == 1) {
318  vParams.resize(5, 0.0);
319  nParamsFound = 5;
320  } else if (nParamsFound != 5) {
321  throw CanteraError("HMWSoln::readXMLThetaAnion::Theta for " + ispName
322  + "::" + jspName,
323  "wrong number of params found");
324  }
325  for (size_t j = 0; j < nParamsFound; j++) {
326  m_Theta_ij_coeff(j, counter) = vParams[j];
327  }
328  m_Theta_ij[counter] = vParams[0];
329  }
330  }
331  }
332 }
333 
334 void HMWSoln::readXMLThetaCation(XML_Node& BinSalt)
335 {
336  string xname = BinSalt.name();
337  vector_fp vParams;
338  size_t nParamsFound = 0;
339  if (xname != "thetaCation") {
340  throw CanteraError("HMWSoln::readXMLThetaCation",
341  "Incorrect name for processing this routine: " + xname);
342  }
343  string stemp;
344  string ispName = BinSalt.attrib("cation1");
345  if (ispName == "") {
346  throw CanteraError("HMWSoln::readXMLThetaCation", "no cation1 attrib");
347  }
348  string jspName = BinSalt.attrib("cation2");
349  if (jspName == "") {
350  throw CanteraError("HMWSoln::readXMLThetaCation", "no cation2 attrib");
351  }
352  /*
353  * Find the index of the species in the current phase. It's not
354  * an error to not find the species
355  */
356  size_t iSpecies = speciesIndex(ispName);
357  if (iSpecies == npos) {
358  return;
359  }
360  if (charge(iSpecies) <= 0) {
361  throw CanteraError("HMWSoln::readXMLThetaCation", "cation1 charge problem");
362  }
363  size_t jSpecies = speciesIndex(jspName);
364  if (jSpecies == npos) {
365  return;
366  }
367  if (charge(jSpecies) <= 0) {
368  throw CanteraError("HMWSoln::readXMLThetaCation", "cation2 charge problem");
369  }
370 
371  size_t n = iSpecies * m_kk + jSpecies;
372  int counter = m_CounterIJ[n];
373  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
374  XML_Node& xmlChild = BinSalt.child(i);
375  stemp = xmlChild.name();
376  string nodeName = lowercase(stemp);
377  if (nodeName == "theta") {
378  getFloatArray(xmlChild, vParams, false, "", stemp);
379  nParamsFound = vParams.size();
380  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
381  if (nParamsFound != 1) {
382  throw CanteraError("HMWSoln::readXMLThetaCation::Theta for " + ispName
383  + "::" + jspName,
384  "wrong number of params found");
385  }
386  m_Theta_ij_coeff(0,counter) = vParams[0];
387  m_Theta_ij[counter] = vParams[0];
388  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
389  if (nParamsFound != 2) {
390  throw CanteraError("HMWSoln::readXMLThetaCation::Theta for " + ispName
391  + "::" + jspName,
392  "wrong number of params found");
393  }
394  m_Theta_ij_coeff(0,counter) = vParams[0];
395  m_Theta_ij_coeff(1,counter) = vParams[1];
396  m_Theta_ij[counter] = vParams[0];
397  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
398  if (nParamsFound == 1) {
399  vParams.resize(5, 0.0);
400  nParamsFound = 5;
401  } else if (nParamsFound != 5) {
402  throw CanteraError("HMWSoln::readXMLThetaCation::Theta for " + ispName
403  + "::" + jspName,
404  "wrong number of params found");
405  }
406  for (size_t j = 0; j < nParamsFound; j++) {
407  m_Theta_ij_coeff(j, counter) = vParams[j];
408  }
409  m_Theta_ij[counter] = vParams[0];
410  }
411  }
412  }
413 }
414 
415 void HMWSoln::readXMLPsiCommonCation(XML_Node& BinSalt)
416 {
417  string xname = BinSalt.name();
418  if (xname != "psiCommonCation") {
419  throw CanteraError("HMWSoln::readXMLPsiCommonCation",
420  "Incorrect name for processing this routine: " + xname);
421  }
422  string stemp;
423  vector_fp vParams;
424  size_t nParamsFound = 0;
425  string kName = BinSalt.attrib("cation");
426  if (kName == "") {
427  throw CanteraError("HMWSoln::readXMLPsiCommonCation", "no cation attrib");
428  }
429  string iName = BinSalt.attrib("anion1");
430  if (iName == "") {
431  throw CanteraError("HMWSoln::readXMLPsiCommonCation", "no anion1 attrib");
432  }
433  string jName = BinSalt.attrib("anion2");
434  if (jName == "") {
435  throw CanteraError("HMWSoln::readXMLPsiCommonCation", "no anion2 attrib");
436  }
437  /*
438  * Find the index of the species in the current phase. It's not
439  * an error to not find the species
440  */
441  size_t kSpecies = speciesIndex(kName);
442  if (kSpecies == npos) {
443  return;
444  }
445  if (charge(kSpecies) <= 0) {
446  throw CanteraError("HMWSoln::readXMLPsiCommonCation",
447  "cation charge problem");
448  }
449  size_t iSpecies = speciesIndex(iName);
450  if (iSpecies == npos) {
451  return;
452  }
453  if (charge(iSpecies) >= 0) {
454  throw CanteraError("HMWSoln::readXMLPsiCommonCation",
455  "anion1 charge problem");
456  }
457  size_t jSpecies = speciesIndex(jName);
458  if (jSpecies == npos) {
459  return;
460  }
461  if (charge(jSpecies) >= 0) {
462  throw CanteraError("HMWSoln::readXMLPsiCommonCation",
463  "anion2 charge problem");
464  }
465 
466  size_t n = iSpecies * m_kk + jSpecies;
467  int counter = m_CounterIJ[n];
468  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
469  XML_Node& xmlChild = BinSalt.child(i);
470  stemp = xmlChild.name();
471  string nodeName = lowercase(stemp);
472  if (nodeName == "theta") {
473  stemp = xmlChild.value();
474  double old = m_Theta_ij[counter];
475  m_Theta_ij[counter] = fpValueCheck(stemp);
476  if (old != 0.0) {
477  if (old != m_Theta_ij[counter]) {
478  throw CanteraError("HMWSoln::readXMLPsiCommonCation",
479  "conflicting values");
480  }
481  }
482  }
483  if (nodeName == "psi") {
484  getFloatArray(xmlChild, vParams, false, "", stemp);
485  nParamsFound = vParams.size();
486  n = iSpecies * m_kk *m_kk + jSpecies * m_kk + kSpecies ;
487 
488  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
489  if (nParamsFound != 1) {
490  throw CanteraError("HMWSoln::readXMLPsiCommonCation::Psi for "
491  + kName + "::" + iName + "::" + jName,
492  "wrong number of params found");
493  }
494  m_Psi_ijk_coeff(0,n) = vParams[0];
495  m_Psi_ijk[n] = vParams[0];
496  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
497  if (nParamsFound != 2) {
498  throw CanteraError("HMWSoln::readXMLPsiCation::Psi for "
499  + kName + "::" + iName + "::" + jName,
500  "wrong number of params found");
501  }
502  m_Psi_ijk_coeff(0,n) = vParams[0];
503  m_Psi_ijk_coeff(1,n) = vParams[1];
504  m_Psi_ijk[n] = vParams[0];
505  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
506  if (nParamsFound == 1) {
507  vParams.resize(5, 0.0);
508  nParamsFound = 5;
509  } else if (nParamsFound != 5) {
510  throw CanteraError("HMWSoln::readXMLPsiCation::Psi for "
511  + kName + "::" + iName + "::" + jName,
512  "wrong number of params found");
513  }
514  for (size_t j = 0; j < nParamsFound; j++) {
515  m_Psi_ijk_coeff(j, n) = vParams[j];
516  }
517  m_Psi_ijk[n] = vParams[0];
518  }
519 
520 
521  // fill in the duplicate entries
522  n = iSpecies * m_kk *m_kk + kSpecies * m_kk + jSpecies ;
523  for (size_t j = 0; j < nParamsFound; j++) {
524  m_Psi_ijk_coeff(j, n) = vParams[j];
525  }
526  m_Psi_ijk[n] = vParams[0];
527 
528  n = jSpecies * m_kk *m_kk + iSpecies * m_kk + kSpecies ;
529  for (size_t j = 0; j < nParamsFound; j++) {
530  m_Psi_ijk_coeff(j, n) = vParams[j];
531  }
532  m_Psi_ijk[n] = vParams[0];
533 
534  n = jSpecies * m_kk *m_kk + kSpecies * m_kk + iSpecies ;
535  for (size_t j = 0; j < nParamsFound; j++) {
536  m_Psi_ijk_coeff(j, n) = vParams[j];
537  }
538  m_Psi_ijk[n] = vParams[0];
539 
540  n = kSpecies * m_kk *m_kk + jSpecies * m_kk + iSpecies ;
541  for (size_t j = 0; j < nParamsFound; j++) {
542  m_Psi_ijk_coeff(j, n) = vParams[j];
543  }
544  m_Psi_ijk[n] = vParams[0];
545 
546  n = kSpecies * m_kk *m_kk + iSpecies * m_kk + jSpecies ;
547  for (size_t j = 0; j < nParamsFound; j++) {
548  m_Psi_ijk_coeff(j, n) = vParams[j];
549  }
550  m_Psi_ijk[n] = vParams[0];
551  }
552  }
553 }
554 
555 void HMWSoln::readXMLPsiCommonAnion(XML_Node& BinSalt)
556 {
557  string xname = BinSalt.name();
558  if (xname != "psiCommonAnion") {
559  throw CanteraError("HMWSoln::readXMLPsiCommonAnion",
560  "Incorrect name for processing this routine: " + xname);
561  }
562  string stemp;
563  vector_fp vParams;
564  size_t nParamsFound = 0;
565  string kName = BinSalt.attrib("anion");
566  if (kName == "") {
567  throw CanteraError("HMWSoln::readXMLPsiCommonAnion", "no anion attrib");
568  }
569  string iName = BinSalt.attrib("cation1");
570  if (iName == "") {
571  throw CanteraError("HMWSoln::readXMLPsiCommonAnion", "no cation1 attrib");
572  }
573  string jName = BinSalt.attrib("cation2");
574  if (jName == "") {
575  throw CanteraError("HMWSoln::readXMLPsiCommonAnion", "no cation2 attrib");
576  }
577  /*
578  * Find the index of the species in the current phase. It's not
579  * an error to not find the species
580  */
581  size_t kSpecies = speciesIndex(kName);
582  if (kSpecies == npos) {
583  return;
584  }
585  if (charge(kSpecies) >= 0) {
586  throw CanteraError("HMWSoln::readXMLPsiCommonAnion", "anion charge problem");
587  }
588  size_t iSpecies = speciesIndex(iName);
589  if (iSpecies == npos) {
590  return;
591  }
592  if (charge(iSpecies) <= 0) {
593  throw CanteraError("HMWSoln::readXMLPsiCommonAnion",
594  "cation1 charge problem");
595  }
596  size_t jSpecies = speciesIndex(jName);
597  if (jSpecies == npos) {
598  return;
599  }
600  if (charge(jSpecies) <= 0) {
601  throw CanteraError("HMWSoln::readXMLPsiCommonAnion",
602  "cation2 charge problem");
603  }
604 
605  size_t n = iSpecies * m_kk + jSpecies;
606  int counter = m_CounterIJ[n];
607  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
608  XML_Node& xmlChild = BinSalt.child(i);
609  stemp = xmlChild.name();
610  string nodeName = lowercase(stemp);
611  if (nodeName == "theta") {
612  stemp = xmlChild.value();
613  double old = m_Theta_ij[counter];
614  m_Theta_ij[counter] = fpValueCheck(stemp);
615  if (old != 0.0) {
616  if (old != m_Theta_ij[counter]) {
617  throw CanteraError("HMWSoln::readXMLPsiCommonAnion",
618  "conflicting values");
619  }
620  }
621  }
622  if (nodeName == "psi") {
623 
624  getFloatArray(xmlChild, vParams, false, "", stemp);
625  nParamsFound = vParams.size();
626  n = iSpecies * m_kk *m_kk + jSpecies * m_kk + kSpecies ;
627 
628  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
629  if (nParamsFound != 1) {
630  throw CanteraError("HMWSoln::readXMLPsiCommonAnion::Psi for "
631  + kName + "::" + iName + "::" + jName,
632  "wrong number of params found");
633  }
634  m_Psi_ijk_coeff(0,n) = vParams[0];
635  m_Psi_ijk[n] = vParams[0];
636  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
637  if (nParamsFound != 2) {
638  throw CanteraError("HMWSoln::readXMLPsiAnion::Psi for "
639  + kName + "::" + iName + "::" + jName,
640  "wrong number of params found");
641  }
642  m_Psi_ijk_coeff(0,n) = vParams[0];
643  m_Psi_ijk_coeff(1,n) = vParams[1];
644  m_Psi_ijk[n] = vParams[0];
645  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
646  if (nParamsFound == 1) {
647  vParams.resize(5, 0.0);
648  nParamsFound = 5;
649  } else if (nParamsFound != 5) {
650  throw CanteraError("HMWSoln::readXMLPsiAnion::Psi for "
651  + kName + "::" + iName + "::" + jName,
652  "wrong number of params found");
653  }
654  for (size_t j = 0; j < nParamsFound; j++) {
655  m_Psi_ijk_coeff(j, n) = vParams[j];
656  }
657  m_Psi_ijk[n] = vParams[0];
658  }
659 
660 
661  // fill in the duplicate entries
662  n = iSpecies * m_kk *m_kk + kSpecies * m_kk + jSpecies ;
663  for (size_t j = 0; j < nParamsFound; j++) {
664  m_Psi_ijk_coeff(j, n) = vParams[j];
665  }
666  m_Psi_ijk[n] = vParams[0];
667 
668  n = jSpecies * m_kk *m_kk + iSpecies * m_kk + kSpecies ;
669  for (size_t j = 0; j < nParamsFound; j++) {
670  m_Psi_ijk_coeff(j, n) = vParams[j];
671  }
672  m_Psi_ijk[n] = vParams[0];
673 
674  n = jSpecies * m_kk *m_kk + kSpecies * m_kk + iSpecies ;
675  for (size_t j = 0; j < nParamsFound; j++) {
676  m_Psi_ijk_coeff(j, n) = vParams[j];
677  }
678  m_Psi_ijk[n] = vParams[0];
679 
680  n = kSpecies * m_kk *m_kk + jSpecies * m_kk + iSpecies ;
681  for (size_t j = 0; j < nParamsFound; j++) {
682  m_Psi_ijk_coeff(j, n) = vParams[j];
683  }
684  m_Psi_ijk[n] = vParams[0];
685 
686  n = kSpecies * m_kk *m_kk + iSpecies * m_kk + jSpecies ;
687  for (size_t j = 0; j < nParamsFound; j++) {
688  m_Psi_ijk_coeff(j, n) = vParams[j];
689  }
690  m_Psi_ijk[n] = vParams[0];
691 
692  }
693  }
694 }
695 
696 void HMWSoln::readXMLLambdaNeutral(XML_Node& BinSalt)
697 {
698  string xname = BinSalt.name();
699  vector_fp vParams;
700  size_t nParamsFound;
701  if (xname != "lambdaNeutral") {
702  throw CanteraError("HMWSoln::readXMLLanbdaNeutral",
703  "Incorrect name for processing this routine: " + xname);
704  }
705  string stemp;
706  string iName = BinSalt.attrib("species1");
707  if (iName == "") {
708  throw CanteraError("HMWSoln::readXMLLambdaNeutral", "no species1 attrib");
709  }
710  string jName = BinSalt.attrib("species2");
711  if (jName == "") {
712  throw CanteraError("HMWSoln::readXMLLambdaNeutral", "no species2 attrib");
713  }
714  /*
715  * Find the index of the species in the current phase. It's not
716  * an error to not find the species
717  */
718  size_t iSpecies = speciesIndex(iName);
719  if (iSpecies == npos) {
720  return;
721  }
722  if (charge(iSpecies) != 0) {
723  throw CanteraError("HMWSoln::readXMLLambdaNeutral",
724  "neutral charge problem");
725  }
726  size_t jSpecies = speciesIndex(jName);
727  if (jSpecies == npos) {
728  return;
729  }
730 
731  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
732  XML_Node& xmlChild = BinSalt.child(i);
733  stemp = xmlChild.name();
734  string nodeName = lowercase(stemp);
735  if (nodeName == "lambda") {
736  size_t nCount = iSpecies*m_kk + jSpecies;
737  getFloatArray(xmlChild, vParams, false, "", stemp);
738  nParamsFound = vParams.size();
739  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
740  if (nParamsFound != 1) {
741  throw CanteraError("HMWSoln::readXMLLambdaNeutral::Lambda for " + iName
742  + "::" + jName,
743  "wrong number of params found");
744  }
745  m_Lambda_nj_coeff(0,nCount) = vParams[0];
746  m_Lambda_nj(iSpecies,jSpecies) = vParams[0];
747 
748  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
749  if (nParamsFound != 2) {
750  throw CanteraError("HMWSoln::readXMLLambdaNeutral::Lambda for " + iName
751  + "::" + jName,
752  "wrong number of params found");
753  }
754  m_Lambda_nj_coeff(0,nCount) = vParams[0];
755  m_Lambda_nj_coeff(1,nCount) = vParams[1];
756  m_Lambda_nj(iSpecies, jSpecies) = vParams[0];
757 
758  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
759  if (nParamsFound == 1) {
760  vParams.resize(5, 0.0);
761  nParamsFound = 5;
762  } else if (nParamsFound != 5) {
763  throw CanteraError("HMWSoln::readXMLLambdaNeutral::Lambda for " + iName
764  + "::" + jName,
765  "wrong number of params found");
766  }
767  for (size_t j = 0; j < nParamsFound; j++) {
768  m_Lambda_nj_coeff(j,nCount) = vParams[j];
769  }
770  m_Lambda_nj(iSpecies, jSpecies) = vParams[0];
771  }
772  }
773  }
774 }
775 
776 void HMWSoln::readXMLMunnnNeutral(XML_Node& BinSalt)
777 {
778  string xname = BinSalt.name();
779  vector_fp vParams;
780  size_t nParamsFound;
781  if (xname != "MunnnNeutral") {
782  throw CanteraError("HMWSoln::readXMLMunnnNeutral",
783  "Incorrect name for processing this routine: " + xname);
784  }
785  string stemp;
786  string iName = BinSalt.attrib("species1");
787  if (iName == "") {
788  throw CanteraError("HMWSoln::readXMLMunnnNeutral", "no species1 attrib");
789  }
790 
791  /*
792  * Find the index of the species in the current phase. It's not
793  * an error to not find the species
794  */
795  size_t iSpecies = speciesIndex(iName);
796  if (iSpecies == npos) {
797  return;
798  }
799  if (charge(iSpecies) != 0) {
800  throw CanteraError("HMWSoln::readXMLMunnnNeutral",
801  "neutral charge problem");
802  }
803 
804  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
805  XML_Node& xmlChild = BinSalt.child(i);
806  stemp = xmlChild.name();
807  string nodeName = lowercase(stemp);
808  if (nodeName == "munnn") {
809  getFloatArray(xmlChild, vParams, false, "", "Munnn");
810  nParamsFound = vParams.size();
811  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
812  if (nParamsFound != 1) {
813  throw CanteraError("HMWSoln::readXMLMunnnNeutral::Munnn for " + iName,
814  "wrong number of params found");
815  }
816  m_Mu_nnn_coeff(0,iSpecies) = vParams[0];
817  m_Mu_nnn[iSpecies] = vParams[0];
818 
819  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
820  if (nParamsFound != 2) {
821  throw CanteraError("HMWSoln::readXMLMunnnNeutral::Munnn for " + iName,
822  "wrong number of params found");
823  }
824  m_Mu_nnn_coeff(0, iSpecies) = vParams[0];
825  m_Mu_nnn_coeff(1, iSpecies) = vParams[1];
826  m_Mu_nnn[iSpecies] = vParams[0];
827 
828  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
829  if (nParamsFound == 1) {
830  vParams.resize(5, 0.0);
831  nParamsFound = 5;
832  } else if (nParamsFound != 5) {
833  throw CanteraError("HMWSoln::readXMLMunnnNeutral::Munnn for " + iName,
834  "wrong number of params found");
835  }
836  for (size_t j = 0; j < nParamsFound; j++) {
837  m_Mu_nnn_coeff(j, iSpecies) = vParams[j];
838  }
839  m_Mu_nnn[iSpecies] = vParams[0];
840  }
841  }
842  }
843 }
844 
845 void HMWSoln::readXMLZetaCation(const XML_Node& BinSalt)
846 {
847  string xname = BinSalt.name();
848  if (xname != "zetaCation") {
849  throw CanteraError("HMWSoln::readXMLZetaCation",
850  "Incorrect name for processing this routine: " + xname);
851  }
852  string stemp;
853  vector_fp vParams;
854  size_t nParamsFound = 0;
855 
856  string iName = BinSalt.attrib("neutral");
857  if (iName == "") {
858  throw CanteraError("HMWSoln::readXMLZetaCation", "no neutral attrib");
859  }
860 
861  string jName = BinSalt.attrib("cation1");
862  if (jName == "") {
863  throw CanteraError("HMWSoln::readXMLZetaCation", "no cation1 attrib");
864  }
865 
866  string kName = BinSalt.attrib("anion1");
867  if (kName == "") {
868  throw CanteraError("HMWSoln::readXMLZetaCation", "no anion1 attrib");
869  }
870  /*
871  * Find the index of the species in the current phase. It's not
872  * an error to not find the species
873  */
874  size_t iSpecies = speciesIndex(iName);
875  if (iSpecies == npos) {
876  return;
877  }
878  if (charge(iSpecies) != 0.0) {
879  throw CanteraError("HMWSoln::readXMLZetaCation", "neutral charge problem");
880  }
881 
882  size_t jSpecies = speciesIndex(jName);
883  if (jSpecies == npos) {
884  return;
885  }
886  if (charge(jSpecies) <= 0.0) {
887  throw CanteraError("HMWSoln::readXLZetaCation", "cation1 charge problem");
888  }
889 
890  size_t kSpecies = speciesIndex(kName);
891  if (kSpecies == npos) {
892  return;
893  }
894  if (charge(kSpecies) >= 0.0) {
895  throw CanteraError("HMWSoln::readXMLZetaCation", "anion1 charge problem");
896  }
897 
898  for (size_t i = 0; i < BinSalt.nChildren(); i++) {
899  XML_Node& xmlChild = BinSalt.child(i);
900  stemp = xmlChild.name();
901  string nodeName = lowercase(stemp);
902  if (nodeName == "zeta") {
903  getFloatArray(xmlChild, vParams, false, "", "zeta");
904  nParamsFound = vParams.size();
905  size_t n = iSpecies * m_kk *m_kk + jSpecies * m_kk + kSpecies ;
906 
907  if (m_formPitzerTemp == PITZER_TEMP_CONSTANT) {
908  if (nParamsFound != 1) {
909  throw CanteraError("HMWSoln::readXMLZetaCation::Zeta for "
910  + iName + "::" + jName + "::" + kName,
911  "wrong number of params found");
912  }
913  m_Psi_ijk_coeff(0,n) = vParams[0];
914  m_Psi_ijk[n] = vParams[0];
915  } else if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
916  if (nParamsFound != 2) {
917  throw CanteraError("HMWSoln::readXMLZetaCation::Zeta for "
918  + iName + "::" + jName + "::" + kName,
919  "wrong number of params found");
920  }
921  m_Psi_ijk_coeff(0,n) = vParams[0];
922  m_Psi_ijk_coeff(1,n) = vParams[1];
923  m_Psi_ijk[n] = vParams[0];
924  } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
925  if (nParamsFound == 1) {
926  vParams.resize(5, 0.0);
927  nParamsFound = 5;
928  } else if (nParamsFound != 5) {
929  throw CanteraError("HMWSoln::readXMLZetaCation::Zeta for "
930  + iName + "::" + jName + "::" + kName,
931  "wrong number of params found");
932  }
933  for (size_t j = 0; j < nParamsFound; j++) {
934  m_Psi_ijk_coeff(j, n) = vParams[j];
935  }
936  m_Psi_ijk[n] = vParams[0];
937  }
938 
939  // There are no duplicate entries
940  }
941  }
942 }
943 
944 void HMWSoln::readXMLCroppingCoefficients(const XML_Node& acNode)
945 {
946 
947  if (acNode.hasChild("croppingCoefficients")) {
948  XML_Node& cropNode = acNode.child("croppingCoefficients");
949  if (cropNode.hasChild("ln_gamma_k_min")) {
950  XML_Node& gkminNode = cropNode.child("ln_gamma_k_min");
951  getOptionalFloat(gkminNode, "pureSolventValue", CROP_ln_gamma_k_min);
952  }
953  if (cropNode.hasChild("ln_gamma_k_max")) {
954  XML_Node& gkmaxNode = cropNode.child("ln_gamma_k_max");
955  getOptionalFloat(gkmaxNode, "pureSolventValue", CROP_ln_gamma_k_max);
956  }
957 
958  if (cropNode.hasChild("ln_gamma_o_min")) {
959  XML_Node& gominNode = cropNode.child("ln_gamma_o_min");
960  getOptionalFloat(gominNode, "pureSolventValue", CROP_ln_gamma_o_min);
961  }
962 
963  if (cropNode.hasChild("ln_gamma_o_max")) {
964  XML_Node& gomaxNode = cropNode.child("ln_gamma_o_max");
965  getOptionalFloat(gomaxNode, "pureSolventValue", CROP_ln_gamma_o_max);
966  }
967  }
968 }
969 
970 void HMWSoln::initThermo()
971 {
972  MolalityVPSSTP::initThermo();
973  initLengths();
974 }
975 
976 void HMWSoln::constructPhaseFile(std::string inputFile, std::string id_)
977 {
978 
979  if (inputFile.size() == 0) {
980  throw CanteraError("HMWSoln:constructPhaseFile",
981  "input file is null");
982  }
983  string path = findInputFile(inputFile);
984  std::ifstream fin(path.c_str());
985  if (!fin) {
986  throw CanteraError("HMWSoln:constructPhaseFile","could not open "
987  +path+" for reading.");
988  }
989  /*
990  * The phase object automatically constructs an XML object.
991  * Use this object to store information.
992  */
993  XML_Node& phaseNode_XML = xml();
994  XML_Node* fxml = new XML_Node();
995  fxml->build(fin);
996  XML_Node* fxml_phase = findXMLPhase(fxml, id_);
997  if (!fxml_phase) {
998  throw CanteraError("HMWSoln:constructPhaseFile",
999  "ERROR: Can not find phase named " +
1000  id_ + " in file named " + inputFile);
1001  }
1002  fxml_phase->copy(&phaseNode_XML);
1003  constructPhaseXML(*fxml_phase, id_);
1004  delete fxml;
1005 }
1006 
1007 void HMWSoln::constructPhaseXML(XML_Node& phaseNode, std::string id_)
1008 {
1009  string stemp;
1010  if (id_.size() > 0) {
1011  string idp = phaseNode.id();
1012  if (idp != id_) {
1013  throw CanteraError("HMWSoln::constructPhaseXML",
1014  "phasenode and Id are incompatible");
1015  }
1016  }
1017 
1018  /*
1019  * Find the Thermo XML node
1020  */
1021  if (!phaseNode.hasChild("thermo")) {
1022  throw CanteraError("HMWSoln::constructPhaseXML",
1023  "no thermo XML node");
1024  }
1025  XML_Node& thermoNode = phaseNode.child("thermo");
1026 
1027  /*
1028  * Possibly change the form of the standard concentrations
1029  */
1030  if (thermoNode.hasChild("standardConc")) {
1031  XML_Node& scNode = thermoNode.child("standardConc");
1032  m_formGC = 2;
1033  stemp = scNode.attrib("model");
1034  string formString = lowercase(stemp);
1035  if (formString != "") {
1036  if (formString == "unity") {
1037  m_formGC = 0;
1038  printf("exit standardConc = unity not done\n");
1039  exit(EXIT_FAILURE);
1040  } else if (formString == "molar_volume") {
1041  m_formGC = 1;
1042  printf("exit standardConc = molar_volume not done\n");
1043  exit(EXIT_FAILURE);
1044  } else if (formString == "solvent_volume") {
1045  m_formGC = 2;
1046  } else {
1047  throw CanteraError("HMWSoln::constructPhaseXML",
1048  "Unknown standardConc model: " + formString);
1049  }
1050  }
1051  }
1052  /*
1053  * Get the Name of the Solvent:
1054  * <solvent> solventName </solvent>
1055  */
1056  string solventName = "";
1057  if (thermoNode.hasChild("solvent")) {
1058  XML_Node& scNode = thermoNode.child("solvent");
1059  vector<string> nameSolventa;
1060  getStringArray(scNode, nameSolventa);
1061  int nsp = static_cast<int>(nameSolventa.size());
1062  if (nsp != 1) {
1063  throw CanteraError("HMWSoln::constructPhaseXML",
1064  "badly formed solvent XML node");
1065  }
1066  solventName = nameSolventa[0];
1067  }
1068 
1069  /*
1070  * Determine the form of the Pitzer model,
1071  * We will use this information to size arrays below.
1072  */
1073  if (thermoNode.hasChild("activityCoefficients")) {
1074  XML_Node& scNode = thermoNode.child("activityCoefficients");
1075  stemp = scNode.attrib("model");
1076  string formString = lowercase(stemp);
1077  if (formString != "") {
1078  if (formString == "pitzer" || formString == "default") {
1079  m_formPitzer = PITZERFORM_BASE;
1080  } else if (formString == "base") {
1081  m_formPitzer = PITZERFORM_BASE;
1082  } else {
1083  throw CanteraError("HMWSoln::constructPhaseXML",
1084  "Unknown Pitzer ActivityCoeff model: "
1085  + formString);
1086  }
1087  }
1088  /*
1089  * Determine the form of the temperature dependence
1090  * of the Pitzer activity coefficient model.
1091  */
1092  stemp = scNode.attrib("TempModel");
1093  formString = lowercase(stemp);
1094  if (formString != "") {
1095  if (formString == "constant" || formString == "default") {
1096  m_formPitzerTemp = PITZER_TEMP_CONSTANT;
1097  } else if (formString == "linear") {
1098  m_formPitzerTemp = PITZER_TEMP_LINEAR;
1099  } else if (formString == "complex" || formString == "complex1") {
1100  m_formPitzerTemp = PITZER_TEMP_COMPLEX1;
1101  } else {
1102  throw CanteraError("HMWSoln::constructPhaseXML",
1103  "Unknown Pitzer ActivityCoeff Temp model: "
1104  + formString);
1105  }
1106  }
1107 
1108  /*
1109  * Determine the reference temperature
1110  * of the Pitzer activity coefficient model's temperature
1111  * dependence formulation: defaults to 25C
1112  */
1113  stemp = scNode.attrib("TempReference");
1114  formString = lowercase(stemp);
1115  if (formString != "") {
1116  m_TempPitzerRef = fpValueCheck(formString);
1117  } else {
1118  m_TempPitzerRef = 273.15 + 25;
1119  }
1120 
1121  }
1122 
1123  /*
1124  * Call the Cantera importPhase() function. This will import
1125  * all of the species into the phase. This will also handle
1126  * all of the solvent and solute standard states
1127  */
1128  bool m_ok = importPhase(phaseNode, this);
1129  if (!m_ok) {
1130  throw CanteraError("HMWSoln::constructPhaseXML","importPhase failed ");
1131  }
1132 
1133 }
1134 
1135 void HMWSoln::
1136 initThermoXML(XML_Node& phaseNode, const std::string& id_)
1137 {
1138  string stemp;
1139  if (id_.size() > 0) {
1140  string idp = phaseNode.id();
1141  if (idp != id_) {
1142  throw CanteraError("HMWSoln::initThermoXML",
1143  "phasenode and Id are incompatible");
1144  }
1145  }
1146 
1147  /*
1148  * Find the Thermo XML node
1149  */
1150  if (!phaseNode.hasChild("thermo")) {
1151  throw CanteraError("HMWSoln::initThermoXML",
1152  "no thermo XML node");
1153  }
1154  XML_Node& thermoNode = phaseNode.child("thermo");
1155 
1156  /*
1157  * Possibly change the form of the standard concentrations
1158  */
1159  if (thermoNode.hasChild("standardConc")) {
1160  XML_Node& scNode = thermoNode.child("standardConc");
1161  m_formGC = 2;
1162  stemp = scNode.attrib("model");
1163  string formString = lowercase(stemp);
1164  if (formString != "") {
1165  if (formString == "unity") {
1166  m_formGC = 0;
1167  printf("exit standardConc = unity not done\n");
1168  exit(EXIT_FAILURE);
1169  } else if (formString == "molar_volume") {
1170  m_formGC = 1;
1171  printf("exit standardConc = molar_volume not done\n");
1172  exit(EXIT_FAILURE);
1173  } else if (formString == "solvent_volume") {
1174  m_formGC = 2;
1175  } else {
1176  throw CanteraError("HMWSoln::initThermoXML",
1177  "Unknown standardConc model: " + formString);
1178  }
1179  }
1180  }
1181 
1182  /*
1183  * Determine the form of the Pitzer model,
1184  * We will use this information to size arrays below.
1185  */
1186  if (thermoNode.hasChild("activityCoefficients")) {
1187  XML_Node& scNode = thermoNode.child("activityCoefficients");
1188  stemp = scNode.attrib("model");
1189  string formString = lowercase(stemp);
1190  if (formString != "") {
1191  if (formString == "pitzer" || formString == "default") {
1192  m_formPitzer = PITZERFORM_BASE;
1193  } else if (formString == "base") {
1194  m_formPitzer = PITZERFORM_BASE;
1195  } else {
1196  throw CanteraError("HMWSoln::initThermoXML",
1197  "Unknown Pitzer ActivityCoeff model: "
1198  + formString);
1199  }
1200  }
1201 
1202  /*
1203  * Determine the form of the temperature dependence
1204  * of the Pitzer activity coefficient model.
1205  */
1206  stemp = scNode.attrib("TempModel");
1207  formString = lowercase(stemp);
1208  if (formString != "") {
1209  if (formString == "constant" || formString == "default") {
1210  m_formPitzerTemp = PITZER_TEMP_CONSTANT;
1211  } else if (formString == "linear") {
1212  m_formPitzerTemp = PITZER_TEMP_LINEAR;
1213  } else if (formString == "complex" || formString == "complex1") {
1214  m_formPitzerTemp = PITZER_TEMP_COMPLEX1;
1215  } else {
1216  throw CanteraError("HMWSoln::initThermoXML",
1217  "Unknown Pitzer ActivityCoeff Temp model: "
1218  + formString);
1219  }
1220  }
1221 
1222  /*
1223  * Determine the reference temperature
1224  * of the Pitzer activity coefficient model's temperature
1225  * dependence formulation: defaults to 25C
1226  */
1227  stemp = scNode.attrib("TempReference");
1228  formString = lowercase(stemp);
1229  if (formString != "") {
1230  m_TempPitzerRef = fpValueCheck(formString);
1231  } else {
1232  m_TempPitzerRef = 273.15 + 25;
1233  }
1234 
1235  }
1236 
1237  /*
1238  * Get the Name of the Solvent:
1239  * <solvent> solventName </solvent>
1240  */
1241  string solventName = "";
1242  if (thermoNode.hasChild("solvent")) {
1243  XML_Node& scNode = thermoNode.child("solvent");
1244  vector<string> nameSolventa;
1245  getStringArray(scNode, nameSolventa);
1246  int nsp = static_cast<int>(nameSolventa.size());
1247  if (nsp != 1) {
1248  throw CanteraError("HMWSoln::initThermoXML",
1249  "badly formed solvent XML node");
1250  }
1251  solventName = nameSolventa[0];
1252  }
1253 
1254  /*
1255  * Initialize all of the lengths of arrays in the object
1256  * now that we know what species are in the phase.
1257  */
1258  initLengths();
1259 
1260  /*
1261  * Reconcile the solvent name and index.
1262  */
1263  for (size_t k = 0; k < m_kk; k++) {
1264  string sname = speciesName(k);
1265  if (solventName == sname) {
1266  setSolvent(k);
1267  if (k != 0) {
1268  throw CanteraError("HMWSoln::initThermoXML",
1269  "Solvent must be species 0 atm");
1270  }
1271  m_indexSolvent = k;
1272  break;
1273  }
1274  }
1275  if (m_indexSolvent == npos) {
1276  std::cout << "HMWSoln::initThermo: Solvent Name not found"
1277  << std::endl;
1278  throw CanteraError("HMWSoln::initThermoXML",
1279  "Solvent name not found");
1280  }
1281  if (m_indexSolvent != 0) {
1282  throw CanteraError("HMWSoln::initThermoXML",
1283  "Solvent " + solventName +
1284  " should be first species");
1285  }
1286 
1287  /*
1288  * Now go get the specification of the standard states for
1289  * species in the solution. This includes the molar volumes
1290  * data blocks for incompressible species.
1291  */
1292  XML_Node& speciesList = phaseNode.child("speciesArray");
1293  XML_Node* speciesDB =
1294  get_XML_NameID("speciesData", speciesList["datasrc"],
1295  &phaseNode.root());
1296  const vector<string>&sss = speciesNames();
1297 
1298  for (size_t k = 0; k < m_kk; k++) {
1299  XML_Node* s = speciesDB->findByAttr("name", sss[k]);
1300  if (!s) {
1301  throw CanteraError("HMWSoln::initThermoXML",
1302  "Species Data Base " + sss[k] + " not found");
1303  }
1304  XML_Node* ss = s->findByName("standardState");
1305  if (!ss) {
1306  throw CanteraError("HMWSoln::initThermoXML",
1307  "Species " + sss[k] +
1308  " standardState XML block not found");
1309  }
1310  string modelStringa = ss->attrib("model");
1311  if (modelStringa == "") {
1312  throw CanteraError("HMWSoln::initThermoXML",
1313  "Species " + sss[k] +
1314  " standardState XML block model attribute not found");
1315  }
1316  string modelString = lowercase(modelStringa);
1317  if (k == 0) {
1318  if (modelString == "wateriapws" || modelString == "real_water" ||
1319  modelString == "waterpdss") {
1320  /*
1321  * Store a local pointer to the water standard state model.
1322  * -> We've hardcoded it to a PDSS_Water model, so this is ok.
1323  */
1324  m_waterSS = dynamic_cast<PDSS_Water*>(providePDSS(0)) ;
1325  if (!m_waterSS) {
1326  throw CanteraError("HMWSoln::initThermoXML",
1327  "Dynamic cast to PDSS_Water failed");
1328  }
1329  /*
1330  * Fill in the molar volume of water (m3/kmol)
1331  * at standard conditions to fill in the m_speciesSize entry
1332  * with something reasonable.
1333  */
1334  m_waterSS->setState_TP(300., OneAtm);
1335  double dens = m_waterSS->density();
1336  double mw = m_waterSS->molecularWeight();
1337  m_speciesSize[0] = mw / dens;
1338 #ifdef DEBUG_HKM_NOT
1339  cout << "Solvent species " << sss[k] << " has volume " <<
1340  m_speciesSize[k] << endl;
1341 #endif
1342  } else {
1343  // throw CanteraError("HMWSoln::initThermoXML",
1344  // "Solvent SS Model \"" + modelStringa +
1345  // "\" is not allowed, name = " + sss[0]);
1346  m_waterSS = providePDSS(0);
1347  m_waterSS->setState_TP(300., OneAtm);
1348  double dens = m_waterSS->density();
1349  double mw = m_waterSS->molecularWeight();
1350  m_speciesSize[0] = mw / dens;
1351  }
1352  } else {
1353  if (modelString != "constant_incompressible" && modelString != "hkft") {
1354  throw CanteraError("HMWSoln::initThermoXML",
1355  "Solute SS Model \"" + modelStringa +
1356  "\" is not known");
1357  }
1358  if (modelString == "constant_incompressible") {
1359  m_speciesSize[k] = getFloat(*ss, "molarVolume", "toSI");
1360 #ifdef DEBUG_HKM_NOT
1361  cout << "species " << sss[k] << " has volume " <<
1362  m_speciesSize[k] << endl;
1363 #endif
1364  }
1365  // HKM Note, have to fill up m_speciesSize[] for HKFT species
1366  }
1367  }
1368 
1369  /*
1370  * Initialize the water property calculator. It will share
1371  * the internal eos water calculator.
1372  */
1373  m_waterProps = new WaterProps(dynamic_cast<PDSS_Water*>(m_waterSS));
1374 
1375  /*
1376  * Fill in parameters for the calculation of the
1377  * stoichiometric Ionic Strength
1378  *
1379  * The default is that stoich charge is the same as the
1380  * regular charge.
1381  */
1382  for (size_t k = 0; k < m_kk; k++) {
1383  m_speciesCharge_Stoich[k] = charge(k);
1384  }
1385 
1386  /*
1387  * Go get all of the coefficients and factors in the
1388  * activityCoefficients XML block
1389  */
1390  XML_Node* acNodePtr = 0;
1391  if (thermoNode.hasChild("activityCoefficients")) {
1392  XML_Node& acNode = thermoNode.child("activityCoefficients");
1393  acNodePtr = &acNode;
1394  /*
1395  * Look for parameters for A_Debye
1396  */
1397  if (acNode.hasChild("A_Debye")) {
1398  XML_Node& ADebye = acNode.child("A_Debye");
1399  m_form_A_Debye = A_DEBYE_CONST;
1400  stemp = "model";
1401  if (ADebye.hasAttrib(stemp)) {
1402  string atemp = ADebye.attrib(stemp);
1403  stemp = lowercase(atemp);
1404  if (stemp == "water") {
1405  m_form_A_Debye = A_DEBYE_WATER;
1406  }
1407  }
1408  if (m_form_A_Debye == A_DEBYE_CONST) {
1409  m_A_Debye = getFloat(acNode, "A_Debye");
1410  }
1411 #ifdef DEBUG_HKM_NOT
1412  cout << "A_Debye = " << m_A_Debye << endl;
1413 #endif
1414  }
1415 
1416  /*
1417  * Look for Parameters for the Maximum Ionic Strength
1418  */
1419  if (acNode.hasChild("maxIonicStrength")) {
1420  m_maxIionicStrength = getFloat(acNode, "maxIonicStrength");
1421 #ifdef DEBUG_HKM_NOT
1422  cout << "m_maxIionicStrength = "
1423  <<m_maxIionicStrength << endl;
1424 #endif
1425  }
1426 
1427 
1428  /*
1429  * Look for parameters for the Ionic radius
1430  */
1431  if (acNode.hasChild("ionicRadius")) {
1432  XML_Node& irNode = acNode.child("ionicRadius");
1433 
1434  double Afactor = 1.0;
1435  if (irNode.hasAttrib("units")) {
1436  string Aunits = irNode.attrib("units");
1437  Afactor = toSI(Aunits);
1438  }
1439 
1440  if (irNode.hasAttrib("default")) {
1441  string ads = irNode.attrib("default");
1442  double ad = fpValue(ads);
1443  for (size_t k = 0; k < m_kk; k++) {
1444  m_Aionic[k] = ad * Afactor;
1445  }
1446  }
1447 
1448  }
1449 
1450  /*
1451  * First look at the species database.
1452  * -> Look for the subelement "stoichIsMods"
1453  * in each of the species SS databases.
1454  */
1455  std::vector<const XML_Node*> xspecies = speciesData();
1456 
1457  string kname, jname;
1458  size_t jj = xspecies.size();
1459  for (size_t k = 0; k < m_kk; k++) {
1460  size_t jmap = npos;
1461  kname = speciesName(k);
1462  for (size_t j = 0; j < jj; j++) {
1463  const XML_Node& sp = *xspecies[j];
1464  jname = sp["name"];
1465  if (jname == kname) {
1466  jmap = j;
1467  break;
1468  }
1469  }
1470  if (jmap != npos) {
1471  const XML_Node& sp = *xspecies[jmap];
1472  getOptionalFloat(sp, "stoichIsMods", m_speciesCharge_Stoich[k]);
1473  // if (sp.hasChild("stoichIsMods")) {
1474  // double val = getFloat(sp, "stoichIsMods");
1475  //m_speciesCharge_Stoich[k] = val;
1476  //}
1477  }
1478  }
1479 
1480  /*
1481  * Now look at the activity coefficient database
1482  */
1483  if (acNodePtr) {
1484  if (acNodePtr->hasChild("stoichIsMods")) {
1485  XML_Node& sIsNode = acNodePtr->child("stoichIsMods");
1486 
1487  map<string, string> msIs;
1488  getMap(sIsNode, msIs);
1489  map<string,string>::const_iterator _b = msIs.begin();
1490  for (; _b != msIs.end(); ++_b) {
1491  size_t kk = speciesIndex(_b->first);
1492  if (kk != npos) {
1493  double val = fpValue(_b->second);
1494  m_speciesCharge_Stoich[kk] = val;
1495  }
1496  }
1497  }
1498  }
1499 
1500 
1501  /*
1502  * Loop through the children getting multiple instances of
1503  * parameters
1504  */
1505  if (acNodePtr) {
1506  for (size_t i = 0; i < acNodePtr->nChildren(); i++) {
1507  XML_Node& xmlACChild = acNodePtr->child(i);
1508  stemp = xmlACChild.name();
1509  string nodeName = lowercase(stemp);
1510  /*
1511  * Process a binary salt field, or any of the other XML fields
1512  * that make up the Pitzer Database. Entries will be ignored
1513  * if any of the species in the entry isn't in the solution.
1514  */
1515  if (nodeName == "binarysaltparameters") {
1516  readXMLBinarySalt(xmlACChild);
1517  } else if (nodeName == "thetaanion") {
1518  readXMLThetaAnion(xmlACChild);
1519  } else if (nodeName == "thetacation") {
1520  readXMLThetaCation(xmlACChild);
1521  } else if (nodeName == "psicommonanion") {
1522  readXMLPsiCommonAnion(xmlACChild);
1523  } else if (nodeName == "psicommoncation") {
1524  readXMLPsiCommonCation(xmlACChild);
1525  } else if (nodeName == "lambdaneutral") {
1526  readXMLLambdaNeutral(xmlACChild);
1527  } else if (nodeName == "zetacation") {
1528  readXMLZetaCation(xmlACChild);
1529  }
1530  }
1531  }
1532 
1533  // Go look up the optional Cropping parameters
1534  readXMLCroppingCoefficients(acNode);
1535 
1536  }
1537 
1538  /*
1539  * Fill in the vector specifying the electrolyte species
1540  * type
1541  *
1542  * First fill in default values. Everything is either
1543  * a charge species, a nonpolar neutral, or the solvent.
1544  */
1545  for (size_t k = 0; k < m_kk; k++) {
1546  if (fabs(charge(k)) > 0.0001) {
1547  m_electrolyteSpeciesType[k] = cEST_chargedSpecies;
1548  if (fabs(m_speciesCharge_Stoich[k] - charge(k))
1549  > 0.0001) {
1550  m_electrolyteSpeciesType[k] = cEST_weakAcidAssociated;
1551  }
1552  } else if (fabs(m_speciesCharge_Stoich[k]) > 0.0001) {
1553  m_electrolyteSpeciesType[k] = cEST_weakAcidAssociated;
1554  } else {
1555  m_electrolyteSpeciesType[k] = cEST_nonpolarNeutral;
1556  }
1557  }
1558  m_electrolyteSpeciesType[m_indexSolvent] = cEST_solvent;
1559  /*
1560  * First look at the species database.
1561  * -> Look for the subelement "stoichIsMods"
1562  * in each of the species SS databases.
1563  */
1564  std::vector<const XML_Node*> xspecies = speciesData();
1565  const XML_Node* spPtr = 0;
1566  string kname;
1567  for (size_t k = 0; k < m_kk; k++) {
1568  kname = speciesName(k);
1569  spPtr = xspecies[k];
1570  if (!spPtr) {
1571  if (spPtr->hasChild("electrolyteSpeciesType")) {
1572  string est = getChildValue(*spPtr, "electrolyteSpeciesType");
1573  if ((m_electrolyteSpeciesType[k] = interp_est(est)) == -1) {
1574  throw CanteraError("HMWSoln::initThermoXML",
1575  "Bad electrolyte type: " + est);
1576  }
1577  }
1578  }
1579  }
1580  /*
1581  * Then look at the phase thermo specification
1582  */
1583  if (acNodePtr) {
1584  if (acNodePtr->hasChild("electrolyteSpeciesType")) {
1585  XML_Node& ESTNode = acNodePtr->child("electrolyteSpeciesType");
1586  map<string, string> msEST;
1587  getMap(ESTNode, msEST);
1588  map<string,string>::const_iterator _b = msEST.begin();
1589  for (; _b != msEST.end(); ++_b) {
1590  size_t kk = speciesIndex(_b->first);
1591  if (kk != npos) {
1592  string est = _b->second;
1593  if ((m_electrolyteSpeciesType[kk] = interp_est(est)) == -1) {
1594  throw CanteraError("HMWSoln::initThermoXML",
1595  "Bad electrolyte type: " + est);
1596  }
1597  }
1598  }
1599  }
1600  }
1601 
1602  IMS_typeCutoff_ = 2;
1603  if (IMS_typeCutoff_ == 2) {
1604  calcIMSCutoffParams_();
1605  }
1606  calcMCCutoffParams_();
1607  setMoleFSolventMin(1.0E-5);
1608 
1609  MolalityVPSSTP::initThermoXML(phaseNode, id_);
1610  /*
1611  * Lastly calculate the charge balance and then add stuff until the charges compensate
1612  */
1613 
1614  vector_fp mf(m_kk, 0.0);
1615  getMoleFractions(DATA_PTR(mf));
1616  bool notDone = true;
1617 
1618  do {
1619  double sum = 0.0;
1620  size_t kMaxC = npos;
1621  double MaxC = 0.0;
1622  for (size_t k = 0; k < m_kk; k++) {
1623  sum += mf[k] * charge(k);
1624  if (fabs(mf[k] * charge(k)) > MaxC) {
1625  kMaxC = k;
1626  }
1627  }
1628  size_t kHp = speciesIndex("H+");
1629  size_t kOHm = speciesIndex("OH-");
1630 
1631 
1632  if (fabs(sum) > 1.0E-30) {
1633  if (kHp != npos) {
1634  if (mf[kHp] > sum * 1.1) {
1635  mf[kHp] -= sum;
1636  mf[0] += sum;
1637  notDone = false;
1638  } else {
1639  if (sum > 0.0) {
1640  mf[kHp] *= 0.5;
1641  mf[0] += mf[kHp];
1642  sum -= mf[kHp];
1643  }
1644  }
1645  }
1646  if (notDone) {
1647  if (kOHm != npos) {
1648  if (mf[kOHm] > -sum * 1.1) {
1649  mf[kOHm] += sum;
1650  mf[0] -= sum;
1651  notDone = false;
1652  } else {
1653  if (sum < 0.0) {
1654  mf[kOHm] *= 0.5;
1655  mf[0] += mf[kOHm];
1656  sum += mf[kOHm];
1657  }
1658  }
1659  }
1660  if (notDone) {
1661  if (kMaxC != npos) {
1662  if (mf[kMaxC] > (1.1 * sum / charge(kMaxC))) {
1663  mf[kMaxC] -= sum / charge(kMaxC);
1664  mf[0] += sum / charge(kMaxC);
1665  } else {
1666  mf[kMaxC] *= 0.5;
1667  mf[0] += mf[kMaxC];
1668  notDone = true;
1669  }
1670  }
1671  }
1672  }
1673  setMoleFractions(DATA_PTR(mf));
1674  } else {
1675  notDone = false;
1676  }
1677  } while (notDone);
1678 
1679 
1680 
1681 
1682 
1683 
1684 
1685 
1686  // if (phaseNode.hasChild("state")) {
1687  // XML_Node& stateNode = phaseNode.child("state");
1688  // setStateFromXML(stateNode);
1689  //}
1690 
1691 }
1692 
1693 void HMWSoln::calcIMSCutoffParams_()
1694 {
1695  IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_);
1696  IMS_efCut_ = 0.0;
1697  bool converged = false;
1698  double oldV = 0.0;
1699  int its;
1700  for (its = 0; its < 100 && !converged; its++) {
1701  oldV = IMS_efCut_;
1702  IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_) -IMS_efCut_;
1703  IMS_bfCut_ = IMS_afCut_ / IMS_cCut_ + IMS_slopefCut_ - 1.0;
1704  IMS_dfCut_ = ((- IMS_afCut_/IMS_cCut_ + IMS_bfCut_ - IMS_bfCut_*IMS_X_o_cutoff_/IMS_cCut_)
1705  /
1706  (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
1707  double tmp = IMS_afCut_ + IMS_X_o_cutoff_*(IMS_bfCut_ + IMS_dfCut_ *IMS_X_o_cutoff_);
1708  double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
1709  IMS_efCut_ = - eterm * (tmp);
1710  if (fabs(IMS_efCut_ - oldV) < 1.0E-14) {
1711  converged = true;
1712  }
1713  }
1714  if (!converged) {
1715  throw CanteraError("HMWSoln::calcIMSCutoffParams_()",
1716  " failed to converge on the f polynomial");
1717  }
1718  converged = false;
1719  double f_0 = IMS_afCut_ + IMS_efCut_;
1720  double f_prime_0 = 1.0 - IMS_afCut_ / IMS_cCut_ + IMS_bfCut_;
1721  IMS_egCut_ = 0.0;
1722  for (its = 0; its < 100 && !converged; its++) {
1723  oldV = IMS_egCut_;
1724  double lng_0 = -log(IMS_gamma_o_min_) - f_prime_0 / f_0;
1725  IMS_agCut_ = exp(lng_0) - IMS_egCut_;
1726  IMS_bgCut_ = IMS_agCut_ / IMS_cCut_ + IMS_slopegCut_ - 1.0;
1727  IMS_dgCut_ = ((- IMS_agCut_/IMS_cCut_ + IMS_bgCut_ - IMS_bgCut_*IMS_X_o_cutoff_/IMS_cCut_)
1728  /
1729  (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
1730  double tmp = IMS_agCut_ + IMS_X_o_cutoff_*(IMS_bgCut_ + IMS_dgCut_ *IMS_X_o_cutoff_);
1731  double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
1732  IMS_egCut_ = - eterm * (tmp);
1733  if (fabs(IMS_egCut_ - oldV) < 1.0E-14) {
1734  converged = true;
1735  }
1736  }
1737  if (!converged) {
1738  throw CanteraError("HMWSoln::calcIMSCutoffParams_()",
1739  " failed to converge on the g polynomial");
1740  }
1741 }
1742 
1743 void HMWSoln::calcMCCutoffParams_()
1744 {
1745  MC_X_o_min_ = 0.35;
1746  MC_X_o_cutoff_ = 0.6;
1747  MC_slopepCut_ = 0.02;
1748  MC_cpCut_ = 0.25;
1749 
1750  // Initial starting values
1751  MC_apCut_ = MC_X_o_min_;
1752  MC_epCut_ = 0.0;
1753  bool converged = false;
1754  double oldV = 0.0;
1755  int its;
1756  double damp = 0.5;
1757  for (its = 0; its < 500 && !converged; its++) {
1758  oldV = MC_epCut_;
1759  MC_apCut_ = damp *(MC_X_o_min_ - MC_epCut_) + (1-damp) * MC_apCut_;
1760  double MC_bpCutNew = MC_apCut_ / MC_cpCut_ + MC_slopepCut_ - 1.0;
1761  MC_bpCut_ = damp * MC_bpCutNew + (1-damp) * MC_bpCut_;
1762  double MC_dpCutNew = ((- MC_apCut_/MC_cpCut_ + MC_bpCut_ - MC_bpCut_ * MC_X_o_cutoff_/MC_cpCut_)
1763  /
1764  (MC_X_o_cutoff_ * MC_X_o_cutoff_/MC_cpCut_ - 2.0 * MC_X_o_cutoff_));
1765  MC_dpCut_ = damp * MC_dpCutNew + (1-damp) * MC_dpCut_;
1766  double tmp = MC_apCut_ + MC_X_o_cutoff_*(MC_bpCut_ + MC_dpCut_ * MC_X_o_cutoff_);
1767  double eterm = std::exp(- MC_X_o_cutoff_ / MC_cpCut_);
1768  MC_epCut_ = - eterm * (tmp);
1769  double diff = MC_epCut_ - oldV;
1770  if (fabs(diff) < 1.0E-14) {
1771  converged = true;
1772  }
1773  }
1774  if (!converged) {
1775  throw CanteraError("HMWSoln::calcMCCutoffParams_()",
1776  " failed to converge on the p polynomial");
1777  }
1778 }
1779 
1780 }
const int cEST_solvent
Electrolyte species type.
Definition: electrolytes.h:19
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node...
Definition: xml.cpp:716
XML_Node * findXMLPhase(XML_Node *root, const std::string &idtarget)
Search an XML_Node tree for a named phase XML_Node.
Definition: xml.cpp:1104
static int interp_est(const std::string &estString)
Utility function to assign an integer value from a string for the ElectrolyteSpeciesType field...
const doublereal OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:71
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:534
std::string findInputFile(const std::string &name)
Find an input file.
Definition: global.cpp:191
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string 'unit' to SI units.
Definition: global.cpp:196
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:173
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
Implementation of a pressure dependent standard state virtual function for a Pure Water Phase (see Sp...
bool getOptionalFloat(const Cantera::XML_Node &parent, const std::string &name, doublereal &fltRtn, const std::string &type)
Get an optional floating-point value from a child element.
Definition: ctml.cpp:335
doublereal getFloat(const Cantera::XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Definition: ctml.cpp:267
Header for a class used to house several approximation routines for properties of water...
std::string lowercase(const std::string &s)
Cast a copy of a string to lower case.
Definition: stringUtils.cpp:58
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:584
const XML_Node * findByName(const std::string &nm, int depth=100000) const
This routine carries out a recursive search for an XML node based on the name of the node...
Definition: xml.cpp:754
bool importPhase(XML_Node &phase, ThermoPhase *th, SpeciesThermoFactory *spfactory)
Import a phase information into an empty thermophase object.
Headers for the HMWSoln ThermoPhase object, which models concentrated electrolyte solutions (see Ther...
The WaterProps class is used to house several approximation routines for properties of water...
Definition: WaterProps.h:96
#define PITZERFORM_BASE
Major Parameters: The form of the Pitzer expression refers to the form of the Gibbs free energy expre...
Definition: HMWSoln.h:39
Class for the liquid water pressure dependent standard state.
Definition: PDSS_Water.h:54
std::string name() const
Returns the name of the XML node.
Definition: xml.h:390
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:574
void copy(XML_Node *const node_dest) const
Copy all of the information in the current XML_Node tree into the destination XML_Node tree...
Definition: xml.cpp:875
std::string value() const
Return the value of an XML node as a string.
Definition: xml.cpp:488
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:467
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:165
void getStringArray(const Cantera::XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
Definition: ctml.cpp:639
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
void getMap(const Cantera::XML_Node &node, std::map< std::string, std::string > &m)
This routine is used to interpret the value portions of XML elements that contain colon separated pai...
Definition: ctml.cpp:508
XML_Node & root() const
Return the root of the current XML_Node tree.
Definition: xml.cpp:1091
std::string getChildValue(const Cantera::XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its xml value as the return s...
Definition: ctml.cpp:164
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
void build(std::istream &f)
Main routine to create an tree-like representation of an XML file.
Definition: xml.cpp:776
XML_Node * get_XML_NameID(const std::string &nameTarget, const std::string &file_ID, XML_Node *root)
This routine will locate an XML node in either the input XML tree or in another input file specified ...
Definition: global.cpp:271
size_t getFloatArray(const Cantera::XML_Node &node, std::vector< doublereal > &v, const bool convert, const std::string &unitsString, const std::string &nodeName)
This function reads the current node or a child node of the current node with the default name...
Definition: ctml.cpp:419
size_t nChildren(bool discardComments=false) const
Return the number of children.
Definition: xml.cpp:594
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:579