Cantera  2.1.2
MixedSolventElectrolyte.cpp
Go to the documentation of this file.
1 /**
2  * @file MixedSolventElectrolyte.cpp
3  * Definitions for ThermoPhase object for phases which
4  * employ excess gibbs free energy formulations related to Margules
5  * expansions (see \ref thermoprops
6  * and class \link Cantera::MargulesVPSSTP MargulesVPSSTP\endlink).
7  */
8 /*
9  * Copyright (2009) Sandia Corporation. Under the terms of
10  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
11  * U.S. Government retains certain rights in this software.
12  */
13 
17 
18 #include <iomanip>
19 #include <fstream>
20 
21 using namespace std;
22 
23 namespace Cantera
24 {
25 MixedSolventElectrolyte::MixedSolventElectrolyte() :
27  numBinaryInteractions_(0),
28  formMargules_(0),
29  formTempModel_(0)
30 {
31 }
32 
34  const std::string& id_) :
36  numBinaryInteractions_(0),
37  formMargules_(0),
38  formTempModel_(0)
39 {
40  initThermoFile(inputFile, id_);
41 }
42 
44  const std::string& id_) :
46  numBinaryInteractions_(0),
47  formMargules_(0),
48  formTempModel_(0)
49 {
50  importPhase(*findXMLPhase(&phaseRoot, id_), this);
51 }
52 
55 {
57 }
58 
61 {
62  if (&b == this) {
63  return *this;
64  }
65 
67 
69  m_HE_b_ij = b.m_HE_b_ij;
70  m_HE_c_ij = b.m_HE_c_ij;
71  m_HE_d_ij = b.m_HE_d_ij;
72  m_SE_b_ij = b.m_SE_b_ij;
73  m_SE_c_ij = b.m_SE_c_ij;
74  m_SE_d_ij = b.m_SE_d_ij;
85 
86  return *this;
87 }
88 
91 {
92  return new MixedSolventElectrolyte(*this);
93 }
94 
97  numBinaryInteractions_(0),
98  formMargules_(0),
99  formTempModel_(0)
100 {
101  initThermoFile("LiKCl_liquid.xml", "");
102 
103 
105 
106  m_HE_b_ij.resize(1);
107  m_HE_c_ij.resize(1);
108  m_HE_d_ij.resize(1);
109 
110  m_SE_b_ij.resize(1);
111  m_SE_c_ij.resize(1);
112  m_SE_d_ij.resize(1);
113 
114  m_VHE_b_ij.resize(1);
115  m_VHE_c_ij.resize(1);
116  m_VHE_d_ij.resize(1);
117 
118  m_VSE_b_ij.resize(1);
119  m_VSE_c_ij.resize(1);
120  m_VSE_d_ij.resize(1);
121 
122  m_pSpecies_A_ij.resize(1);
123  m_pSpecies_B_ij.resize(1);
124 
125 
126 
127  m_HE_b_ij[0] = -17570E3;
128  m_HE_c_ij[0] = -377.0E3;
129  m_HE_d_ij[0] = 0.0;
130 
131  m_SE_b_ij[0] = -7.627E3;
132  m_SE_c_ij[0] = 4.958E3;
133  m_SE_d_ij[0] = 0.0;
134 
135 
136  size_t iLiCl = speciesIndex("LiCl(L)");
137  if (iLiCl == npos) {
138  throw CanteraError("MixedSolventElectrolyte test1 constructor",
139  "Unable to find LiCl(L)");
140  }
141  m_pSpecies_B_ij[0] = iLiCl;
142 
143 
144  size_t iKCl = speciesIndex("KCl(L)");
145  if (iKCl == npos) {
146  throw CanteraError("MixedSolventElectrolyte test1 constructor",
147  "Unable to find KCl(L)");
148  }
149  m_pSpecies_A_ij[0] = iKCl;
150 }
151 
152 /*
153  * -------------- Utilities -------------------------------
154  */
155 
157 {
158  return 0;
159 }
160 
161 /*
162  * - Activities, Standard States, Activity Concentrations -----------
163  */
164 
166 {
167  /*
168  * Update the activity coefficients
169  */
171 
172  /*
173  * take the exp of the internally stored coefficients.
174  */
175  for (size_t k = 0; k < m_kk; k++) {
176  ac[k] = exp(lnActCoeff_Scaled_[k]);
177  }
178 }
179 
180 /*
181  * ------------ Partial Molar Properties of the Solution ------------
182  */
183 
185 {
186  getChemPotentials(mu);
187  double ve = Faraday * electricPotential();
188  for (size_t k = 0; k < m_kk; k++) {
189  mu[k] += ve*charge(k);
190  }
191 }
192 
194 {
195  doublereal xx;
196  /*
197  * First get the standard chemical potentials in
198  * molar form.
199  * -> this requires updates of standard state as a function
200  * of T and P
201  */
203  /*
204  * Update the activity coefficients
205  */
207  /*
208  *
209  */
210  doublereal RT = GasConstant * temperature();
211  for (size_t k = 0; k < m_kk; k++) {
212  xx = std::max(moleFractions_[k], SmallNumber);
213  mu[k] += RT * (log(xx) + lnActCoeff_Scaled_[k]);
214  }
215 }
216 
218 {
219  size_t kk = nSpecies();
220  double h = 0;
221  vector_fp hbar(kk);
222  getPartialMolarEnthalpies(&hbar[0]);
223  for (size_t i = 0; i < kk; i++) {
224  h += moleFractions_[i]*hbar[i];
225  }
226  return h;
227 }
228 
230 {
231  size_t kk = nSpecies();
232  double s = 0;
233  vector_fp sbar(kk);
234  getPartialMolarEntropies(&sbar[0]);
235  for (size_t i = 0; i < kk; i++) {
236  s += moleFractions_[i]*sbar[i];
237  }
238  return s;
239 }
240 
242 {
243  size_t kk = nSpecies();
244  double cp = 0;
245  vector_fp cpbar(kk);
246  getPartialMolarCp(&cpbar[0]);
247  for (size_t i = 0; i < kk; i++) {
248  cp += moleFractions_[i]*cpbar[i];
249  }
250  return cp;
251 }
252 
254 {
255  return cp_mole() - GasConstant;
256 }
257 
259 {
260  /*
261  * Get the nondimensional standard state enthalpies
262  */
263  getEnthalpy_RT(hbar);
264  /*
265  * dimensionalize it.
266  */
267  double T = temperature();
268  double RT = GasConstant * T;
269  for (size_t k = 0; k < m_kk; k++) {
270  hbar[k] *= RT;
271  }
272  /*
273  * Update the activity coefficients, This also update the
274  * internally stored molalities.
275  */
278  double RTT = RT * T;
279  for (size_t k = 0; k < m_kk; k++) {
280  hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k];
281  }
282 }
283 
284 void MixedSolventElectrolyte::getPartialMolarCp(doublereal* cpbar) const
285 {
286  /*
287  * Get the nondimensional standard state entropies
288  */
289  getCp_R(cpbar);
290  double T = temperature();
291  /*
292  * Update the activity coefficients, This also update the
293  * internally stored molalities.
294  */
297 
298  for (size_t k = 0; k < m_kk; k++) {
299  cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k];
300  }
301  /*
302  * dimensionalize it.
303  */
304  for (size_t k = 0; k < m_kk; k++) {
305  cpbar[k] *= GasConstant;
306  }
307 }
308 
310 {
311  double xx;
312  /*
313  * Get the nondimensional standard state entropies
314  */
315  getEntropy_R(sbar);
316  double T = temperature();
317  /*
318  * Update the activity coefficients, This also update the
319  * internally stored molalities.
320  */
323 
324  for (size_t k = 0; k < m_kk; k++) {
325  xx = std::max(moleFractions_[k], SmallNumber);
326  sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
327  }
328  /*
329  * dimensionalize it.
330  */
331  for (size_t k = 0; k < m_kk; k++) {
332  sbar[k] *= GasConstant;
333  }
334 }
335 
336 void MixedSolventElectrolyte::getPartialMolarVolumes(doublereal* vbar) const
337 {
338  int delAK, delBK;
339  double XA, XB, g0 , g1;
340  double T = temperature();
341 
342  /*
343  * Get the standard state values in m^3 kmol-1
344  */
345  getStandardVolumes(vbar);
346 
347  for (size_t iK = 0; iK < m_kk; iK++) {
348  delAK = 0;
349  delBK = 0;
350  for (size_t i = 0; i < numBinaryInteractions_; i++) {
351  size_t iA = m_pSpecies_A_ij[i];
352  size_t iB = m_pSpecies_B_ij[i];
353 
354  if (iA==iK) {
355  delAK = 1;
356  } else if (iB==iK) {
357  delBK = 1;
358  }
359 
360  XA = moleFractions_[iA];
361  XB = moleFractions_[iB];
362 
363  g0 = (m_VHE_b_ij[i] - T * m_VSE_b_ij[i]);
364  g1 = (m_VHE_c_ij[i] - T * m_VSE_c_ij[i]);
365 
366  vbar[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1;
367  }
368  }
369 }
370 
371 doublereal MixedSolventElectrolyte::err(const std::string& msg) const
372 {
373  throw CanteraError("MixedSolventElectrolyte","Base class method "
374  +msg+" called. Equation of state type: "+int2str(eosType()));
375  return 0;
376 }
377 
379 {
380  initLengths();
382 }
383 
385 {
386  m_kk = nSpecies();
388 }
389 
390 void MixedSolventElectrolyte::initThermoXML(XML_Node& phaseNode, const std::string& id_)
391 {
392  string subname = "MixedSolventElectrolyte::initThermoXML";
393  string stemp;
394 
395  if ((int) id_.size() > 0) {
396  string idp = phaseNode.id();
397  if (idp != id_) {
398  throw CanteraError(subname, "phasenode and Id are incompatible");
399  }
400  }
401 
402  /*
403  * Check on the thermo field. Must have:
404  * <thermo model="MixedSolventElectrolyte" />
405  */
406  if (!phaseNode.hasChild("thermo")) {
407  throw CanteraError(subname, "no thermo XML node");
408  }
409  XML_Node& thermoNode = phaseNode.child("thermo");
410  string mStringa = thermoNode.attrib("model");
411  string mString = lowercase(mStringa);
412  if (mString != "mixedsolventelectrolyte") {
413  throw CanteraError(subname, "Unknown thermo model: " + mStringa);
414  }
415 
416  /*
417  * Go get all of the coefficients and factors in the
418  * activityCoefficients XML block
419  */
420  XML_Node* acNodePtr = 0;
421  if (thermoNode.hasChild("activityCoefficients")) {
422  XML_Node& acNode = thermoNode.child("activityCoefficients");
423  acNodePtr = &acNode;
424  mStringa = acNode.attrib("model");
425  mString = lowercase(mStringa);
426  if (mString != "margules") {
427  throw CanteraError(subname.c_str(),
428  "Unknown activity coefficient model: " + mStringa);
429  }
430  size_t n = acNodePtr->nChildren();
431  for (size_t i = 0; i < n; i++) {
432  XML_Node& xmlACChild = acNodePtr->child(i);
433  stemp = xmlACChild.name();
434  string nodeName = lowercase(stemp);
435  /*
436  * Process a binary salt field, or any of the other XML fields
437  * that make up the Pitzer Database. Entries will be ignored
438  * if any of the species in the entry isn't in the solution.
439  */
440  if (nodeName == "binaryneutralspeciesparameters") {
441  readXMLBinarySpecies(xmlACChild);
442 
443  }
444  }
445  }
446 
447  /*
448  * Go down the chain
449  */
450  MolarityIonicVPSSTP::initThermoXML(phaseNode, id_);
451 
452 
453 }
454 
456 {
457  int delAK, delBK;
458  double XA, XB, g0, g1;
459  double T = temperature();
460  double RT = GasConstant*T;
461  lnActCoeff_Scaled_.assign(m_kk, 0.0);
462  for (size_t iK = 0; iK < m_kk; iK++) {
463  for (size_t i = 0; i < numBinaryInteractions_; i++) {
464  size_t iA = m_pSpecies_A_ij[i];
465  size_t iB = m_pSpecies_B_ij[i];
466  delAK = 0;
467  delBK = 0;
468  if (iA==iK) {
469  delAK = 1;
470  } else if (iB==iK) {
471  delBK = 1;
472  }
473  XA = moleFractions_[iA];
474  XB = moleFractions_[iB];
475  g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT;
476  g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT;
477  lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
478  }
479  }
480 }
481 
483 {
484  int delAK, delBK;
485  doublereal XA, XB, g0, g1;
486  doublereal T = temperature();
487  doublereal RTT = GasConstant*T*T;
488  dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
489  d2lnActCoeffdT2_Scaled_.assign(m_kk, 0.0);
490  for (size_t iK = 0; iK < m_kk; iK++) {
491  for (size_t i = 0; i < numBinaryInteractions_; i++) {
492  size_t iA = m_pSpecies_A_ij[i];
493  size_t iB = m_pSpecies_B_ij[i];
494  delAK = 0;
495  delBK = 0;
496  if (iA==iK) {
497  delAK = 1;
498  } else if (iB==iK) {
499  delBK = 1;
500  }
501  XA = moleFractions_[iA];
502  XB = moleFractions_[iB];
503  g0 = -m_HE_b_ij[i] / RTT;
504  g1 = -m_HE_c_ij[i] / RTT;
505  double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
506  dlnActCoeffdT_Scaled_[iK] += temp;
507  d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T;
508  }
509  }
510 }
511 
512 void MixedSolventElectrolyte::getdlnActCoeffdT(doublereal* dlnActCoeffdT) const
513 {
515  for (size_t k = 0; k < m_kk; k++) {
516  dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
517  }
518 }
519 
520 void MixedSolventElectrolyte::getd2lnActCoeffdT2(doublereal* d2lnActCoeffdT2) const
521 {
523  for (size_t k = 0; k < m_kk; k++) {
524  d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k];
525  }
526 }
527 
528 void MixedSolventElectrolyte::getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds,
529  doublereal* dlnActCoeffds) const
530 {
531  int delAK, delBK;
532  double XA, XB, g0, g1, dXA, dXB;
533  double T = temperature();
534  double RT = GasConstant*T;
535 
536  //fvo_zero_dbl_1(dlnActCoeff, m_kk);
538 
539  for (size_t iK = 0; iK < m_kk; iK++) {
540  dlnActCoeffds[iK] = 0.0;
541  for (size_t i = 0; i < numBinaryInteractions_; i++) {
542 
543  size_t iA = m_pSpecies_A_ij[i];
544  size_t iB = m_pSpecies_B_ij[i];
545 
546  delAK = 0;
547  delBK = 0;
548 
549  if (iA==iK) {
550  delAK = 1;
551  } else if (iB==iK) {
552  delBK = 1;
553  }
554 
555  XA = moleFractions_[iA];
556  XB = moleFractions_[iB];
557 
558  dXA = dXds[iA];
559  dXB = dXds[iB];
560 
561  g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT;
562  g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT;
563 
564  dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB
565  + dlnActCoeffdT_Scaled_[iK]*dTds;
566  }
567  }
568 }
569 
571 {
572  int delAK, delBK;
573  double XA, XB, XK, g0, g1;
574  double T = temperature();
575  double RT = GasConstant*T;
576 
577  dlnActCoeffdlnN_diag_.assign(m_kk, 0);
578 
579  for (size_t iK = 0; iK < m_kk; iK++) {
580 
581  XK = moleFractions_[iK];
582 
583  for (size_t i = 0; i < numBinaryInteractions_; i++) {
584 
585  size_t iA = m_pSpecies_A_ij[i];
586  size_t iB = m_pSpecies_B_ij[i];
587 
588  delAK = 0;
589  delBK = 0;
590 
591  if (iA==iK) {
592  delAK = 1;
593  } else if (iB==iK) {
594  delBK = 1;
595  }
596 
597  XA = moleFractions_[iA];
598  XB = moleFractions_[iB];
599 
600  g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT;
601  g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT;
602 
603  dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB)));
604 
605  // double gfac = g0 + g1 * XB;
606  // double gggg = (delBK - XB) * g1;
607 
608 
609  // dlnActCoeffdlnN_diag_[iK] += gfac * delAK * ( - XB + delBK);
610 
611  // dlnActCoeffdlnN_diag_[iK] += gfac * delBK * ( - XA + delAK);
612 
613  // dlnActCoeffdlnN_diag_[iK] += gfac * (2.0 * XA * XB - delAK * XB - XA * delBK);
614 
615  // dlnActCoeffdlnN_diag_[iK] += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBK);
616 
617  // dlnActCoeffdlnN_diag_[iK] += gggg * ( - 2.0 * XA * XB + delAK * XB + XA * delBK);
618 
619  // dlnActCoeffdlnN_diag_[iK] += - g1 * XA * XB * (- XB + delBK);
620  }
621  dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK];//-XK;
622  }
623 }
624 
626 {
627  doublereal delAK, delBK;
628  double XA, XB, g0, g1,XM;
629  double T = temperature();
630  double RT = GasConstant*T;
631 
632  doublereal delAM, delBM;
634 
635  /*
636  * Loop over the activity coefficient gamma_k
637  */
638  for (size_t iK = 0; iK < m_kk; iK++) {
639  for (size_t iM = 0; iM < m_kk; iM++) {
640  XM = moleFractions_[iM];
641  for (size_t i = 0; i < numBinaryInteractions_; i++) {
642 
643  size_t iA = m_pSpecies_A_ij[i];
644  size_t iB = m_pSpecies_B_ij[i];
645 
646  delAK = 0.0;
647  delBK = 0.0;
648  delAM = 0.0;
649  delBM = 0.0;
650  if (iA==iK) {
651  delAK = 1.0;
652  } else if (iB==iK) {
653  delBK = 1.0;
654  }
655  if (iA==iM) {
656  delAM = 1.0;
657  } else if (iB==iM) {
658  delBM = 1.0;
659  }
660 
661  XA = moleFractions_[iA];
662  XB = moleFractions_[iB];
663 
664  g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT;
665  g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT;
666 
667  dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB));
668  dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA);
669 
670  // double gfac = g0 + g1 * XB;
671  // double gggg = (delBK - XB) * g1;
672 
673 
674  // dlnActCoeffdlnN_(iK, iM) += gfac * delAK * ( - XB + delBM);
675 
676  // dlnActCoeffdlnN_(iK, iM) += gfac * delBK * ( - XA + delAM);
677 
678  // dlnActCoeffdlnN_(iK, iM) += gfac * (2.0 * XA * XB - delAM * XB - XA * delBM);
679 
680  // dlnActCoeffdlnN_(iK, iM) += (delAK * XB + XA * delBK - XA * XB) * g1 * (-XB + delBM);
681 
682  // dlnActCoeffdlnN_(iK, iM) += gggg * ( - 2.0 * XA * XB + delAM * XB + XA * delBM);
683 
684  // dlnActCoeffdlnN_(iK, iM) += - g1 * XA * XB * (- XB + delBM);
685  }
686  dlnActCoeffdlnN_(iK,iM) = XM*dlnActCoeffdlnN_(iK,iM);
687  }
688  }
689 }
690 
692 {
693  doublereal XA, XB, g0 , g1;
694  doublereal T = temperature();
695 
696  dlnActCoeffdlnX_diag_.assign(m_kk, 0);
697  doublereal RT = GasConstant * T;
698 
699  for (size_t i = 0; i < numBinaryInteractions_; i++) {
700 
701  size_t iA = m_pSpecies_A_ij[i];
702  size_t iB = m_pSpecies_B_ij[i];
703 
704  XA = moleFractions_[iA];
705  XB = moleFractions_[iB];
706 
707  g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT;
708  g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT;
709 
710  dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB);
711  dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB);
712  }
713 }
714 
715 
716 void MixedSolventElectrolyte::getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const
717 {
719  for (size_t k = 0; k < m_kk; k++) {
720  dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k];
721  }
722 }
723 
724 void MixedSolventElectrolyte::getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const
725 {
727  for (size_t k = 0; k < m_kk; k++) {
728  dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
729  }
730 }
731 
732 void MixedSolventElectrolyte::getdlnActCoeffdlnN(const size_t ld, doublereal* dlnActCoeffdlnN)
733 {
735  double* data = & dlnActCoeffdlnN_(0,0);
736  for (size_t k = 0; k < m_kk; k++) {
737  for (size_t m = 0; m < m_kk; m++) {
738  dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
739  }
740  }
741 }
742 
744 {
746  m_HE_b_ij.resize(num, 0.0);
747  m_HE_c_ij.resize(num, 0.0);
748  m_HE_d_ij.resize(num, 0.0);
749  m_SE_b_ij.resize(num, 0.0);
750  m_SE_c_ij.resize(num, 0.0);
751  m_SE_d_ij.resize(num, 0.0);
752  m_VHE_b_ij.resize(num, 0.0);
753  m_VHE_c_ij.resize(num, 0.0);
754  m_VHE_d_ij.resize(num, 0.0);
755  m_VSE_b_ij.resize(num, 0.0);
756  m_VSE_c_ij.resize(num, 0.0);
757  m_VSE_d_ij.resize(num, 0.0);
758 
759  m_pSpecies_A_ij.resize(num, npos);
760  m_pSpecies_B_ij.resize(num, npos);
761 
762 }
763 
765 {
766  string xname = xmLBinarySpecies.name();
767  if (xname != "binaryNeutralSpeciesParameters") {
768  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies",
769  "Incorrect name for processing this routine: " + xname);
770  }
771  string stemp;
772  size_t nParamsFound;
773  vector_fp vParams;
774  string iName = xmLBinarySpecies.attrib("speciesA");
775  if (iName == "") {
776  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesA attrib");
777  }
778  string jName = xmLBinarySpecies.attrib("speciesB");
779  if (jName == "") {
780  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesB attrib");
781  }
782  /*
783  * Find the index of the species in the current phase. It's not
784  * an error to not find the species
785  */
786  size_t iSpecies = speciesIndex(iName);
787  if (iSpecies == npos) {
788  return;
789  }
790  string ispName = speciesName(iSpecies);
791  if (charge(iSpecies) != 0) {
792  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesA charge problem");
793  }
794  size_t jSpecies = speciesIndex(jName);
795  if (jSpecies == npos) {
796  return;
797  }
798  string jspName = speciesName(jSpecies);
799  if (charge(jSpecies) != 0) {
800  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesB charge problem");
801  }
802 
804  size_t iSpot = numBinaryInteractions_ - 1;
805  m_pSpecies_A_ij[iSpot] = iSpecies;
806  m_pSpecies_B_ij[iSpot] = jSpecies;
807 
808  size_t num = xmLBinarySpecies.nChildren();
809  for (size_t iChild = 0; iChild < num; iChild++) {
810  XML_Node& xmlChild = xmLBinarySpecies.child(iChild);
811  stemp = xmlChild.name();
812  string nodeName = lowercase(stemp);
813  /*
814  * Process the binary species interaction child elements
815  */
816  if (nodeName == "excessenthalpy") {
817  /*
818  * Get the string containing all of the values
819  */
820  ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy");
821  nParamsFound = vParams.size();
822 
823  if (nParamsFound != 2) {
824  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEnthalpy for " + ispName
825  + "::" + jspName,
826  "wrong number of params found");
827  }
828  m_HE_b_ij[iSpot] = vParams[0];
829  m_HE_c_ij[iSpot] = vParams[1];
830  }
831 
832  if (nodeName == "excessentropy") {
833  /*
834  * Get the string containing all of the values
835  */
836  ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy");
837  nParamsFound = vParams.size();
838 
839  if (nParamsFound != 2) {
840  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEntropy for " + ispName
841  + "::" + jspName,
842  "wrong number of params found");
843  }
844  m_SE_b_ij[iSpot] = vParams[0];
845  m_SE_c_ij[iSpot] = vParams[1];
846  }
847 
848  if (nodeName == "excessvolume_enthalpy") {
849  /*
850  * Get the string containing all of the values
851  */
852  ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy");
853  nParamsFound = vParams.size();
854 
855  if (nParamsFound != 2) {
856  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName
857  + "::" + jspName,
858  "wrong number of params found");
859  }
860  m_VHE_b_ij[iSpot] = vParams[0];
861  m_VHE_c_ij[iSpot] = vParams[1];
862  }
863 
864  if (nodeName == "excessvolume_entropy") {
865  /*
866  * Get the string containing all of the values
867  */
868  ctml::getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy");
869  nParamsFound = vParams.size();
870 
871  if (nParamsFound != 2) {
872  throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Entropy for " + ispName
873  + "::" + jspName,
874  "wrong number of params found");
875  }
876  m_VSE_b_ij[iSpot] = vParams[0];
877  m_VSE_c_ij[iSpot] = vParams[1];
878  }
879  }
880 }
881 
882 }
virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const
Get the array of derivatives of the log activity coefficients wrt mole numbers - diagonal only...
void s_update_dlnActCoeff_dlnN_diag() const
Update the derivative of the log of the activity coefficients wrt log(moles) - diagonal only...
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:40
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:391
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies for the species in the mixture.
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
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
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:534
void s_update_dlnActCoeff_dlnN() const
Update the derivative of the log of the activity coefficients wrt log(moles_m)
void resize(size_t n, size_t m, doublereal v=0.0)
Resize the array, and fill the new entries with 'v'.
Definition: Array.h:128
virtual void getd2lnActCoeffdT2(doublereal *d2lnActCoeffdT2) const
Get the array of temperature second derivatives of the log activity coefficients. ...
void s_update_dlnActCoeff_dlnX_diag() const
Update the derivative of the log of the activity coefficients wrt log(mole fraction) ...
void s_update_lnActCoeff() const
Update the activity coefficients.
virtual ThermoPhase * duplMyselfAsThermoPhase() const
Duplication routine for objects which inherit from ThermoPhase.
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of each species in their standard states at the current T and P of the solution...
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:173
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
vector_fp m_HE_d_ij
Enthalpy term for the quaternary mole fraction interaction of the excess gibbs free energy expression...
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
vector_fp m_SE_b_ij
Entropy term for the binary mole fraction interaction of the excess gibbs free energy expression...
std::string lowercase(const std::string &s)
Cast a copy of a string to lower case.
Definition: stringUtils.cpp:58
std::vector< doublereal > d2lnActCoeffdT2_Scaled_
Storage for the current derivative values of the gradients with respect to temperature of the log of ...
std::vector< doublereal > dlnActCoeffdlnN_diag_
Storage for the current derivative values of the gradients with respect to logarithm of the mole frac...
MolarityIonicVPSSTP & operator=(const MolarityIonicVPSSTP &b)
Assignment operator.
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol.
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
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:101
void readXMLBinarySpecies(XML_Node &xmlBinarySpecies)
Process an XML node called "binaryNeutralSpeciesParameters".
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition: Phase.cpp:229
bool importPhase(XML_Node &phase, ThermoPhase *th, SpeciesThermoFactory *spfactory)
Import a phase information into an empty thermophase object.
virtual void getdlnActCoeffds(const doublereal dTds, const doublereal *const dXds, doublereal *dlnActCoeffds) const
Get the change in activity coefficients w.r.t.
void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object.
virtual void getPartialMolarCp(doublereal *cpbar) const
Returns an array of partial molar entropies for the species in the mixture.
void initLengths()
Initialize lengths of local variables after all species have been identified.
int formTempModel_
form of the temperature dependence of the Margules interaction expression
virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const
Get the array of log concentration-like derivatives of the log activity coefficients - diagonal compo...
void s_update_dlnActCoeff_dT() const
Update the derivative of the log of the activity coefficients wrt T.
vector_fp m_HE_b_ij
Enthalpy term for the binary mole fraction interaction of the excess gibbs free energy expression...
void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object.
MixedSolventElectrolyte is a derived class of GibbsExcessVPSSTP that employs the DH and local Margule...
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal *const dlnActCoeffdlnN)
Get the array of derivatives of the log activity coefficients with respect to the ln species mole num...
vector_fp m_VHE_d_ij
Enthalpy term for the quaternary mole fraction interaction of the excess gibbs free energy expression...
std::string name() const
Returns the name of the XML node.
Definition: xml.h:390
void resizeNumInteractions(const size_t num)
Resize internal arrays within the object that depend upon the number of binary Margules interaction t...
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
vector_fp m_VHE_b_ij
Enthalpy term for the binary mole fraction interaction of the excess gibbs free energy expression...
int formMargules_
form of the Margules interaction expression
vector_fp m_VHE_c_ij
Enthalpy term for the ternary mole fraction interaction of the excess gibbs free energy expression...
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:574
doublereal err(const std::string &msg) const
Error function.
virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const
Get the array of temperature derivatives of the log activity coefficients.
void getElectrochemPotentials(doublereal *mu) const
Get the species electrochemical potentials.
vector_fp m_VSE_c_ij
Entropy term for the ternary mole fraction interaction of the excess gibbs free energy expression...
vector_fp m_VSE_d_ij
Entropy term for the quaternary mole fraction interaction of the excess gibbs free energy expression...
std::vector< size_t > m_pSpecies_B_ij
vector of species indices representing species B in the interaction
vector_fp m_SE_c_ij
Entropy term for the ternary mole fraction interaction of the excess gibbs free energy expression...
vector_fp m_HE_c_ij
Enthalpy term for the ternary mole fraction interaction of the excess gibbs free energy expression...
size_t numBinaryInteractions_
number of binary interaction expressions
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:252
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
std::vector< size_t > m_pSpecies_A_ij
vector of species indices representing species A in the interaction
std::vector< doublereal > dlnActCoeffdlnX_diag_
Storage for the current derivative values of the gradients with respect to logarithm of the mole frac...
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Enthalpy functions for the standard state species at the current T an...
doublereal temperature() const
Temperature (K).
Definition: Phase.h:528
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:467
const doublereal SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:139
std::vector< doublereal > lnActCoeff_Scaled_
Storage for the current values of the activity coefficients of the species.
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
std::vector< doublereal > moleFractions_
Storage for the current values of the mole fractions of the species.
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
virtual int eosType() const
Equation of state type flag.
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:66
Contains declarations for string manipulation functions within Cantera.
size_t m_kk
Number of species in the phase.
Definition: Phase.h:716
Array2D dlnActCoeffdlnN_
Storage for the current derivative values of the gradients with respect to logarithm of the species m...
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
vector_fp m_SE_d_ij
Entropy term for the quaternary mole fraction interaction of the excess gibbs free energy expression...
void zero()
Set all of the entries to zero.
Definition: Array.h:256
virtual void initThermoFile(const std::string &inputFile, const std::string &id)
MixedSolventElectrolyte & operator=(const MixedSolventElectrolyte &b)
Assignment operator.
vector_fp m_VSE_b_ij
Entropy term for the binary mole fraction interaction of the excess gibbs free energy expression...
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity.
Header for intermediate ThermoPhase object for phases which employ gibbs excess free energy based for...
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:246
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
std::vector< doublereal > dlnActCoeffdT_Scaled_
Storage for the current derivative values of the gradients with respect to temperature of the log of ...
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition: Phase.h:504