Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IonsFromNeutralVPSSTP.cpp
Go to the documentation of this file.
1 /**
2  * @file IonsFromNeutralVPSSTP.cpp
3  * Definitions for the object which treats ionic liquids as made of ions as species
4  * even though the thermodynamics is obtained from the neutral molecule representation.
5  * (see \ref thermoprops
6  * and class \link Cantera::IonsFromNeutralVPSSTP IonsFromNeutralVPSSTP\endlink).
7  *
8  * Header file for a derived class of ThermoPhase that handles
9  * variable pressure standard state methods for calculating
10  * thermodynamic properties that are further based upon expressions
11  * for the excess Gibbs free energy expressed as a function of
12  * the mole fractions.
13  */
14 /*
15  * Copyright (2009) Sandia Corporation. Under the terms of
16  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
17  * U.S. Government retains certain rights in this software.
18  */
23 
24 #include <fstream>
25 
26 using namespace std;
27 
28 namespace Cantera
29 {
30 
31 IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP() :
32  ionSolnType_(cIonSolnType_SINGLEANION),
33  numNeutralMoleculeSpecies_(0),
34  indexSpecialSpecies_(npos),
35  indexSecondSpecialSpecies_(npos),
36  neutralMoleculePhase_(0),
37  geThermo(0),
38  IOwnNThermoPhase_(true)
39 {
40 }
41 
42 IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP(const std::string& inputFile,
43  const std::string& id_,
44  ThermoPhase* neutralPhase) :
45  ionSolnType_(cIonSolnType_SINGLEANION),
46  numNeutralMoleculeSpecies_(0),
47  indexSpecialSpecies_(npos),
48  indexSecondSpecialSpecies_(npos),
49  neutralMoleculePhase_(neutralPhase),
50  IOwnNThermoPhase_(true)
51 {
52  if (neutralPhase) {
53  IOwnNThermoPhase_ = false;
54  }
55  constructPhaseFile(inputFile, id_);
56  geThermo = dynamic_cast<GibbsExcessVPSSTP*>(neutralMoleculePhase_);
57 }
58 
60  const std::string& id_, ThermoPhase* neutralPhase) :
61  ionSolnType_(cIonSolnType_SINGLEANION),
62  numNeutralMoleculeSpecies_(0),
63  indexSpecialSpecies_(npos),
64  indexSecondSpecialSpecies_(npos),
65  neutralMoleculePhase_(neutralPhase),
66  IOwnNThermoPhase_(true)
67 {
68  if (neutralPhase) {
69  IOwnNThermoPhase_ = false;
70  }
71  constructPhaseXML(phaseRoot, id_);
72  geThermo = dynamic_cast<GibbsExcessVPSSTP*>(neutralMoleculePhase_);
73  y_.resize(numNeutralMoleculeSpecies_,0.0);
74  size_t numNeutMolSpec = geThermo->nSpecies();
75  dlnActCoeff_NeutralMolecule_.resize(numNeutMolSpec);
76  dX_NeutralMolecule_.resize(numNeutMolSpec);
77 }
78 
80  ionSolnType_(cIonSolnType_SINGLEANION),
81  numNeutralMoleculeSpecies_(0),
82  indexSpecialSpecies_(npos),
83  indexSecondSpecialSpecies_(npos),
84  neutralMoleculePhase_(0),
85  geThermo(0),
86  IOwnNThermoPhase_(true)
87 {
89 }
90 
93 {
94  if (&b == this) {
95  return *this;
96  }
97 
98  /*
99  * If we own the underlying neutral molecule phase, then we do a deep
100  * copy. If not, we do a shallow copy. We get a valid pointer for
101  * neutralMoleculePhase_ first, because we need it to assign the pointers
102  * within the PDSS_IonsFromNeutral object. which is done in the
103  * GibbsExcessVPSSTP::operator=(b) step.
104  */
105  if (IOwnNThermoPhase_) {
106  if (b.neutralMoleculePhase_) {
107  delete neutralMoleculePhase_;
109  } else {
111  }
112  } else {
114  }
115  geThermo = dynamic_cast<GibbsExcessVPSSTP*>(neutralMoleculePhase_);
116 
118 
119 
130 
131  y_ = b.y_;
132  dlnActCoeff_NeutralMolecule_ = b.dlnActCoeff_NeutralMolecule_;
133  dX_NeutralMolecule_ = b.dX_NeutralMolecule_;
134 
138  // gammaNeutralMolecule_ = b.gammaNeutralMolecule_;
144 
145  return *this;
146 }
147 
149 {
150  if (IOwnNThermoPhase_) {
151  delete neutralMoleculePhase_;
153  }
154 }
155 
158 {
159  return new IonsFromNeutralVPSSTP(*this);
160 }
161 
162 void IonsFromNeutralVPSSTP::constructPhaseFile(std::string inputFile, std::string id_)
163 {
164 
165  if (inputFile.size() == 0) {
166  throw CanteraError("MargulesVPSSTP:constructPhaseFile",
167  "input file is null");
168  }
169  string path = findInputFile(inputFile);
170  std::ifstream fin(path.c_str());
171  if (!fin) {
172  throw CanteraError("MargulesVPSSTP:constructPhaseFile","could not open "
173  +path+" for reading.");
174  }
175  /*
176  * The phase object automatically constructs an XML object.
177  * Use this object to store information.
178  */
179  XML_Node fxml;
180  fxml.build(fin);
181  XML_Node* fxml_phase = findXMLPhase(&fxml, id_);
182  if (!fxml_phase) {
183  throw CanteraError("MargulesVPSSTP:constructPhaseFile",
184  "ERROR: Can not find phase named " +
185  id_ + " in file named " + inputFile);
186  }
187  setXMLdata(*fxml_phase);
188  constructPhaseXML(*fxml_phase, id_);
189 }
190 
191 void IonsFromNeutralVPSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id_)
192 {
193  if (id_.size() > 0) {
194  if (phaseNode.id() != id_) {
195  throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML",
196  "phasenode and Id are incompatible");
197  }
198  }
199 
200  /*
201  * Find the thermo XML node
202  */
203  if (!phaseNode.hasChild("thermo")) {
204  throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML",
205  "no thermo XML node");
206  }
207  XML_Node& thermoNode = phaseNode.child("thermo");
208 
209 
210 
211  /*
212  * Make sure that the thermo model is IonsFromNeutralMolecule
213  */
214  string formString = lowercase(thermoNode.attrib("model"));
215  if (formString != "ionsfromneutralmolecule") {
216  throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML",
217  "model name isn't IonsFromNeutralMolecule: " + formString);
218  }
219 
220  /*
221  * Find the Neutral Molecule Phase
222  */
223  if (!thermoNode.hasChild("neutralMoleculePhase")) {
224  throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML",
225  "no neutralMoleculePhase XML node");
226  }
227  XML_Node& neutralMoleculeNode = thermoNode.child("neutralMoleculePhase");
228 
229  XML_Node* neut_ptr = get_XML_Node(neutralMoleculeNode["datasrc"], 0);
230  if (!neut_ptr) {
231  throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML",
232  "neut_ptr = 0");
233  }
234 
235  /*
236  * Create the neutralMolecule ThermoPhase if we haven't already
237  */
238  if (!neutralMoleculePhase_) {
239  neutralMoleculePhase_ = newPhase(*neut_ptr);
240  }
241 
242  /*
243  * Call the Cantera importPhase() function. This will import
244  * all of the species into the phase. This will also handle
245  * all of the solvent and solute standard states
246  */
247  importPhase(phaseNode, this);
248 }
249 
250 /*
251  * -------------- Utilities -------------------------------
252  */
253 
255 {
256  return cIonsFromNeutral;
257 }
258 
259 /*
260  * ------------ Molar Thermodynamic Properties ----------------------
261  */
262 
264 {
266  return mean_X(m_pp);
267 }
268 
270 {
272  return mean_X(m_pp);
273 }
274 
276 {
278  return mean_X(m_pp);
279 }
280 
282 {
284  return mean_X(m_pp);
285 }
286 
288 {
289  // Need to revisit this, as it is wrong
291  return mean_X(m_pp);
292 }
293 
294 /*
295  * - Activities, Standard States, Activity Concentrations -----------
296  */
297 
299  vector_fp& charges, std::vector<size_t>& neutMolIndex) const
300 {
301  coeffs = fm_neutralMolec_ions_;
302  charges = m_speciesCharge;
303  neutMolIndex = fm_invert_ionForNeutral;
304 }
305 
307 {
308  /*
309  * Update the activity coefficients
310  */
312 
313  /*
314  * take the exp of the internally stored coefficients.
315  */
316  for (size_t k = 0; k < m_kk; k++) {
317  ac[k] = exp(lnActCoeff_Scaled_[k]);
318  }
319 }
320 
321 /*
322  * --------- Partial Molar Properties of the Solution -------------
323  */
324 
326 {
327  size_t icat, jNeut;
328  doublereal xx, fact2;
329 
330  /*
331  * Get the standard chemical potentials of netural molecules
332  */
334 
335  doublereal RT_ = GasConstant * temperature();
336 
337  switch (ionSolnType_) {
338  case cIonSolnType_PASSTHROUGH:
340  break;
341  case cIonSolnType_SINGLEANION:
343 
344  fact2 = 2.0 * RT_ * log(2.0);
345 
346  // Do the cation list
347  for (size_t k = 0; k < cationList_.size(); k++) {
348  //! Get the id for the next cation
349  icat = cationList_[k];
350  jNeut = fm_invert_ionForNeutral[icat];
351  xx = std::max(SmallNumber, moleFractions_[icat]);
352  mu[icat] = muNeutralMolecule_[jNeut] + fact2 + RT_ * (lnActCoeff_NeutralMolecule_[jNeut] + log(xx));
353  }
354 
355  // Do the anion list
356  icat = anionList_[0];
357  jNeut = fm_invert_ionForNeutral[icat];
358  xx = std::max(SmallNumber, moleFractions_[icat]);
359  mu[icat] = RT_ * log(xx);
360 
361  // Do the list of neutral molecules
362  for (size_t k = 0; k < passThroughList_.size(); k++) {
363  icat = passThroughList_[k];
364  jNeut = fm_invert_ionForNeutral[icat];
365  xx = std::max(SmallNumber, moleFractions_[icat]);
366  mu[icat] = muNeutralMolecule_[jNeut] + RT_ * (lnActCoeff_NeutralMolecule_[jNeut] + log(xx));
367  }
368  break;
369 
370  case cIonSolnType_SINGLECATION:
371  throw CanteraError("eosType", "Unknown type");
372  break;
373  case cIonSolnType_MULTICATIONANION:
374  throw CanteraError("eosType", "Unknown type");
375  break;
376  default:
377  throw CanteraError("eosType", "Unknown type");
378  break;
379  }
380 }
381 
383 {
384  /*
385  * Get the nondimensional standard state enthalpies
386  */
387  getEnthalpy_RT(hbar);
388  /*
389  * dimensionalize it.
390  */
391  double T = temperature();
392  double RT = GasConstant * T;
393  for (size_t k = 0; k < m_kk; k++) {
394  hbar[k] *= RT;
395  }
396  /*
397  * Update the activity coefficients, This also update the
398  * internally stored molalities.
399  */
402  double RTT = RT * T;
403  for (size_t k = 0; k < m_kk; k++) {
404  hbar[k] -= RTT * dlnActCoeffdT_Scaled_[k];
405  }
406 }
407 
409 {
410  /*
411  * Get the nondimensional standard state entropies
412  */
413  getEntropy_R(sbar);
414  double T = temperature();
415  /*
416  * Update the activity coefficients, This also update the
417  * internally stored molalities.
418  */
421 
422  for (size_t k = 0; k < m_kk; k++) {
423  double xx = std::max(moleFractions_[k], SmallNumber);
424  sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
425  }
426  /*
427  * dimensionalize it.
428  */
429  for (size_t k = 0; k < m_kk; k++) {
430  sbar[k] *= GasConstant;
431  }
432 }
433 
434 void IonsFromNeutralVPSSTP::getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const
435 {
438 
439  for (size_t k = 0; k < m_kk; k++) {
440  dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
441  }
442 }
443 
444 void IonsFromNeutralVPSSTP::getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const
445 {
448 
449  for (size_t k = 0; k < m_kk; k++) {
450  dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k];
451  }
452 }
453 
454 void IonsFromNeutralVPSSTP::getdlnActCoeffdlnN(const size_t ld, doublereal* dlnActCoeffdlnN)
455 {
458  double* data = & dlnActCoeffdlnN_(0,0);
459  for (size_t k = 0; k < m_kk; k++) {
460  for (size_t m = 0; m < m_kk; m++) {
461  dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
462  }
463  }
464 }
465 
466 void IonsFromNeutralVPSSTP::setTemperature(const doublereal temp)
467 {
469 }
470 
472 {
474 }
475 
476 void IonsFromNeutralVPSSTP::setState_TP(doublereal t, doublereal p)
477 {
478  /*
479  * This is a two phase process. First, we calculate the standard states
480  * within the neutral molecule phase.
481  */
484 
485  /*
486  * Calculate the partial molar volumes, and then the density of the fluid
487  */
489 }
490 
491 void IonsFromNeutralVPSSTP::calcIonMoleFractions(doublereal* const mf) const
492 {
493  /*
494  * Download the neutral mole fraction vector into the
495  * vector, NeutralMolecMoleFractions_[]
496  */
498 
499  // Zero the mole fractions
500  for (size_t k = 0; k < m_kk; k++) {
501  mf[k] = 0.0;
502  }
503 
504  /*
505  * Use the formula matrix to calculate the relative mole numbers.
506  */
507  for (size_t jNeut = 0; jNeut < numNeutralMoleculeSpecies_; jNeut++) {
508  for (size_t k = 0; k < m_kk; k++) {
509  double fmij = fm_neutralMolec_ions_[k + jNeut * m_kk];
510  mf[k] += fmij * NeutralMolecMoleFractions_[jNeut];
511  }
512  }
513 
514  /*
515  * Normalize the new mole fractions
516  */
517  doublereal sum = 0.0;
518  for (size_t k = 0; k < m_kk; k++) {
519  sum += mf[k];
520  }
521  for (size_t k = 0; k < m_kk; k++) {
522  mf[k] /= sum;
523  }
524 
525 }
526 
528 {
529  size_t icat, jNeut;
530  doublereal fmij;
531  doublereal sum = 0.0;
532 
533  //! Zero the vector we are trying to find.
534  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
536  }
537  if (DEBUG_MODE_ENABLED) {
538  sum = -1.0;
539  for (size_t k = 0; k < m_kk; k++) {
540  sum += moleFractions_[k];
541  }
542  if (fabs(sum) > 1.0E-11) {
543  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions",
544  "molefracts don't sum to one: " + fp2str(sum));
545  }
546  }
547 
548  switch (ionSolnType_) {
549 
550  case cIonSolnType_PASSTHROUGH:
551  for (size_t k = 0; k < m_kk; k++) {
553  }
554  break;
555 
556  case cIonSolnType_SINGLEANION:
557  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
559  }
560 
561  for (size_t k = 0; k < cationList_.size(); k++) {
562  //! Get the id for the next cation
563  icat = cationList_[k];
564  jNeut = fm_invert_ionForNeutral[icat];
565  if (jNeut != npos) {
566  fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
567  AssertTrace(fmij != 0.0);
568  NeutralMolecMoleFractions_[jNeut] += moleFractions_[icat] / fmij;
569  }
570  }
571 
572  for (size_t k = 0; k < passThroughList_.size(); k++) {
573  icat = passThroughList_[k];
574  jNeut = fm_invert_ionForNeutral[icat];
575  fmij = fm_neutralMolec_ions_[ icat + jNeut * m_kk];
576  NeutralMolecMoleFractions_[jNeut] += moleFractions_[icat] / fmij;
577  }
578 
579  if (DEBUG_MODE_ENABLED) {
580  for (size_t k = 0; k < m_kk; k++) {
582  }
583  for (jNeut = 0; jNeut < numNeutralMoleculeSpecies_; jNeut++) {
584  for (size_t k = 0; k < m_kk; k++) {
585  fmij = fm_neutralMolec_ions_[k + jNeut * m_kk];
586  moleFractionsTmp_[k] -= fmij * NeutralMolecMoleFractions_[jNeut];
587  }
588  }
589  for (size_t k = 0; k < m_kk; k++) {
590  if (fabs(moleFractionsTmp_[k]) > 1.0E-13) {
591  //! Check to see if we have in fact found the inverse.
592  if (anionList_[0] != k) {
593  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions",
594  "neutral molecule calc error");
595  } else {
596  //! For the single anion case, we will allow some slippage
597  if (fabs(moleFractionsTmp_[k]) > 1.0E-5) {
598  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions",
599  "neutral molecule calc error - anion");
600  }
601  }
602  }
603  }
604  }
605 
606  // Normalize the Neutral Molecule mole fractions
607  sum = 0.0;
608  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
609  sum += NeutralMolecMoleFractions_[k];
610  }
611  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
612  NeutralMolecMoleFractions_[k] /= sum;
613  }
614 
615  break;
616 
617  case cIonSolnType_SINGLECATION:
618 
619  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions", "Unknown type");
620 
621  break;
622 
623  case cIonSolnType_MULTICATIONANION:
624 
625  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions", "Unknown type");
626  break;
627 
628  default:
629 
630  throw CanteraError("IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions", "Unknown type");
631  break;
632 
633  }
634 }
635 
636 void IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads(const doublereal* const dx, doublereal* const dy) const
637 {
638  doublereal sumy, sumdy;
639 
640  //check sum dx = 0
641 
642  //! Zero the vector we are trying to find.
643  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
644  y_[k] = 0.0;
645  dy[k] = 0.0;
646  }
647 
648  switch (ionSolnType_) {
649 
650  case cIonSolnType_PASSTHROUGH:
651  for (size_t k = 0; k < m_kk; k++) {
652  dy[k] = dx[k];
653  }
654  break;
655 
656  case cIonSolnType_SINGLEANION:
657  for (size_t k = 0; k < cationList_.size(); k++) {
658  //! Get the id for the next cation
659  size_t icat = cationList_[k];
660  size_t jNeut = fm_invert_ionForNeutral[icat];
661  if (jNeut != npos) {
662  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
663  AssertTrace(fmij != 0.0);
664  const doublereal temp = 1.0/fmij;
665  dy[jNeut] += dx[icat] * temp;
666  y_[jNeut] += moleFractions_[icat] * temp;
667  }
668  }
669 
670  for (size_t k = 0; k < passThroughList_.size(); k++) {
671  size_t icat = passThroughList_[k];
672  size_t jNeut = fm_invert_ionForNeutral[icat];
673  double fmij = fm_neutralMolec_ions_[ icat + jNeut * m_kk];
674  const doublereal temp = 1.0/fmij;
675  dy[jNeut] += dx[icat] * temp;
676  y_[jNeut] += moleFractions_[icat] * temp;
677  }
678 #ifdef DEBUG_MODE_NOT
679  //check dy sum to zero
680  for (size_t k = 0; k < m_kk; k++) {
681  moleFractionsTmp_[k] = dx[k];
682  }
683  for (jNeut = 0; jNeut < numNeutralMoleculeSpecies_; jNeut++) {
684  for (size_t k = 0; k < m_kk; k++) {
685  fmij = fm_neutralMolec_ions_[k + jNeut * m_kk];
686  moleFractionsTmp_[k] -= fmij * dy[jNeut];
687  }
688  }
689  for (size_t k = 0; k < m_kk; k++) {
690  if (fabs(moleFractionsTmp_[k]) > 1.0E-13) {
691  //! Check to see if we have in fact found the inverse.
692  if (anionList_[0] != k) {
693  throw CanteraError("IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads",
694  "neutral molecule calc error");
695  } else {
696  //! For the single anion case, we will allow some slippage
697  if (fabs(moleFractionsTmp_[k]) > 1.0E-5) {
698  throw CanteraError("IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads",
699  "neutral molecule calc error - anion");
700  }
701  }
702  }
703  }
704 #endif
705  // Normalize the Neutral Molecule mole fractions
706  sumy = 0.0;
707  sumdy = 0.0;
708  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
709  sumy += y_[k];
710  sumdy += dy[k];
711  }
712  sumy = 1.0 / sumy;
713  for (size_t k = 0; k < numNeutralMoleculeSpecies_; k++) {
714  dy[k] = dy[k] * sumy - y_[k]*sumdy*sumy*sumy;
715  }
716 
717  break;
718 
719  case cIonSolnType_SINGLECATION:
720 
721  throw CanteraError("IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads",
722  "Unknown type");
723 
724  break;
725 
726  case cIonSolnType_MULTICATIONANION:
727 
728  throw CanteraError("IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads",
729  "Unknown type");
730  break;
731 
732  default:
733 
734  throw CanteraError("IonsFromNeutralVPSSTP::getNeutralMoleculeMoleGrads",
735  "Unknown type");
736  break;
737 
738  }
739 }
740 
741 void IonsFromNeutralVPSSTP::setMassFractions(const doublereal* const y)
742 {
746 }
747 
748 void IonsFromNeutralVPSSTP::setMassFractions_NoNorm(const doublereal* const y)
749 {
753 }
754 
755 void IonsFromNeutralVPSSTP::setMoleFractions(const doublereal* const x)
756 {
760 }
761 
762 void IonsFromNeutralVPSSTP::setMoleFractions_NoNorm(const doublereal* const x)
763 {
767 }
768 
769 void IonsFromNeutralVPSSTP::setConcentrations(const doublereal* const c)
770 {
774 }
775 
776 /*
777  * ------------ Partial Molar Properties of the Solution ------------
778  */
779 
781 {
782  initLengths();
784 }
785 
787 {
789  moleFractions_.resize(m_kk);
791  fm_invert_ionForNeutral.resize(m_kk);
793  cationList_.resize(m_kk);
794  anionList_.resize(m_kk);
795  passThroughList_.resize(m_kk);
796  moleFractionsTmp_.resize(m_kk);
803 
804  y_.resize(numNeutralMoleculeSpecies_, 0.0);
805  dlnActCoeff_NeutralMolecule_.resize(numNeutralMoleculeSpecies_, 0.0);
806  dX_NeutralMolecule_.resize(numNeutralMoleculeSpecies_, 0.0);
807 
808 }
809 
810 //! Return the factor overlap
811 /*!
812  * @param elnamesVN
813  * @param elemVectorN
814  * @param nElementsN
815  * @param elnamesVI
816  * @param elemVectorI
817  * @param nElementsI
818  */
819 static double factorOverlap(const std::vector<std::string>& elnamesVN ,
820  const std::vector<double>& elemVectorN,
821  const size_t nElementsN,
822  const std::vector<std::string>& elnamesVI ,
823  const std::vector<double>& elemVectorI,
824  const size_t nElementsI)
825 {
826  double fMax = 1.0E100;
827  for (size_t mi = 0; mi < nElementsI; mi++) {
828  if (elnamesVI[mi] != "E") {
829  if (elemVectorI[mi] > 1.0E-13) {
830  double eiNum = elemVectorI[mi];
831  for (size_t mn = 0; mn < nElementsN; mn++) {
832  if (elnamesVI[mi] == elnamesVN[mn]) {
833  if (elemVectorN[mn] <= 1.0E-13) {
834  return 0.0;
835  }
836  fMax = std::min(fMax, elemVectorN[mn]/eiNum);
837  }
838  }
839  }
840  }
841  }
842  return fMax;
843 }
844 void IonsFromNeutralVPSSTP::initThermoXML(XML_Node& phaseNode, const std::string& id_)
845 {
846  if (id_.size() > 0) {
847  if (phaseNode.id() != id_) {
848  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
849  "phasenode and Id are incompatible");
850  }
851  }
852 
853  /*
854  * Find the Thermo XML node
855  */
856  if (!phaseNode.hasChild("thermo")) {
857  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
858  "no thermo XML node");
859  }
860  XML_Node& thermoNode = phaseNode.child("thermo");
861 
862 
863 
864  /*
865  * Make sure that the thermo model is IonsFromNeutralMolecule
866  */
867  string formString = lowercase(thermoNode.attrib("model"));
868  if (formString != "ionsfromneutralmolecule") {
869  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
870  "model name isn't IonsFromNeutralMolecule: " + formString);
871  }
872 
873  /*
874  * Find the Neutral Molecule Phase
875  */
876  if (!thermoNode.hasChild("neutralMoleculePhase")) {
877  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
878  "no neutralMoleculePhase XML node");
879  }
880  XML_Node& neutralMoleculeNode = thermoNode.child("neutralMoleculePhase");
881 
882  XML_Node* neut_ptr = get_XML_Node(neutralMoleculeNode["datasrc"], 0);
883  if (!neut_ptr) {
884  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
885  "neut_ptr = 0");
886  }
887 
888  /*
889  * Create the neutralMolecule ThermoPhase if we haven't already
890  */
891  if (!neutralMoleculePhase_) {
892  neutralMoleculePhase_ = newPhase(*neut_ptr);
893  }
894 
895  cationList_.clear();
896  for (size_t k = 0; k < m_kk; k++) {
897  if (charge(k) > 0) {
898  cationList_.push_back(k);
899  }
900  }
901 
902  anionList_.clear();
903  for (size_t k = 0; k < m_kk; k++) {
904  if (charge(k) < 0) {
905  anionList_.push_back(k);
906  }
907  }
908 
909  passThroughList_.clear();
910  for (size_t k = 0; k < m_kk; k++) {
911  if (charge(k) == 0) {
912  passThroughList_.push_back(k);
913  }
914  }
915 
917  for (size_t k = 0; k < m_kk; k++) {
918  PDSS_IonsFromNeutral* speciesSS =
919  dynamic_cast<PDSS_IonsFromNeutral*>(providePDSS(k));
920  if (!speciesSS) {
921  throw CanteraError("initThermoXML", "Dynamic cast failed");
922  }
923  if (speciesSS->specialSpecies_ == 1) {
925  }
926  if (speciesSS->specialSpecies_ == 2) {
928  }
929  }
930 
931 
932  size_t nElementsN = neutralMoleculePhase_->nElements();
933  const std::vector<std::string>& elnamesVN = neutralMoleculePhase_->elementNames();
934  std::vector<double> elemVectorN(nElementsN);
935  std::vector<double> elemVectorN_orig(nElementsN);
936 
937  size_t nElementsI = nElements();
938  const std::vector<std::string>& elnamesVI = elementNames();
939  std::vector<double> elemVectorI(nElementsI);
940 
941  vector<doublereal> fm_tmp(m_kk);
942  for (size_t k = 0; k < m_kk; k++) {
944  }
945  for (size_t jNeut = 0; jNeut < numNeutralMoleculeSpecies_; jNeut++) {
946  for (size_t m = 0; m < nElementsN; m++) {
947  elemVectorN[m] = neutralMoleculePhase_->nAtoms(jNeut, m);
948  }
949  elemVectorN_orig = elemVectorN;
950  fm_tmp.assign(m_kk, 0.0);
951 
952  for (size_t m = 0; m < nElementsI; m++) {
953  elemVectorI[m] = nAtoms(indexSpecialSpecies_, m);
954  }
955  double fac = factorOverlap(elnamesVN, elemVectorN, nElementsN,
956  elnamesVI ,elemVectorI, nElementsI);
957  if (fac > 0.0) {
958  for (size_t m = 0; m < nElementsN; m++) {
959  std::string mName = elnamesVN[m];
960  for (size_t mi = 0; mi < nElementsI; mi++) {
961  std::string eName = elnamesVI[mi];
962  if (mName == eName) {
963  elemVectorN[m] -= fac * elemVectorI[mi];
964  }
965 
966  }
967  }
968  }
970 
971 
972  for (size_t k = 0; k < m_kk; k++) {
973  for (size_t m = 0; m < nElementsI; m++) {
974  elemVectorI[m] = nAtoms(k, m);
975  }
976  fac = factorOverlap(elnamesVN, elemVectorN, nElementsN,
977  elnamesVI ,elemVectorI, nElementsI);
978  if (fac > 0.0) {
979  for (size_t m = 0; m < nElementsN; m++) {
980  std::string mName = elnamesVN[m];
981  for (size_t mi = 0; mi < nElementsI; mi++) {
982  std::string eName = elnamesVI[mi];
983  if (mName == eName) {
984  elemVectorN[m] -= fac * elemVectorI[mi];
985  }
986 
987  }
988  }
989  bool notTaken = true;
990  for (size_t iNeut = 0; iNeut < jNeut; iNeut++) {
991  if (fm_invert_ionForNeutral[k] == iNeut) {
992  notTaken = false;
993  }
994  }
995  if (notTaken) {
996  fm_invert_ionForNeutral[k] = jNeut;
997  } else {
998  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
999  "Simple formula matrix generation failed, one cation is shared between two salts");
1000  }
1001  }
1002  fm_neutralMolec_ions_[k + jNeut * m_kk] += fac;
1003  }
1004 
1005  // Ok check the work
1006  for (size_t m = 0; m < nElementsN; m++) {
1007  if (fabs(elemVectorN[m]) > 1.0E-13) {
1008  throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML",
1009  "Simple formula matrix generation failed");
1010  }
1011  }
1012 
1013 
1014  }
1015  /*
1016  * This includes the setStateFromXML calls
1017  */
1018  GibbsExcessVPSSTP::initThermoXML(phaseNode, id_);
1019 
1020  /*
1021  * There is one extra step here. We assure ourselves that we
1022  * have charge conservation.
1023  */
1024 }
1025 
1027 {
1028  size_t icat, jNeut;
1029  /*
1030  * Get the activity coefficiens of the neutral molecules
1031  */
1033 
1034  switch (ionSolnType_) {
1035  case cIonSolnType_PASSTHROUGH:
1036  break;
1037  case cIonSolnType_SINGLEANION:
1038 
1039  // Do the cation list
1040  for (size_t k = 0; k < cationList_.size(); k++) {
1041  //! Get the id for the next cation
1042  icat = cationList_[k];
1043  jNeut = fm_invert_ionForNeutral[icat];
1044  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
1045  lnActCoeff_Scaled_[icat] = lnActCoeff_NeutralMolecule_[jNeut] / fmij;
1046  }
1047 
1048  // Do the anion list
1049  icat = anionList_[0];
1050  jNeut = fm_invert_ionForNeutral[icat];
1051  lnActCoeff_Scaled_[icat]= 0.0;
1052 
1053  // Do the list of neutral molecules
1054  for (size_t k = 0; k < passThroughList_.size(); k++) {
1055  icat = passThroughList_[k];
1056  jNeut = fm_invert_ionForNeutral[icat];
1058  }
1059  break;
1060 
1061  case cIonSolnType_SINGLECATION:
1062  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type");
1063  break;
1064  case cIonSolnType_MULTICATIONANION:
1065  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type");
1066  break;
1067  default:
1068  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff", "Unimplemented type");
1069  break;
1070  }
1071 
1072 }
1073 
1074 void IonsFromNeutralVPSSTP::getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds,
1075  doublereal* dlnActCoeffds) const
1076 {
1077  size_t icat, jNeut;
1078  /*
1079  * Get the activity coefficients of the neutral molecules
1080  */
1081  if (!geThermo) {
1082  for (size_t k = 0; k < m_kk; k++) {
1083  dlnActCoeffds[k] = dXds[k] / moleFractions_[k];
1084  }
1085  return;
1086  }
1087 
1088  // static vector_fp dlnActCoeff_NeutralMolecule(numNeutMolSpec);
1089  // static vector_fp dX_NeutralMolecule(numNeutMolSpec);
1090 
1091 
1092  getNeutralMoleculeMoleGrads(DATA_PTR(dXds),DATA_PTR(dX_NeutralMolecule_));
1093 
1094  // All mole fractions returned to normal
1095 
1096  geThermo->getdlnActCoeffds(dTds, DATA_PTR(dX_NeutralMolecule_), DATA_PTR(dlnActCoeff_NeutralMolecule_));
1097 
1098  switch (ionSolnType_) {
1099  case cIonSolnType_PASSTHROUGH:
1100  break;
1101  case cIonSolnType_SINGLEANION:
1102 
1103  // Do the cation list
1104  for (size_t k = 0; k < cationList_.size(); k++) {
1105  //! Get the id for the next cation
1106  icat = cationList_[k];
1107  jNeut = fm_invert_ionForNeutral[icat];
1108  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
1109  dlnActCoeffds[icat] = dlnActCoeff_NeutralMolecule_[jNeut]/fmij;
1110  }
1111 
1112  // Do the anion list
1113  icat = anionList_[0];
1114  jNeut = fm_invert_ionForNeutral[icat];
1115  dlnActCoeffds[icat]= 0.0;
1116 
1117  // Do the list of neutral molecules
1118  for (size_t k = 0; k < passThroughList_.size(); k++) {
1119  icat = passThroughList_[k];
1120  jNeut = fm_invert_ionForNeutral[icat];
1121  dlnActCoeffds[icat] = dlnActCoeff_NeutralMolecule_[jNeut];
1122  }
1123  break;
1124 
1125  case cIonSolnType_SINGLECATION:
1126  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type");
1127  break;
1128  case cIonSolnType_MULTICATIONANION:
1129  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type");
1130  break;
1131  default:
1132  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffds", "Unimplemented type");
1133  break;
1134  }
1135 
1136 }
1137 
1139 {
1140  size_t icat, jNeut;
1141  /*
1142  * Get the activity coefficients of the neutral molecules
1143  */
1144  if (!geThermo) {
1145  dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
1146  return;
1147  }
1148 
1150 
1151  switch (ionSolnType_) {
1152  case cIonSolnType_PASSTHROUGH:
1153  break;
1154  case cIonSolnType_SINGLEANION:
1155 
1156  // Do the cation list
1157  for (size_t k = 0; k < cationList_.size(); k++) {
1158  //! Get the id for the next cation
1159  icat = cationList_[k];
1160  jNeut = fm_invert_ionForNeutral[icat];
1161  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
1163  }
1164 
1165  // Do the anion list
1166  icat = anionList_[0];
1167  jNeut = fm_invert_ionForNeutral[icat];
1168  dlnActCoeffdT_Scaled_[icat]= 0.0;
1169 
1170  // Do the list of neutral molecules
1171  for (size_t k = 0; k < passThroughList_.size(); k++) {
1172  icat = passThroughList_[k];
1173  jNeut = fm_invert_ionForNeutral[icat];
1175  }
1176  break;
1177 
1178  case cIonSolnType_SINGLECATION:
1179  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type");
1180  break;
1181  case cIonSolnType_MULTICATIONANION:
1182  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type");
1183  break;
1184  default:
1185  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeffdT", "Unimplemented type");
1186  break;
1187  }
1188 
1189 }
1190 
1192 {
1193  size_t icat, jNeut;
1194  /*
1195  * Get the activity coefficients of the neutral molecules
1196  */
1197  if (!geThermo) {
1198  dlnActCoeffdlnX_diag_.assign(m_kk, 0.0);
1199  return;
1200  }
1201 
1203 
1204  switch (ionSolnType_) {
1205  case cIonSolnType_PASSTHROUGH:
1206  break;
1207  case cIonSolnType_SINGLEANION:
1208 
1209  // Do the cation list
1210  for (size_t k = 0; k < cationList_.size(); k++) {
1211  //! Get the id for the next cation
1212  icat = cationList_[k];
1213  jNeut = fm_invert_ionForNeutral[icat];
1214  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
1216  }
1217 
1218  // Do the anion list
1219  icat = anionList_[0];
1220  jNeut = fm_invert_ionForNeutral[icat];
1221  dlnActCoeffdlnX_diag_[icat]= 0.0;
1222 
1223  // Do the list of neutral molecules
1224  for (size_t k = 0; k < passThroughList_.size(); k++) {
1225  icat = passThroughList_[k];
1226  jNeut = fm_invert_ionForNeutral[icat];
1228  }
1229  break;
1230 
1231  case cIonSolnType_SINGLECATION:
1232  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type");
1233  break;
1234  case cIonSolnType_MULTICATIONANION:
1235  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type");
1236  break;
1237  default:
1238  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnX_diag()", "Unimplemented type");
1239  break;
1240  }
1241 
1242 }
1243 
1245 {
1246  size_t icat, jNeut;
1247  /*
1248  * Get the activity coefficients of the neutral molecules
1249  */
1250  if (!geThermo) {
1251  dlnActCoeffdlnN_diag_.assign(m_kk, 0.0);
1252  return;
1253  }
1254 
1256 
1257  switch (ionSolnType_) {
1258  case cIonSolnType_PASSTHROUGH:
1259  break;
1260  case cIonSolnType_SINGLEANION:
1261 
1262  // Do the cation list
1263  for (size_t k = 0; k < cationList_.size(); k++) {
1264  //! Get the id for the next cation
1265  icat = cationList_[k];
1266  jNeut = fm_invert_ionForNeutral[icat];
1267  double fmij = fm_neutralMolec_ions_[icat + jNeut * m_kk];
1269  }
1270 
1271  // Do the anion list
1272  icat = anionList_[0];
1273  jNeut = fm_invert_ionForNeutral[icat];
1274  dlnActCoeffdlnN_diag_[icat]= 0.0;
1275 
1276  // Do the list of neutral molecules
1277  for (size_t k = 0; k < passThroughList_.size(); k++) {
1278  icat = passThroughList_[k];
1279  jNeut = fm_invert_ionForNeutral[icat];
1281  }
1282  break;
1283 
1284  case cIonSolnType_SINGLECATION:
1285  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type");
1286  break;
1287  case cIonSolnType_MULTICATIONANION:
1288  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type");
1289  break;
1290  default:
1291  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN_diag()", "Unimplemented type");
1292  break;
1293  }
1294 
1295 }
1296 
1298 {
1299  size_t kcat = 0, kNeut = 0, mcat = 0, mNeut = 0;
1300  doublereal fmij = 0.0;
1302  /*
1303  * Get the activity coefficients of the neutral molecules
1304  */
1305  if (!geThermo) {
1306  throw CanteraError("IonsFromNeutralVPSSTP::s_update_dlnActCoeff_dlnN()", "dynamic cast failed");
1307  }
1308  size_t nsp_ge = geThermo->nSpecies();
1309  geThermo->getdlnActCoeffdlnN(nsp_ge, &(dlnActCoeffdlnN_NeutralMolecule_(0,0)));
1310 
1311  switch (ionSolnType_) {
1312  case cIonSolnType_PASSTHROUGH:
1313  break;
1314  case cIonSolnType_SINGLEANION:
1315 
1316  // Do the cation list
1317  for (size_t k = 0; k < cationList_.size(); k++) {
1318  for (size_t m = 0; m < cationList_.size(); m++) {
1319  kcat = cationList_[k];
1320 
1321  kNeut = fm_invert_ionForNeutral[kcat];
1322  fmij = fm_neutralMolec_ions_[kcat + kNeut * m_kk];
1324 
1325  mcat = cationList_[m];
1326  mNeut = fm_invert_ionForNeutral[mcat];
1327  double mfmij = fm_neutralMolec_ions_[mcat + mNeut * m_kk];
1328 
1329  dlnActCoeffdlnN_(kcat,mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut,mNeut) * mfmij / fmij;
1330 
1331  }
1332  for (size_t m = 0; m < passThroughList_.size(); m++) {
1333  mcat = passThroughList_[m];
1334  mNeut = fm_invert_ionForNeutral[mcat];
1335  dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut, mNeut) / fmij;
1336  }
1337  }
1338 
1339  // Do the anion list -> anion activity coefficient is one
1340  kcat = anionList_[0];
1341  kNeut = fm_invert_ionForNeutral[kcat];
1342  for (size_t k = 0; k < m_kk; k++) {
1343  dlnActCoeffdlnN_(kcat, k) = 0.0;
1344  dlnActCoeffdlnN_(k, kcat) = 0.0;
1345  }
1346 
1347  // Do the list of neutral molecules
1348  for (size_t k = 0; k < passThroughList_.size(); k++) {
1349  kcat = passThroughList_[k];
1350  kNeut = fm_invert_ionForNeutral[kcat];
1352 
1353  for (size_t m = 0; m < m_kk; m++) {
1354  mcat = passThroughList_[m];
1355  mNeut = fm_invert_ionForNeutral[mcat];
1356  dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut, mNeut);
1357  }
1358 
1359 
1360  for (size_t m = 0; m < cationList_.size(); m++) {
1361  mcat = cationList_[m];
1362  mNeut = fm_invert_ionForNeutral[mcat];
1363  dlnActCoeffdlnN_(kcat, mcat) = dlnActCoeffdlnN_NeutralMolecule_(kNeut,mNeut);
1364  }
1365 
1366  }
1367  break;
1368 
1369  case cIonSolnType_SINGLECATION:
1370  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type");
1371  break;
1372  case cIonSolnType_MULTICATIONANION:
1373  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type");
1374  break;
1375  default:
1376  throw CanteraError("IonsFromNeutralVPSSTP::s_update_lnActCoeff_dlnN", "Unimplemented type");
1377  break;
1378  }
1379 }
1380 
1381 }
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal *const dlnActCoeffdlnN)
Get the array of derivatives of the log activity coefficients with respect to the log of the species ...
XML_Node * get_XML_Node(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:214
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition: Phase.cpp:243
virtual void setMassFractions(const doublereal *const y)
Set the mass fractions to the specified values, and then normalize them so that they sum to 1...
virtual void setMoleFractions_NoNorm(const doublereal *const x)
Set the mole fractions to the specified values without normalizing.
Definition: Phase.cpp:367
ThermoPhase * newPhase(XML_Node &xmlphase)
Create a new ThermoPhase object and initializes it according to the XML tree.
std::vector< doublereal > m_pp
Temporary storage space that is fair game.
virtual doublereal density() const
Density (kg/m^3).
Definition: Phase.h:608
virtual ~IonsFromNeutralVPSSTP()
Destructor.
virtual ThermoPhase * duplMyselfAsThermoPhase() const
Duplication routine for objects which inherit from ThermoPhase.
virtual void setConcentrations(const doublereal *const c)
Set the concentrations to the specified values within the phase.
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
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
Derived class for pressure dependent standard states of an ideal gas species.
IonsFromNeutralVPSSTP & operator=(const IonsFromNeutralVPSSTP &b)
Assignment operator.
size_t nElements() const
Number of elements.
Definition: Phase.cpp:167
static double factorOverlap(const std::vector< std::string > &elnamesVN, const std::vector< double > &elemVectorN, const size_t nElementsN, const std::vector< std::string > &elnamesVI, const std::vector< double > &elemVectorI, const size_t nElementsI)
Return the factor overlap.
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:527
std::vector< double > fm_neutralMolec_ions_
Formula Matrix for composition of neutral molecules in terms of the molecules in this ThermoPhase...
GibbsExcessVPSSTP & operator=(const GibbsExcessVPSSTP &b)
Assignment operator.
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:121
std::string findInputFile(const std::string &name)
Find an input file.
Definition: global.cpp:156
Header for intermediate ThermoPhase object for phases which consist of ions whose thermodynamics is c...
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
vector_fp m_speciesCharge
Vector of species charges. length m_kk.
Definition: Phase.h:858
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
size_t indexSpecialSpecies_
Index of special species.
virtual void calcNeutralMoleculeMoleFractions() const
Calculate neutral molecule mole fractions.
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
virtual void calcIonMoleFractions(doublereal *const mf) const
Calculate ion mole fractions from neutral molecule mole fractions.
void constructPhaseFile(std::string inputFile, std::string id)
The following methods are used in the process of constructing the phase and setting its parameters fr...
virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const
Get the array of ln mole fraction derivatives of the log activity coefficients - diagonal component o...
Definition: ThermoPhase.h:1522
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity for the species at their standard states at the...
Definition: ThermoPhase.h:670
std::string lowercase(const std::string &s)
Cast a copy of a string to lower case.
Definition: stringUtils.cpp:73
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:556
void s_update_dlnActCoeff_dlnN_diag() const
Update the derivative of the log of the activity coefficients wrt log(number of moles) - diagonal com...
std::vector< doublereal > dlnActCoeffdlnN_diag_
Storage for the current derivative values of the gradients with respect to logarithm of the mole frac...
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
bool IOwnNThermoPhase_
If true then we own the underlying neutral Molecule Phase.
void getDissociationCoeffs(vector_fp &fm_neutralMolec_ions, vector_fp &charges, std::vector< size_t > &neutMolIndex) const
Get the Salt Dissociation Coefficients Returns the vector of dissociation coefficients and vector of ...
void constructPhaseXML(XML_Node &phaseNode, std::string id)
Import and initialize an IonsFromNeutralVPSSTP phase specification in an XML tree into the current ob...
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
virtual int eosType() const
Equation of state type flag.
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:97
doublereal mean_X(const doublereal *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
Definition: Phase.cpp:687
bool importPhase(XML_Node &phase, ThermoPhase *th, SpeciesThermoFactory *spfactory)
Import a phase information into an empty ThermoPhase object.
virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const
Get the array of log concentration-like derivatives of the log activity coefficients - diagonal compo...
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
virtual doublereal enthalpy_mole() const
Return the Molar enthalpy. Units: J/kmol.
virtual void setTemperature(const doublereal t)
Set the temperature of the phase.
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
doublereal pressure() const
Returns the current pressure of the phase.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies for the species in the mixture.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:28
virtual void setConcentrations(const doublereal *const c)
Set the concentrations to the specified values within the phase.
virtual void getdlnActCoeffdlnN_diag(doublereal *dlnActCoeffdlnN_diag) const
Get the array of log concentration-like derivatives of the log activity coefficients.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:554
IonSolnType_enumType ionSolnType_
Ion solution type.
virtual void getdlnActCoeffdT(doublereal *dlnActCoeffdT) const
Get the array of temperature derivatives of the log activity coefficients.
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal *const dlnActCoeffdlnN)
Get the array of derivatives of the ln activity coefficients with respect to the ln species mole numb...
Array2D dlnActCoeffdlnN_NeutralMolecule_
Storage vector for the neutral molecule d ln activity coefficients dlnN.
virtual void getdlnActCoeffds(const doublereal dTds, const doublereal *const dXds, doublereal *dlnActCoeffds) const
Get the change in activity coefficients wrt changes in state (temp, mole fraction, etc) along a line in parameter space or along a line in physical space.
Definition: ThermoPhase.h:1500
std::vector< doublereal > dlnActCoeffdT_NeutralMolecule_
Storage vector for the neutral molecule d ln activity coefficients dT.
void initLengths()
Initialize lengths of local variables after all species have been identified.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values, and then normalize them so that they sum to 1...
std::vector< doublereal > muNeutralMolecule_
Storage vector for the neutral molecule chemical potentials.
void s_update_dlnActCoeffdT() const
Update the temperature derivative of the ln activity coefficients.
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values There is no restriction on the sum of the mole fractio...
Definition: Phase.cpp:331
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:563
const std::vector< std::string > & elementNames() const
Return a read-only reference to the vector of element names.
Definition: Phase.cpp:202
virtual void setMassFractions(const doublereal *const y)
Set the mass fractions to the specified values, and then normalize them so that they sum to 1...
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values, and then normalize them so that they sum to 1...
virtual void setMassFractions_NoNorm(const doublereal *const y)
Set the mass fractions to the specified values without normalizing.
void s_update_dlnActCoeff_dlnX_diag() const
Update the derivative of the log of the activity coefficients wrt log(mole fraction) ...
std::vector< size_t > anionList_
List of the species in this ThermoPhase which are anion species.
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
std::vector< size_t > passThroughList_
List of the species in this ThermoPhase which are passed through to the neutralMoleculePhase ThermoPh...
void s_update_dlnActCoeff_dlnN() const
Update the derivative of the log of the activity coefficients wrt log(number of moles) - diagonal com...
std::vector< doublereal > lnActCoeff_NeutralMolecule_
Storage vector for the neutral molecule ln activity coefficients.
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:265
void getNeutralMoleculeMoleGrads(const doublereal *const dx, doublereal *const dy) const
Calculate neutral molecule mole fractions.
std::vector< doublereal > dlnActCoeffdlnX_diag_
Storage for the current derivative values of the gradients with respect to logarithm of the mole frac...
#define AssertTrace(expr)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:270
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:602
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:448
virtual void getdlnActCoeffdlnX_diag(doublereal *dlnActCoeffdlnX_diag) const
Get the array of log concentration-like derivatives of the log activity coefficients - diagonal compo...
const doublereal SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:126
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:157
virtual void getLnActivityCoefficients(doublereal *lnac) const
Get the array of non-dimensional molar-based ln activity coefficients at the current solution tempera...
std::vector< doublereal > moleFractions_
Storage for the current values of the mole fractions of the species.
std::vector< size_t > fm_invert_ionForNeutral
Mapping between ion species and neutral molecule for quick invert.
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:64
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Initialize a ThermoPhase object, potentially reading activity coefficient information from an XML dat...
virtual void setMoleFractions_NoNorm(const doublereal *const x)
Set the mole fractions to the specified values without normalizing.
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
std::vector< doublereal > dlnActCoeffdlnN_diag_NeutralMolecule_
Storage vector for the neutral molecule d ln activity coefficients dlnN - diagonal component...
std::vector< size_t > cationList_
List of the species in this ThermoPhase which are cation species.
virtual doublereal gibbs_mole() const
Molar Gibbs free Energy for an ideal gas. Units = J/kmol.
void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object.
void setXMLdata(XML_Node &xmlPhase)
Stores the XML tree information for the current phase.
Definition: Phase.cpp:128
size_t m_kk
Number of species in the phase.
Definition: Phase.h:843
Array2D dlnActCoeffdlnN_
Storage for the current derivative values of the gradients with respect to logarithm of the species m...
std::vector< doublereal > dlnActCoeffdlnX_diag_NeutralMolecule_
Storage vector for the neutral molecule d ln activity coefficients dX - diagonal component.
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
Definition: ThermoPhase.h:618
virtual void getdlnActCoeffds(const doublereal dTds, const doublereal *const dXds, doublereal *dlnActCoeffds) const
Get the change in activity coefficients w.r.t.
void zero()
Set all of the entries to zero.
Definition: Array.h:251
virtual void setMoleFractions_NoNorm(const doublereal *const x)
Set the mole fractions to the specified values without normalizing.
std::vector< doublereal > NeutralMolecMoleFractions_
Mole fractions using the Neutral Molecule Mole fraction basis.
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
virtual void setMassFractions_NoNorm(const doublereal *const y)
Set the mass fractions to the specified values without normalizing.
size_t indexSecondSpecialSpecies_
Index of special species.
Declarations for the class PDSS_IonsFromNeutral ( which handles calculations for a single ion in a fl...
size_t numNeutralMoleculeSpecies_
Number of neutral molecule species.
ThermoPhase * neutralMoleculePhase_
This is a pointer to the neutral Molecule Phase.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
void build(std::istream &f)
Main routine to create an tree-like representation of an XML file.
Definition: xml.cpp:764
void s_update_lnActCoeff() const
Update the activity coefficients.
int specialSpecies_
True if this species is the special species.
std::vector< doublereal > dlnActCoeffdT_Scaled_
Storage for the current derivative values of the gradients with respect to temperature of the log of ...
virtual void setDensity(const doublereal density_)
Set the internally stored density (kg/m^3) of the phase Note the density of a phase is an independent...
Definition: Phase.h:623
virtual void setState_TP(doublereal T, doublereal pres)
Set the temperature and pressure at the same time.
std::vector< doublereal > moleFractionsTmp_
Temporary mole fraction vector.
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
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:578