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