Cantera 2.6.0

DebyeHuckel.cpp
Go to the documentation of this file.
1/**
2 * @file DebyeHuckel.cpp
3 * Declarations for the DebyeHuckel ThermoPhase object, which models dilute
4 * electrolyte solutions
5 * (see \ref thermoprops and \link Cantera::DebyeHuckel DebyeHuckel \endlink).
6 *
7 * Class DebyeHuckel represents a dilute liquid electrolyte phase which
8 * obeys the Debye Huckel formulation for nonideality.
9 */
10
11// This file is part of Cantera. See License.txt in the top-level directory or
12// at https://cantera.org/license.txt for license and copyright information.
13
14#include "cantera/thermo/DebyeHuckel.h"
15#include "cantera/thermo/ThermoFactory.h"
16#include "cantera/thermo/Species.h"
17#include "cantera/thermo/PDSS_Water.h"
18#include "cantera/thermo/PDSS_ConstVol.h"
19#include "cantera/thermo/electrolytes.h"
20#include "cantera/base/stringUtils.h"
21#include "cantera/base/ctml.h"
22
23#include <cstdio>
24
25 using namespace std;
26
27 namespace Cantera
28{
29
30 namespace {
31 double A_Debye_default = 1.172576; // units = sqrt(kg/gmol)
32 double B_Debye_default = 3.28640E9; // units = sqrt(kg/gmol) / m
33 double maxIionicStrength_default = 30.0;
34}
35
36 DebyeHuckel::DebyeHuckel(const std::string& inputFile,
37 const std::string& id_) :
38 m_formDH(DHFORM_DILUTE_LIMIT),
39 m_Aionic_default(NAN),
40 m_IionicMolality(0.0),
41 m_maxIionicStrength(maxIionicStrength_default),
42 m_useHelgesonFixedForm(false),
43 m_IionicMolalityStoich(0.0),
44 m_form_A_Debye(A_DEBYE_CONST),
45 m_A_Debye(A_Debye_default),
46 m_B_Debye(B_Debye_default),
47 m_waterSS(0),
48 m_densWaterSS(1000.)
49{
50 initThermoFile(inputFile, id_);
51}
52
53 DebyeHuckel::DebyeHuckel(XML_Node& phaseRoot, const std::string& id_) :
54 m_formDH(DHFORM_DILUTE_LIMIT),
55 m_Aionic_default(NAN),
56 m_IionicMolality(0.0),
57 m_maxIionicStrength(maxIionicStrength_default),
58 m_useHelgesonFixedForm(false),
59 m_IionicMolalityStoich(0.0),
60 m_form_A_Debye(A_DEBYE_CONST),
61 m_A_Debye(A_Debye_default),
62 m_B_Debye(B_Debye_default),
63 m_waterSS(0),
64 m_densWaterSS(1000.)
65{
66 importPhase(phaseRoot, this);
67}
68
69DebyeHuckel::~DebyeHuckel()
70{
71}
72
73// -------- Molar Thermodynamic Properties of the Solution ---------------
74
75doublereal DebyeHuckel::enthalpy_mole() const
76{
77 getPartialMolarEnthalpies(m_tmpV.data());
78 return mean_X(m_tmpV);
79}
80
81doublereal DebyeHuckel::entropy_mole() const
82{
83 getPartialMolarEntropies(m_tmpV.data());
84 return mean_X(m_tmpV);
85}
86
87doublereal DebyeHuckel::gibbs_mole() const
88{
89 getChemPotentials(m_tmpV.data());
90 return mean_X(m_tmpV);
91}
92
93doublereal DebyeHuckel::cp_mole() const
94{
95 getPartialMolarCp(m_tmpV.data());
96 return mean_X(m_tmpV);
97}
98
99// ------- Mechanical Equation of State Properties ------------------------
100
101 void DebyeHuckel::calcDensity()
102{
103 if (m_waterSS) {
104 // Store the internal density of the water SS. Note, we would have to do
105 // this for all other species if they had pressure dependent properties.
106 m_densWaterSS = m_waterSS->density();
107 }
108 getPartialMolarVolumes(m_tmpV.data());
109 double dd = meanMolecularWeight() / mean_X(m_tmpV);
110 Phase::assignDensity(dd);
111}
112
113// ------- Activities and Activity Concentrations
114
115 void DebyeHuckel::getActivityConcentrations(doublereal* c) const
116{
117 double c_solvent = standardConcentration();
118 getActivities(c);
119 for (size_t k = 0; k < m_kk; k++) {
120 c[k] *= c_solvent;
121 }
122}
123
124doublereal DebyeHuckel::standardConcentration(size_t k) const
125{
126 double mvSolvent = providePDSS(0)->molarVolume();
127 return 1.0 / mvSolvent;
128}
129
130 void DebyeHuckel::getActivities(doublereal* ac) const
131{
132 _updateStandardStateThermo();
133
134 // Update the molality array, m_molalities(). This requires an update due to
135 // mole fractions
136 s_update_lnMolalityActCoeff();
137 for (size_t k = 1; k < m_kk; k++) {
138 ac[k] = m_molalities[k] * exp(m_lnActCoeffMolal[k]);
139 }
140 double xmolSolvent = moleFraction(0);
141 ac[0] = exp(m_lnActCoeffMolal[0]) * xmolSolvent;
142}
143
144 void DebyeHuckel::getMolalityActivityCoefficients(doublereal* acMolality) const
145{
146 _updateStandardStateThermo();
147 A_Debye_TP(-1.0, -1.0);
148 s_update_lnMolalityActCoeff();
149 copy(m_lnActCoeffMolal.begin(), m_lnActCoeffMolal.end(), acMolality);
150 for (size_t k = 0; k < m_kk; k++) {
151 acMolality[k] = exp(acMolality[k]);
152 }
153}
154
155// ------ Partial Molar Properties of the Solution -----------------
156
157 void DebyeHuckel::getChemPotentials(doublereal* mu) const
158{
159 double xx;
160
161 // First get the standard chemical potentials in molar form. This requires
162 // updates of standard state as a function of T and P
163 getStandardChemPotentials(mu);
164
165 // Update the activity coefficients. This also updates the internal molality
166 // array.
167 s_update_lnMolalityActCoeff();
168 double xmolSolvent = moleFraction(0);
169 for (size_t k = 1; k < m_kk; k++) {
170 xx = std::max(m_molalities[k], SmallNumber);
171 mu[k] += RT() * (log(xx) + m_lnActCoeffMolal[k]);
172 }
173 xx = std::max(xmolSolvent, SmallNumber);
174 mu[0] += RT() * (log(xx) + m_lnActCoeffMolal[0]);
175}
176
177 void DebyeHuckel::getPartialMolarEnthalpies(doublereal* hbar) const
178{
179 // Get the nondimensional standard state enthalpies
180 getEnthalpy_RT(hbar);
181
182 // Dimensionalize it.
183 for (size_t k = 0; k < m_kk; k++) {
184 hbar[k] *= RT();
185 }
186
187 // Check to see whether activity coefficients are temperature
188 // dependent. If they are, then calculate the their temperature
189 // derivatives and add them into the result.
190 double dAdT = dA_DebyedT_TP();
191 if (dAdT != 0.0) {
192 // Update the activity coefficients, This also update the
193 // internally stored molalities.
194 s_update_lnMolalityActCoeff();
195 s_update_dlnMolalityActCoeff_dT();
196 for (size_t k = 0; k < m_kk; k++) {
197 hbar[k] -= RT() * temperature() * m_dlnActCoeffMolaldT[k];
198 }
199 }
200}
201
202 void DebyeHuckel::getPartialMolarEntropies(doublereal* sbar) const
203{
204 // Get the standard state entropies at the temperature and pressure of the
205 // solution.
206 getEntropy_R(sbar);
207
208 // Dimensionalize the entropies
209 for (size_t k = 0; k < m_kk; k++) {
210 sbar[k] *= GasConstant;
211 }
212
213 // Update the activity coefficients, This also update the internally stored
214 // molalities.
215 s_update_lnMolalityActCoeff();
216
217 // First we will add in the obvious dependence on the T term out front of
218 // the log activity term
219 doublereal mm;
220 for (size_t k = 1; k < m_kk; k++) {
221 mm = std::max(SmallNumber, m_molalities[k]);
222 sbar[k] -= GasConstant * (log(mm) + m_lnActCoeffMolal[k]);
223 }
224 double xmolSolvent = moleFraction(0);
225 mm = std::max(SmallNumber, xmolSolvent);
226 sbar[0] -= GasConstant *(log(mm) + m_lnActCoeffMolal[0]);
227
228 // Check to see whether activity coefficients are temperature dependent. If
229 // they are, then calculate the their temperature derivatives and add them
230 // into the result.
231 double dAdT = dA_DebyedT_TP();
232 if (dAdT != 0.0) {
233 s_update_dlnMolalityActCoeff_dT();
234 for (size_t k = 0; k < m_kk; k++) {
235 sbar[k] -= RT() * m_dlnActCoeffMolaldT[k];
236 }
237 }
238}
239
240 void DebyeHuckel::getPartialMolarVolumes(doublereal* vbar) const
241{
242 getStandardVolumes(vbar);
243
244 // Update the derivatives wrt the activity coefficients.
245 s_update_lnMolalityActCoeff();
246 s_update_dlnMolalityActCoeff_dP();
247 for (size_t k = 0; k < m_kk; k++) {
248 vbar[k] += RT() * m_dlnActCoeffMolaldP[k];
249 }
250}
251
252 void DebyeHuckel::getPartialMolarCp(doublereal* cpbar) const
253{
254 getCp_R(cpbar);
255 for (size_t k = 0; k < m_kk; k++) {
256 cpbar[k] *= GasConstant;
257 }
258
259 // Check to see whether activity coefficients are temperature dependent. If
260 // they are, then calculate the their temperature derivatives and add them
261 // into the result.
262 double dAdT = dA_DebyedT_TP();
263 if (dAdT != 0.0) {
264 // Update the activity coefficients, This also update the internally
265 // stored molalities.
266 s_update_lnMolalityActCoeff();
267 s_update_dlnMolalityActCoeff_dT();
268 s_update_d2lnMolalityActCoeff_dT2();
269 for (size_t k = 0; k < m_kk; k++) {
270 cpbar[k] -= (2.0 * RT() * m_dlnActCoeffMolaldT[k] +
271 RT() * temperature() * m_d2lnActCoeffMolaldT2[k]);
272 }
273 }
274}
275
276// -------------- Utilities -------------------------------
277
278//! Utility function to assign an integer value from a string for the
279//! ElectrolyteSpeciesType field.
280/*!
281 * @param estString input string that will be interpreted
282 */
283 static int interp_est(const std::string& estString)
284{
285 if (caseInsensitiveEquals(estString, "solvent")) {
286 return cEST_solvent;
287 } else if (estString == "charged-species"
288 || caseInsensitiveEquals(estString, "chargedspecies")) {
289 return cEST_chargedSpecies;
290 } else if (estString == "weak-acid-associated"
291 || caseInsensitiveEquals(estString, "weakacidassociated")) {
292 return cEST_weakAcidAssociated;
293 } else if (estString == "strong-acid-associated"
294 || caseInsensitiveEquals(estString, "strongacidassociated")) {
295 return cEST_strongAcidAssociated;
296 } else if (estString == "polar-neutral"
297 || caseInsensitiveEquals(estString, "polarneutral")) {
298 return cEST_polarNeutral;
299 } else if (estString == "nonpolar-neutral"
300 || caseInsensitiveEquals(estString, "nonpolarneutral")) {
301 return cEST_nonpolarNeutral;
302 } else {
303 throw CanteraError("interp_est (DebyeHuckel)",
304 "Invalid electrolyte species type '{}'", estString);
305 }
306}
307
308 void DebyeHuckel::setDebyeHuckelModel(const std::string& model) {
309 if (model == ""
310 || model == "dilute-limit"
311 || caseInsensitiveEquals(model, "Dilute_limit")) {
312 m_formDH = DHFORM_DILUTE_LIMIT;
313 } else if (model == "B-dot-with-variable-a"
314 || caseInsensitiveEquals(model, "Bdot_with_variable_a")) {
315 m_formDH = DHFORM_BDOT_AK;
316 } else if (model == "B-dot-with-common-a"
317 || caseInsensitiveEquals(model, "Bdot_with_common_a")) {
318 m_formDH = DHFORM_BDOT_ACOMMON;
319 } else if (caseInsensitiveEquals(model, "beta_ij")) {
320 m_formDH = DHFORM_BETAIJ;
321 m_Beta_ij.resize(m_kk, m_kk, 0.0);
322 } else if (model == "Pitzer-with-beta_ij"
323 || caseInsensitiveEquals(model, "Pitzer_with_Beta_ij")) {
324 m_formDH = DHFORM_PITZER_BETAIJ;
325 m_Beta_ij.resize(m_kk, m_kk, 0.0);
326 } else {
327 throw CanteraError("DebyeHuckel::setDebyeHuckelModel",
328 "Unknown model '{}'", model);
329 }
330}
331
332 void DebyeHuckel::setA_Debye(double A)
333{
334 if (A < 0) {
335 m_form_A_Debye = A_DEBYE_WATER;
336 } else {
337 m_form_A_Debye = A_DEBYE_CONST;
338 m_A_Debye = A;
339 }
340}
341
342 void DebyeHuckel::setB_dot(double bdot)
343{
344 if (m_formDH == DHFORM_BETAIJ || m_formDH == DHFORM_DILUTE_LIMIT ||
345 m_formDH == DHFORM_PITZER_BETAIJ) {
346 throw CanteraError("DebyeHuckel::setB_dot",
347 "B_dot entry in the wrong DH form");
348 }
349 // Set B_dot parameters for charged species
350 for (size_t k = 0; k < nSpecies(); k++) {
351 if (fabs(charge(k)) > 0.0001) {
352 m_B_Dot[k] = bdot;
353 } else {
354 m_B_Dot[k] = 0.0;
355 }
356 }
357}
358
359 void DebyeHuckel::setDefaultIonicRadius(double value)
360{
361 m_Aionic_default = value;
362 for (size_t k = 0; k < m_kk; k++) {
363 if (std::isnan(m_Aionic[k])) {
364 m_Aionic[k] = value;
365 }
366 }
367}
368
369 void DebyeHuckel::setBeta(const std::string& sp1, const std::string& sp2,
370 double value)
371{
372 size_t k1 = speciesIndex(sp1);
373 if (k1 == npos) {
374 throw CanteraError("DebyeHuckel::setBeta", "Species '{}' not found", sp1);
375 }
376 size_t k2 = speciesIndex(sp2);
377 if (k2 == npos) {
378 throw CanteraError("DebyeHuckel::setBeta", "Species '{}' not found", sp2);
379 }
380 m_Beta_ij(k1, k2) = value;
381 m_Beta_ij(k2, k1) = value;
382}
383
384 void DebyeHuckel::initThermoXML(XML_Node& phaseNode, const std::string& id_)
385{
386 if (id_.size() > 0) {
387 std::string idp = phaseNode.id();
388 if (idp != id_) {
389 throw CanteraError("DebyeHuckel::initThermoXML",
390 "phasenode and Id are incompatible");
391 }
392 }
393
394 // Find the Thermo XML node
395 if (!phaseNode.hasChild("thermo")) {
396 throw CanteraError("DebyeHuckel::initThermoXML",
397 "no thermo XML node");
398 }
399 XML_Node& thermoNode = phaseNode.child("thermo");
400
401 // Determine the form of the Debye-Huckel model, m_formDH. We will use
402 // this information to size arrays below. If there is no XML node named
403 // "activityCoefficients", assume that we are doing the extreme dilute
404 // limit assumption
405 if (thermoNode.hasChild("activityCoefficients")) {
406 setDebyeHuckelModel(thermoNode.child("activityCoefficients")["model"]);
407 } else {
408 setDebyeHuckelModel("Dilute_limit");
409 }
410
411 // Go get all of the coefficients and factors in the activityCoefficients
412 // XML block
413 XML_Node* acNodePtr = 0;
414 if (thermoNode.hasChild("activityCoefficients")) {
415 XML_Node& acNode = thermoNode.child("activityCoefficients");
416 acNodePtr = &acNode;
417
418 // Look for parameters for A_Debye
419 if (acNode.hasChild("A_Debye")) {
420 XML_Node* ss = acNode.findByName("A_Debye");
421 string modelString = ss->attrib("model");
422 if (modelString != "") {
423 if (caseInsensitiveEquals(modelString, "water")) {
424 setA_Debye(-1);
425 } else {
426 throw CanteraError("DebyeHuckel::initThermoXML",
427 "A_Debye Model \"" + modelString +
428 "\" is not known");
429 }
430 } else {
431 setA_Debye(getFloat(acNode, "A_Debye"));
432 }
433 }
434
435 // Look for parameters for B_Debye
436 if (acNode.hasChild("B_Debye")) {
437 setB_Debye(getFloat(acNode, "B_Debye"));
438 }
439
440 // Look for parameters for B_dot
441 if (acNode.hasChild("B_dot")) {
442 setB_dot(getFloat(acNode, "B_dot"));
443 }
444
445 // Look for Parameters for the Maximum Ionic Strength
446 if (acNode.hasChild("maxIonicStrength")) {
447 setMaxIonicStrength(getFloat(acNode, "maxIonicStrength"));
448 }
449
450 // Look for Helgeson Parameters
451 useHelgesonFixedForm(acNode.hasChild("UseHelgesonFixedForm"));
452
453 // Look for parameters for the Ionic radius
454 if (acNode.hasChild("ionicRadius")) {
455 XML_Node& irNode = acNode.child("ionicRadius");
456
457 double Afactor = 1.0;
458 if (irNode.hasAttrib("units")) {
459 std::string Aunits = irNode.attrib("units");
460 Afactor = toSI(Aunits);
461 }
462
463 if (irNode.hasAttrib("default")) {
464 setDefaultIonicRadius(Afactor * fpValue(irNode.attrib("default")));
465 }
466
467 // If the Debye-Huckel form is BDOT_AK, we can have separate values
468 // for the denominator's ionic size. -> That's how the activity
469 // coefficient is parameterized. In this case only do we allow the
470 // code to read in these parameters.
471 if (m_formDH == DHFORM_BDOT_AK) {
472 // Define a string-string map, and interpret the value of the
473 // XML element as binary pairs separated by colons, for example:
474 // Na+:3.0
475 // Cl-:4.0
476 // H+:9.0
477 // OH-:3.5
478 // Read them into the map.
479 map<string, string> m;
480 getMap(irNode, m);
481
482 // Iterate over the map pairs, interpreting the first string as
483 // a species in the current phase. If no match is made, silently
484 // ignore the lack of agreement (HKM -> may be changed in the
485 // future).
486 for (const auto& b : m) {
487 size_t k = speciesIndex(b.first);
488 if (k != npos) {
489 m_Aionic[k] = fpValue(b.second) * Afactor;
490 }
491 }
492 }
493 }
494
495 // Get the matrix of coefficients for the Beta binary interaction
496 // parameters. We assume here that this matrix is symmetric, so that we
497 // only have to input 1/2 of the values.
498 if (acNode.hasChild("DHBetaMatrix")) {
499 if (m_formDH == DHFORM_BETAIJ ||
500 m_formDH == DHFORM_PITZER_BETAIJ) {
501 XML_Node& irNode = acNode.child("DHBetaMatrix");
502 const vector<string>& sn = speciesNames();
503 getMatrixValues(irNode, sn, sn, m_Beta_ij, true, true);
504 } else {
505 throw CanteraError("DebyeHuckel::initThermoXML:",
506 "DHBetaMatrix found for wrong type");
507 }
508 }
509
510 // Override stoichiometric Ionic Strength based on the phase definition
511 if (acNodePtr && acNodePtr->hasChild("stoichIsMods")) {
512 XML_Node& sIsNode = acNodePtr->child("stoichIsMods");
513 map<std::string, std::string> msIs;
514 getMap(sIsNode, msIs);
515 for (const auto& b : msIs) {
516 size_t kk = speciesIndex(b.first);
517 double val = fpValue(b.second);
518 m_speciesCharge_Stoich[kk] = val;
519 }
520 }
521 }
522
523 // Override electrolyte species type based on the phase definition
524 if (acNodePtr && acNodePtr->hasChild("electrolyteSpeciesType")) {
525 XML_Node& ESTNode = acNodePtr->child("electrolyteSpeciesType");
526 map<std::string, std::string> msEST;
527 getMap(ESTNode, msEST);
528 for (const auto& b : msEST) {
529 size_t kk = speciesIndex(b.first);
530 std::string est = b.second;
531 if ((m_electrolyteSpeciesType[kk] = interp_est(est)) == -1) {
532 throw CanteraError("DebyeHuckel:initThermoXML",
533 "Bad electrolyte type: " + est);
534 }
535 }
536 }
537
538 // Lastly set the state
539 if (phaseNode.hasChild("state")) {
540 XML_Node& stateNode = phaseNode.child("state");
541 setStateFromXML(stateNode);
542 }
543}
544
545 void DebyeHuckel::initThermo()
546{
547 MolalityVPSSTP::initThermo();
548 if (m_input.hasKey("activity-data")) {
549 auto& node = m_input["activity-data"].as<AnyMap>();
550 setDebyeHuckelModel(node["model"].asString());
551 if (node.hasKey("A_Debye")) {
552 if (node["A_Debye"] == "variable") {
553 setA_Debye(-1);
554 } else {
555 setA_Debye(node.convert("A_Debye", "kg^0.5/gmol^0.5"));
556 }
557 }
558 if (node.hasKey("B_Debye")) {
559 setB_Debye(node.convert("B_Debye", "kg^0.5/gmol^0.5/m"));
560 }
561 if (node.hasKey("max-ionic-strength")) {
562 setMaxIonicStrength(node["max-ionic-strength"].asDouble());
563 }
564 if (node.hasKey("use-Helgeson-fixed-form")) {
565 useHelgesonFixedForm(node["use-Helgeson-fixed-form"].asBool());
566 }
567 if (node.hasKey("default-ionic-radius")) {
568 setDefaultIonicRadius(node.convert("default-ionic-radius", "m"));
569 }
570 if (node.hasKey("B-dot")) {
571 setB_dot(node["B-dot"].asDouble());
572 }
573 if (node.hasKey("beta")) {
574 for (auto& item : node["beta"].asVector<AnyMap>()) {
575 auto& species = item["species"].asVector<string>(2);
576 setBeta(species[0], species[1], item["beta"].asDouble());
577 }
578 }
579 }
580
581 // Solvent
582 m_waterSS = dynamic_cast<PDSS_Water*>(providePDSS(0));
583 if (m_waterSS) {
584 // Initialize the water property calculator. It will share the internal
585 // eos water calculator.
586 if (m_form_A_Debye == A_DEBYE_WATER) {
587 m_waterProps.reset(new WaterProps(m_waterSS));
588 }
589 } else if (dynamic_cast<PDSS_ConstVol*>(providePDSS(0)) == 0) {
590 throw CanteraError("DebyeHuckel::initThermo", "Solvent standard state"
591 " model must be WaterIAPWS or constant_incompressible.");
592 }
593
594 // Solutes
595 for (size_t k = 1; k < nSpecies(); k++) {
596 if (dynamic_cast<PDSS_ConstVol*>(providePDSS(k)) == 0) {
597 throw CanteraError("DebyeHuckel::initThermo", "Solute standard"
598 " state model must be constant_incompressible.");
599 }
600 }
601}
602
603 void DebyeHuckel::getParameters(AnyMap& phaseNode) const
604{
605 MolalityVPSSTP::getParameters(phaseNode);
606 AnyMap activityNode;
607
608 switch (m_formDH) {
609 case DHFORM_DILUTE_LIMIT:
610 activityNode["model"] = "dilute-limit";
611 break;
612 case DHFORM_BDOT_AK:
613 activityNode["model"] = "B-dot-with-variable-a";
614 break;
615 case DHFORM_BDOT_ACOMMON:
616 activityNode["model"] = "B-dot-with-common-a";
617 break;
618 case DHFORM_BETAIJ:
619 activityNode["model"] = "beta_ij";
620 break;
621 case DHFORM_PITZER_BETAIJ:
622 activityNode["model"] = "Pitzer-with-beta_ij";
623 break;
624 }
625
626 if (m_form_A_Debye == A_DEBYE_WATER) {
627 activityNode["A_Debye"] = "variable";
628 } else if (m_A_Debye != A_Debye_default) {
629 activityNode["A_Debye"].setQuantity(m_A_Debye, "kg^0.5/gmol^0.5");
630 }
631
632 if (m_B_Debye != B_Debye_default) {
633 activityNode["B_Debye"].setQuantity(m_B_Debye, "kg^0.5/gmol^0.5/m");
634 }
635 if (m_maxIionicStrength != maxIionicStrength_default) {
636 activityNode["max-ionic-strength"] = m_maxIionicStrength;
637 }
638 if (m_useHelgesonFixedForm) {
639 activityNode["use-Helgeson-fixed-form"] = true;
640 }
641 if (!isnan(m_Aionic_default)) {
642 activityNode["default-ionic-radius"].setQuantity(m_Aionic_default, "m");
643 }
644 for (double B_dot : m_B_Dot) {
645 if (B_dot != 0.0) {
646 activityNode["B-dot"] = B_dot;
647 break;
648 }
649 }
650 if (m_Beta_ij.nRows() && m_Beta_ij.nColumns()) {
651 std::vector<AnyMap> beta;
652 for (size_t i = 0; i < m_kk; i++) {
653 for (size_t j = i; j < m_kk; j++) {
654 if (m_Beta_ij(i, j) != 0) {
655 AnyMap entry;
656 entry["species"] = vector<std::string>{
657 speciesName(i), speciesName(j)};
658 entry["beta"] = m_Beta_ij(i, j);
659 beta.push_back(std::move(entry));
660 }
661 }
662 }
663 activityNode["beta"] = std::move(beta);
664 }
665 phaseNode["activity-data"] = std::move(activityNode);
666}
667
668 void DebyeHuckel::getSpeciesParameters(const std::string& name,
669 AnyMap& speciesNode) const
670{
671 MolalityVPSSTP::getSpeciesParameters(name, speciesNode);
672 size_t k = speciesIndex(name);
673 checkSpeciesIndex(k);
674 AnyMap dhNode;
675 if (m_Aionic[k] != m_Aionic_default) {
676 dhNode["ionic-radius"].setQuantity(m_Aionic[k], "m");
677 }
678
679 int estDefault = cEST_nonpolarNeutral;
680 if (k == 0) {
681 estDefault = cEST_solvent;
682 }
683
684 if (m_speciesCharge_Stoich[k] != charge(k)) {
685 dhNode["weak-acid-charge"] = m_speciesCharge_Stoich[k];
686 estDefault = cEST_weakAcidAssociated;
687 } else if (fabs(charge(k)) > 0.0001) {
688 estDefault = cEST_chargedSpecies;
689 }
690
691 if (m_electrolyteSpeciesType[k] != estDefault) {
692 string estType;
693 switch (m_electrolyteSpeciesType[k]) {
694 case cEST_solvent:
695 estType = "solvent";
696 break;
697 case cEST_chargedSpecies:
698 estType = "charged-species";
699 break;
700 case cEST_weakAcidAssociated:
701 estType = "weak-acid-associated";
702 break;
703 case cEST_strongAcidAssociated:
704 estType = "strong-acid-associated";
705 break;
706 case cEST_polarNeutral:
707 estType = "polar-neutral";
708 break;
709 case cEST_nonpolarNeutral:
710 estType = "nonpolar-neutral";
711 break;
712 default:
713 throw CanteraError("DebyeHuckel::getSpeciesParameters",
714 "Unknown electrolyte species type ({}) for species '{}'",
715 m_electrolyteSpeciesType[k], name);
716 }
717 dhNode["electrolyte-species-type"] = estType;
718 }
719
720 if (dhNode.size()) {
721 speciesNode["Debye-Huckel"] = std::move(dhNode);
722 }
723}
724
725
726 double DebyeHuckel::A_Debye_TP(double tempArg, double presArg) const
727{
728 double T = temperature();
729 double A;
730 if (tempArg != -1.0) {
731 T = tempArg;
732 }
733 double P = pressure();
734 if (presArg != -1.0) {
735 P = presArg;
736 }
737
738 switch (m_form_A_Debye) {
739 case A_DEBYE_CONST:
740 A = m_A_Debye;
741 break;
742 case A_DEBYE_WATER:
743 A = m_waterProps->ADebye(T, P, 0);
744 m_A_Debye = A;
745 break;
746 default:
747 throw CanteraError("DebyeHuckel::A_Debye_TP", "shouldn't be here");
748 }
749 return A;
750}
751
752 double DebyeHuckel::dA_DebyedT_TP(double tempArg, double presArg) const
753{
754 double T = temperature();
755 if (tempArg != -1.0) {
756 T = tempArg;
757 }
758 double P = pressure();
759 if (presArg != -1.0) {
760 P = presArg;
761 }
762 double dAdT;
763 switch (m_form_A_Debye) {
764 case A_DEBYE_CONST:
765 dAdT = 0.0;
766 break;
767 case A_DEBYE_WATER:
768 dAdT = m_waterProps->ADebye(T, P, 1);
769 break;
770 default:
771 throw CanteraError("DebyeHuckel::dA_DebyedT_TP", "shouldn't be here");
772 }
773 return dAdT;
774}
775
776 double DebyeHuckel::d2A_DebyedT2_TP(double tempArg, double presArg) const
777{
778 double T = temperature();
779 if (tempArg != -1.0) {
780 T = tempArg;
781 }
782 double P = pressure();
783 if (presArg != -1.0) {
784 P = presArg;
785 }
786 double d2AdT2;
787 switch (m_form_A_Debye) {
788 case A_DEBYE_CONST:
789 d2AdT2 = 0.0;
790 break;
791 case A_DEBYE_WATER:
792 d2AdT2 = m_waterProps->ADebye(T, P, 2);
793 break;
794 default:
795 throw CanteraError("DebyeHuckel::d2A_DebyedT2_TP", "shouldn't be here");
796 }
797 return d2AdT2;
798}
799
800 double DebyeHuckel::dA_DebyedP_TP(double tempArg, double presArg) const
801{
802 double T = temperature();
803 if (tempArg != -1.0) {
804 T = tempArg;
805 }
806 double P = pressure();
807 if (presArg != -1.0) {
808 P = presArg;
809 }
810 double dAdP;
811 switch (m_form_A_Debye) {
812 case A_DEBYE_CONST:
813 dAdP = 0.0;
814 break;
815 case A_DEBYE_WATER:
816 dAdP = m_waterProps->ADebye(T, P, 3);
817 break;
818 default:
819 throw CanteraError("DebyeHuckel::dA_DebyedP_TP", "shouldn't be here");
820 }
821 return dAdP;
822}
823
824// ---------- Other Property Functions
825
826 double DebyeHuckel::AionicRadius(int k) const
827{
828 return m_Aionic[k];
829}
830
831// ------------ Private and Restricted Functions ------------------
832
833 bool DebyeHuckel::addSpecies(shared_ptr<Species> spec)
834{
835 bool added = MolalityVPSSTP::addSpecies(spec);
836 if (added) {
837 m_lnActCoeffMolal.push_back(0.0);
838 m_dlnActCoeffMolaldT.push_back(0.0);
839 m_d2lnActCoeffMolaldT2.push_back(0.0);
840 m_dlnActCoeffMolaldP.push_back(0.0);
841 m_B_Dot.push_back(0.0);
842 m_tmpV.push_back(0.0);
843
844 // NAN will be replaced with default value
845 double Aionic = NAN;
846
847 // Guess electrolyte species type based on charge properties
848 int est = cEST_nonpolarNeutral;
849 double stoichCharge = spec->charge;
850 if (fabs(spec->charge) > 0.0001) {
851 est = cEST_chargedSpecies;
852 }
853
854 if (spec->input.hasKey("Debye-Huckel")) {
855 auto& dhNode = spec->input["Debye-Huckel"].as<AnyMap>();
856 Aionic = dhNode.convert("ionic-radius", "m", NAN);
857 if (dhNode.hasKey("weak-acid-charge")) {
858 stoichCharge = dhNode["weak-acid-charge"].asDouble();
859 if (fabs(stoichCharge - spec->charge) > 0.0001) {
860 est = cEST_weakAcidAssociated;
861 }
862 }
863 // Apply override of the electrolyte species type
864 if (dhNode.hasKey("electrolyte-species-type")) {
865 est = interp_est(dhNode["electrolyte-species-type"].asString());
866 }
867 }
868
869 if (m_electrolyteSpeciesType.size() == 0) {
870 est = cEST_solvent; // species 0 is the solvent
871 }
872
873 m_Aionic.push_back(Aionic);
874 m_speciesCharge_Stoich.push_back(stoichCharge);
875 m_electrolyteSpeciesType.push_back(est);
876 }
877 return added;
878}
879
880 double DebyeHuckel::_nonpolarActCoeff(double IionicMolality)
881{
882 // These are coefficients to describe the increase in activity coeff for
883 // non-polar molecules due to the electrolyte becoming stronger (the so-
884 // called salt-out effect)
885 const static double npActCoeff[] = {0.1127, -0.01049, 1.545E-3};
886 double I2 = IionicMolality * IionicMolality;
887 double l10actCoeff =
888 npActCoeff[0] * IionicMolality +
889 npActCoeff[1] * I2 +
890 npActCoeff[2] * I2 * IionicMolality;
891 return pow(10.0 , l10actCoeff);
892}
893
894 double DebyeHuckel::_osmoticCoeffHelgesonFixedForm() const
895{
896 const double a0 = 1.454;
897 const double b0 = 0.02236;
898 const double c0 = 9.380E-3;
899 const double d0 = -5.362E-4;
900 double Is = m_IionicMolalityStoich;
901 if (Is <= 0.0) {
902 return 0.0;
903 }
904 double Is2 = Is * Is;
905 double bhat = 1.0 + a0 * sqrt(Is);
906 double func = bhat - 2.0 * log(bhat) - 1.0/bhat;
907 double v1 = m_A_Debye / (a0 * a0 * a0 * Is) * func;
908 double oc = 1.0 - v1 + b0 * Is / 2.0 + 2.0 * c0 * Is2 / 3.0
909 + 3.0 * d0 * Is2 * Is / 4.0;
910 return oc;
911}
912
913 double DebyeHuckel::_lnactivityWaterHelgesonFixedForm() const
914{
915 // Update the internally stored vector of molalities
916 calcMolalities();
917 double oc = _osmoticCoeffHelgesonFixedForm();
918 double sum = 0.0;
919 for (size_t k = 1; k < m_kk; k++) {
920 sum += std::max(m_molalities[k], 0.0);
921 }
922 if (sum > 2.0 * m_maxIionicStrength) {
923 sum = 2.0 * m_maxIionicStrength;
924 };
925 return - m_Mnaught * sum * oc;
926}
927
928 void DebyeHuckel::s_update_lnMolalityActCoeff() const
929{
930 double z_k, zs_k1, zs_k2;
931
932 // Update the internally stored vector of molalities
933 calcMolalities();
934
935 // Calculate the apparent (real) ionic strength.
936 //
937 // Note this is not the stoichiometric ionic strengh, where reactions of
938 // ions forming neutral salts are ignorred in calculating the ionic
939 // strength.
940 m_IionicMolality = 0.0;
941 for (size_t k = 0; k < m_kk; k++) {
942 z_k = m_speciesCharge[k];
943 m_IionicMolality += m_molalities[k] * z_k * z_k;
944 }
945 m_IionicMolality /= 2.0;
946 m_IionicMolality = std::min(m_IionicMolality, m_maxIionicStrength);
947
948 // Calculate the stoichiometric ionic charge
949 m_IionicMolalityStoich = 0.0;
950 for (size_t k = 0; k < m_kk; k++) {
951 z_k = m_speciesCharge[k];
952 zs_k1 = m_speciesCharge_Stoich[k];
953 if (z_k == zs_k1) {
954 m_IionicMolalityStoich += m_molalities[k] * z_k * z_k;
955 } else {
956 zs_k2 = z_k - zs_k1;
957 m_IionicMolalityStoich += m_molalities[k] * (zs_k1 * zs_k1 + zs_k2 * zs_k2);
958 }
959 }
960 m_IionicMolalityStoich /= 2.0;
961 m_IionicMolalityStoich = std::min(m_IionicMolalityStoich, m_maxIionicStrength);
962
963 // Possibly update the stored value of the Debye-Huckel parameter A_Debye
964 // This parameter appears on the top of the activity coefficient expression.
965 // It depends on T (and P), as it depends explicitly on the temperature.
966 // Also, the dielectric constant is usually a fairly strong function of T,
967 // also.
968 m_A_Debye = A_Debye_TP();
969
970 // Calculate a safe value for the mole fraction of the solvent
971 double xmolSolvent = moleFraction(0);
972 xmolSolvent = std::max(8.689E-3, xmolSolvent);
973
974 int est;
975 double ac_nonPolar = 1.0;
976 double numTmp = m_A_Debye * sqrt(m_IionicMolality);
977 double denomTmp = m_B_Debye * sqrt(m_IionicMolality);
978 double coeff;
979 double lnActivitySolvent = 0.0;
980 double tmp;
981 double tmpLn;
982 double y, yp1, sigma;
983 switch (m_formDH) {
984 case DHFORM_DILUTE_LIMIT:
985 for (size_t k = 0; k < m_kk; k++) {
986 z_k = m_speciesCharge[k];
987 m_lnActCoeffMolal[k] = - z_k * z_k * numTmp;
988 }
989 lnActivitySolvent =
990 (xmolSolvent - 1.0)/xmolSolvent +
991 2.0 / 3.0 * m_A_Debye * m_Mnaught *
992 m_IionicMolality * sqrt(m_IionicMolality);
993 break;
994
995 case DHFORM_BDOT_AK:
996 ac_nonPolar = _nonpolarActCoeff(m_IionicMolality);
997 for (size_t k = 0; k < m_kk; k++) {
998 est = m_electrolyteSpeciesType[k];
999 if (est == cEST_nonpolarNeutral) {
1000 m_lnActCoeffMolal[k] = log(ac_nonPolar);
1001 } else {
1002 z_k = m_speciesCharge[k];
1003 m_lnActCoeffMolal[k] =
1004 - z_k * z_k * numTmp / (1.0 + denomTmp * m_Aionic[k])
1005 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
1006 }
1007 }
1008
1009 lnActivitySolvent = (xmolSolvent - 1.0)/xmolSolvent;
1010 coeff = 2.0 / 3.0 * m_A_Debye * m_Mnaught
1011 * sqrt(m_IionicMolality);
1012 tmp = 0.0;
1013 if (denomTmp > 0.0) {
1014 for (size_t k = 0; k < m_kk; k++) {
1015 if (k != 0 || m_Aionic[k] != 0.0) {
1016 y = denomTmp * m_Aionic[k];
1017 yp1 = y + 1.0;
1018 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1019 z_k = m_speciesCharge[k];
1020 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1021 }
1022 }
1023 }
1024 lnActivitySolvent += coeff * tmp;
1025 tmp = 0.0;
1026 for (size_t k = 1; k < m_kk; k++) {
1027 z_k = m_speciesCharge[k];
1028 if (z_k != 0.0) {
1029 tmp += m_B_Dot[k] * m_molalities[k];
1030 }
1031 }
1032 lnActivitySolvent -=
1033 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
1034
1035 // Special section to implement the Helgeson fixed form for the water
1036 // brine activity coefficient.
1037 if (m_useHelgesonFixedForm) {
1038 lnActivitySolvent = _lnactivityWaterHelgesonFixedForm();
1039 }
1040 break;
1041
1042 case DHFORM_BDOT_ACOMMON:
1043 denomTmp *= m_Aionic[0];
1044 for (size_t k = 0; k < m_kk; k++) {
1045 z_k = m_speciesCharge[k];
1046 m_lnActCoeffMolal[k] =
1047 - z_k * z_k * numTmp / (1.0 + denomTmp)
1048 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
1049 }
1050 if (denomTmp > 0.0) {
1051 y = denomTmp;
1052 yp1 = y + 1.0;
1053 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1054 } else {
1055 sigma = 0.0;
1056 }
1057 lnActivitySolvent =
1058 (xmolSolvent - 1.0)/xmolSolvent +
1059 2.0 /3.0 * m_A_Debye * m_Mnaught *
1060 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
1061 tmp = 0.0;
1062 for (size_t k = 1; k < m_kk; k++) {
1063 z_k = m_speciesCharge[k];
1064 if (z_k != 0.0) {
1065 tmp += m_B_Dot[k] * m_molalities[k];
1066 }
1067 }
1068 lnActivitySolvent -=
1069 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
1070 break;
1071
1072 case DHFORM_BETAIJ:
1073 denomTmp = m_B_Debye * m_Aionic[0];
1074 denomTmp *= sqrt(m_IionicMolality);
1075 lnActivitySolvent =
1076 (xmolSolvent - 1.0)/xmolSolvent;
1077
1078 for (size_t k = 1; k < m_kk; k++) {
1079 z_k = m_speciesCharge[k];
1080 m_lnActCoeffMolal[k] =
1081 - z_k * z_k * numTmp / (1.0 + denomTmp);
1082 for (size_t j = 0; j < m_kk; j++) {
1083 double beta = m_Beta_ij.value(k, j);
1084 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] * beta;
1085 }
1086 }
1087 if (denomTmp > 0.0) {
1088 y = denomTmp;
1089 yp1 = y + 1.0;
1090 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
1091 } else {
1092 sigma = 0.0;
1093 }
1094 lnActivitySolvent =
1095 (xmolSolvent - 1.0)/xmolSolvent +
1096 2.0 /3.0 * m_A_Debye * m_Mnaught *
1097 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
1098 tmp = 0.0;
1099 for (size_t k = 0; k < m_kk; k++) {
1100 for (size_t j = 0; j < m_kk; j++) {
1101 tmp +=
1102 m_Beta_ij.value(k, j) * m_molalities[k] * m_molalities[j];
1103 }
1104 }
1105 lnActivitySolvent -= m_Mnaught * tmp;
1106 break;
1107
1108 case DHFORM_PITZER_BETAIJ:
1109 denomTmp = m_B_Debye * sqrt(m_IionicMolality);
1110 denomTmp *= m_Aionic[0];
1111 numTmp = m_A_Debye * sqrt(m_IionicMolality);
1112 tmpLn = log(1.0 + denomTmp);
1113 for (size_t k = 1; k < m_kk; k++) {
1114 z_k = m_speciesCharge[k];
1115 m_lnActCoeffMolal[k] =
1116 - z_k * z_k * numTmp / 3.0 / (1.0 + denomTmp);
1117 m_lnActCoeffMolal[k] +=
1118 - 2.0 * z_k * z_k * m_A_Debye * tmpLn /
1119 (3.0 * m_B_Debye * m_Aionic[0]);
1120 for (size_t j = 0; j < m_kk; j++) {
1121 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] *
1122 m_Beta_ij.value(k, j);
1123 }
1124 }
1125 sigma = 1.0 / (1.0 + denomTmp);
1126 lnActivitySolvent =
1127 (xmolSolvent - 1.0)/xmolSolvent +
1128 2.0 /3.0 * m_A_Debye * m_Mnaught *
1129 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
1130 tmp = 0.0;
1131 for (size_t k = 0; k < m_kk; k++) {
1132 for (size_t j = 0; j < m_kk; j++) {
1133 tmp +=
1134 m_Beta_ij.value(k, j) * m_molalities[k] * m_molalities[j];
1135 }
1136 }
1137 lnActivitySolvent -= m_Mnaught * tmp;
1138 break;
1139
1140 default:
1141 throw CanteraError("DebyeHuckel::s_update_lnMolalityActCoeff", "ERROR");
1142 }
1143
1144 // Above, we calculated the ln(activitySolvent). Translate that into the
1145 // molar-based activity coefficient by dividing by the solvent mole
1146 // fraction. Solvents are not on the molality scale.
1147 xmolSolvent = moleFraction(0);
1148 m_lnActCoeffMolal[0] = lnActivitySolvent - log(xmolSolvent);
1149}
1150
1151 void DebyeHuckel::s_update_dlnMolalityActCoeff_dT() const
1152{
1153 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1154 // First we store dAdT explicitly here
1155 double dAdT = dA_DebyedT_TP();
1156 if (dAdT == 0.0) {
1157 for (size_t k = 0; k < m_kk; k++) {
1158 m_dlnActCoeffMolaldT[k] = 0.0;
1159 }
1160 return;
1161 }
1162
1163 // Calculate a safe value for the mole fraction of the solvent
1164 double xmolSolvent = moleFraction(0);
1165 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1166 double sqrtI = sqrt(m_IionicMolality);
1167 double numdAdTTmp = dAdT * sqrtI;
1168 double denomTmp = m_B_Debye * sqrtI;
1169 double d_lnActivitySolvent_dT = 0;
1170
1171 switch (m_formDH) {
1172 case DHFORM_DILUTE_LIMIT:
1173 for (size_t k = 1; k < m_kk; k++) {
1174 m_dlnActCoeffMolaldT[k] =
1175 m_lnActCoeffMolal[k] * dAdT / m_A_Debye;
1176 }
1177 d_lnActivitySolvent_dT = 2.0 / 3.0 * dAdT * m_Mnaught *
1178 m_IionicMolality * sqrt(m_IionicMolality);
1179 m_dlnActCoeffMolaldT[0] = d_lnActivitySolvent_dT;
1180 break;
1181
1182 case DHFORM_BDOT_AK:
1183 for (size_t k = 0; k < m_kk; k++) {
1184 z_k = m_speciesCharge[k];
1185 m_dlnActCoeffMolaldT[k] =
1186 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp * m_Aionic[k]);
1187 }
1188
1189 m_dlnActCoeffMolaldT[0] = 0.0;
1190 coeff = 2.0 / 3.0 * dAdT * m_Mnaught * sqrtI;
1191 tmp = 0.0;
1192 if (denomTmp > 0.0) {
1193 for (size_t k = 0; k < m_kk; k++) {
1194 y = denomTmp * m_Aionic[k];
1195 yp1 = y + 1.0;
1196 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1197 z_k = m_speciesCharge[k];
1198 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1199 }
1200 }
1201 m_dlnActCoeffMolaldT[0] += coeff * tmp;
1202 break;
1203
1204 case DHFORM_BDOT_ACOMMON:
1205 denomTmp *= m_Aionic[0];
1206 for (size_t k = 0; k < m_kk; k++) {
1207 z_k = m_speciesCharge[k];
1208 m_dlnActCoeffMolaldT[k] =
1209 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp);
1210 }
1211 if (denomTmp > 0.0) {
1212 y = denomTmp;
1213 yp1 = y + 1.0;
1214 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1215 } else {
1216 sigma = 0.0;
1217 }
1218 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1219 m_IionicMolality * sqrtI * sigma;
1220 break;
1221
1222 case DHFORM_BETAIJ:
1223 denomTmp *= m_Aionic[0];
1224 for (size_t k = 1; k < m_kk; k++) {
1225 z_k = m_speciesCharge[k];
1226 m_dlnActCoeffMolaldT[k] = -z_k*z_k * numdAdTTmp / (1.0 + denomTmp);
1227 }
1228 if (denomTmp > 0.0) {
1229 y = denomTmp;
1230 yp1 = y + 1.0;
1231 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1232 } else {
1233 sigma = 0.0;
1234 }
1235 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1236 m_IionicMolality * sqrtI * sigma;
1237 break;
1238
1239 case DHFORM_PITZER_BETAIJ:
1240 denomTmp *= m_Aionic[0];
1241 tmpLn = log(1.0 + denomTmp);
1242 for (size_t k = 1; k < m_kk; k++) {
1243 z_k = m_speciesCharge[k];
1244 m_dlnActCoeffMolaldT[k] =
1245 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp)
1246 - 2.0 * z_k * z_k * dAdT * tmpLn / (m_B_Debye * m_Aionic[0]);
1247 m_dlnActCoeffMolaldT[k] /= 3.0;
1248 }
1249
1250 sigma = 1.0 / (1.0 + denomTmp);
1251 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1252 m_IionicMolality * sqrtI * sigma;
1253 break;
1254
1255 default:
1256 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dT",
1257 "ERROR");
1258 }
1259}
1260
1261 void DebyeHuckel::s_update_d2lnMolalityActCoeff_dT2() const
1262{
1263 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1264 double dAdT = dA_DebyedT_TP();
1265 double d2AdT2 = d2A_DebyedT2_TP();
1266 if (d2AdT2 == 0.0 && dAdT == 0.0) {
1267 for (size_t k = 0; k < m_kk; k++) {
1268 m_d2lnActCoeffMolaldT2[k] = 0.0;
1269 }
1270 return;
1271 }
1272
1273 // Calculate a safe value for the mole fraction of the solvent
1274 double xmolSolvent = moleFraction(0);
1275 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1276 double sqrtI = sqrt(m_IionicMolality);
1277 double numd2AdT2Tmp = d2AdT2 * sqrtI;
1278 double denomTmp = m_B_Debye * sqrtI;
1279
1280 switch (m_formDH) {
1281 case DHFORM_DILUTE_LIMIT:
1282 for (size_t k = 0; k < m_kk; k++) {
1283 m_d2lnActCoeffMolaldT2[k] =
1284 m_lnActCoeffMolal[k] * d2AdT2 / m_A_Debye;
1285 }
1286 break;
1287
1288 case DHFORM_BDOT_AK:
1289 for (size_t k = 0; k < m_kk; k++) {
1290 z_k = m_speciesCharge[k];
1291 m_d2lnActCoeffMolaldT2[k] =
1292 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp * m_Aionic[k]);
1293 }
1294
1295 m_d2lnActCoeffMolaldT2[0] = 0.0;
1296 coeff = 2.0 / 3.0 * d2AdT2 * m_Mnaught * sqrtI;
1297 tmp = 0.0;
1298 if (denomTmp > 0.0) {
1299 for (size_t k = 0; k < m_kk; k++) {
1300 y = denomTmp * m_Aionic[k];
1301 yp1 = y + 1.0;
1302 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1303 z_k = m_speciesCharge[k];
1304 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1305 }
1306 }
1307 m_d2lnActCoeffMolaldT2[0] += coeff * tmp;
1308 break;
1309
1310 case DHFORM_BDOT_ACOMMON:
1311 denomTmp *= m_Aionic[0];
1312 for (size_t k = 0; k < m_kk; k++) {
1313 z_k = m_speciesCharge[k];
1314 m_d2lnActCoeffMolaldT2[k] =
1315 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1316 }
1317 if (denomTmp > 0.0) {
1318 y = denomTmp;
1319 yp1 = y + 1.0;
1320 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1321 } else {
1322 sigma = 0.0;
1323 }
1324 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1325 m_IionicMolality * sqrtI * sigma;
1326 break;
1327
1328 case DHFORM_BETAIJ:
1329 denomTmp *= m_Aionic[0];
1330 for (size_t k = 1; k < m_kk; k++) {
1331 z_k = m_speciesCharge[k];
1332 m_d2lnActCoeffMolaldT2[k] = -z_k*z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1333 }
1334 if (denomTmp > 0.0) {
1335 y = denomTmp;
1336 yp1 = y + 1.0;
1337 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
1338 } else {
1339 sigma = 0.0;
1340 }
1341 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1342 m_IionicMolality * sqrtI * sigma;
1343 break;
1344
1345 case DHFORM_PITZER_BETAIJ:
1346 denomTmp *= m_Aionic[0];
1347 tmpLn = log(1.0 + denomTmp);
1348 for (size_t k = 1; k < m_kk; k++) {
1349 z_k = m_speciesCharge[k];
1350 m_d2lnActCoeffMolaldT2[k] =
1351 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp)
1352 - 2.0 * z_k * z_k * d2AdT2 * tmpLn / (m_B_Debye * m_Aionic[0]);
1353 m_d2lnActCoeffMolaldT2[k] /= 3.0;
1354 }
1355
1356 sigma = 1.0 / (1.0 + denomTmp);
1357 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1358 m_IionicMolality * sqrtI * sigma;
1359 break;
1360
1361 default:
1362 throw CanteraError("DebyeHuckel::s_update_d2lnMolalityActCoeff_dT2",
1363 "ERROR");
1364 }
1365}
1366
1367 void DebyeHuckel::s_update_dlnMolalityActCoeff_dP() const
1368{
1369 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1370 int est;
1371 double dAdP = dA_DebyedP_TP();
1372 if (dAdP == 0.0) {
1373 for (size_t k = 0; k < m_kk; k++) {
1374 m_dlnActCoeffMolaldP[k] = 0.0;
1375 }
1376 return;
1377 }
1378
1379 // Calculate a safe value for the mole fraction of the solvent
1380 double xmolSolvent = moleFraction(0);
1381 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1382 double sqrtI = sqrt(m_IionicMolality);
1383 double numdAdPTmp = dAdP * sqrtI;
1384 double denomTmp = m_B_Debye * sqrtI;
1385
1386 switch (m_formDH) {
1387 case DHFORM_DILUTE_LIMIT:
1388 for (size_t k = 0; k < m_kk; k++) {
1389 m_dlnActCoeffMolaldP[k] =
1390 m_lnActCoeffMolal[k] * dAdP / m_A_Debye;
1391 }
1392 break;
1393
1394 case DHFORM_BDOT_AK:
1395 for (size_t k = 0; k < m_kk; k++) {
1396 est = m_electrolyteSpeciesType[k];
1397 if (est == cEST_nonpolarNeutral) {
1398 m_lnActCoeffMolal[k] = 0.0;
1399 } else {
1400 z_k = m_speciesCharge[k];
1401 m_dlnActCoeffMolaldP[k] =
1402 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp * m_Aionic[k]);
1403 }
1404 }
1405
1406 m_dlnActCoeffMolaldP[0] = 0.0;
1407 coeff = 2.0 / 3.0 * dAdP * m_Mnaught * sqrtI;
1408 tmp = 0.0;
1409 if (denomTmp > 0.0) {
1410 for (size_t k = 0; k < m_kk; k++) {
1411 y = denomTmp * m_Aionic[k];
1412 yp1 = y + 1.0;
1413 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1414 z_k = m_speciesCharge[k];
1415 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1416 }
1417 }
1418 m_dlnActCoeffMolaldP[0] += coeff * tmp;
1419 break;
1420
1421 case DHFORM_BDOT_ACOMMON:
1422 denomTmp *= m_Aionic[0];
1423 for (size_t k = 0; k < m_kk; k++) {
1424 z_k = m_speciesCharge[k];
1425 m_dlnActCoeffMolaldP[k] =
1426 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp);
1427 }
1428 if (denomTmp > 0.0) {
1429 y = denomTmp;
1430 yp1 = y + 1.0;
1431 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1432 } else {
1433 sigma = 0.0;
1434 }
1435 m_dlnActCoeffMolaldP[0] =
1436 2.0 /3.0 * dAdP * m_Mnaught *
1437 m_IionicMolality * sqrtI * sigma;
1438 break;
1439
1440 case DHFORM_BETAIJ:
1441 denomTmp *= m_Aionic[0];
1442 for (size_t k = 1; k < m_kk; k++) {
1443 z_k = m_speciesCharge[k];
1444 m_dlnActCoeffMolaldP[k] = - z_k*z_k * numdAdPTmp / (1.0 + denomTmp);
1445 }
1446 if (denomTmp > 0.0) {
1447 y = denomTmp;
1448 yp1 = y + 1.0;
1449 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1450 } else {
1451 sigma = 0.0;
1452 }
1453 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1454 m_IionicMolality * sqrtI * sigma;
1455 break;
1456
1457 case DHFORM_PITZER_BETAIJ:
1458 denomTmp *= m_Aionic[0];
1459 tmpLn = log(1.0 + denomTmp);
1460 for (size_t k = 1; k < m_kk; k++) {
1461 z_k = m_speciesCharge[k];
1462 m_dlnActCoeffMolaldP[k] =
1463 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp)
1464 - 2.0 * z_k * z_k * dAdP * tmpLn
1465 / (m_B_Debye * m_Aionic[0]);
1466 m_dlnActCoeffMolaldP[k] /= 3.0;
1467 }
1468
1469 sigma = 1.0 / (1.0 + denomTmp);
1470 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1471 m_IionicMolality * sqrtI * sigma;
1472 break;
1473
1474 default:
1475 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dP",
1476 "ERROR");
1477 }
1478}
1479
1480}
DebyeHuckel.h
Headers for the DebyeHuckel ThermoPhase object, which models dilute electrolyte solutions (see Thermo...
PDSS_ConstVol.h
Declarations for the class PDSS_ConstVol (pressure dependent standard state) which handles calculatio...
PDSS_Water.h
Implementation of a pressure dependent standard state virtual function for a Pure Water Phase (see Sp...
Species.h
Declaration for class Cantera::Species.
ThermoFactory.h
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Cantera::AnyMap
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
Cantera::AnyMap::size
size_t size() const
Returns the number of elements in this map.
Definition: AnyMap.h:590
Cantera::AnyMap::convert
double convert(const std::string &key, const std::string &units) const
Convert the item stored by the given key to the units specified in units.
Definition: AnyMap.cpp:1508
Cantera::AnyMap::hasKey
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1406
Cantera::Array2D::nRows
size_t nRows() const
Number of rows.
Definition: Array.h:188
Cantera::Array2D::nColumns
size_t nColumns() const
Number of columns.
Definition: Array.h:193
Cantera::Array2D::value
doublereal & value(size_t i, size_t j)
Returns a changeable reference to position in the matrix.
Definition: Array.h:172
Cantera::Array2D::resize
void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
Definition: Array.cpp:52
Cantera::CanteraError
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Cantera::DebyeHuckel::m_Beta_ij
Array2D m_Beta_ij
Array of 2D data used in the DHFORM_BETAIJ formulation Beta_ij.value(i,j) is the coefficient of the j...
Definition: DebyeHuckel.h:1082
Cantera::DebyeHuckel::m_formDH
int m_formDH
form of the Debye-Huckel parameterization used in the model.
Definition: DebyeHuckel.h:939
Cantera::DebyeHuckel::addSpecies
virtual bool addSpecies(shared_ptr< Species > spec)
Definition: DebyeHuckel.cpp:833
Cantera::DebyeHuckel::m_A_Debye
double m_A_Debye
Current value of the Debye Constant, A_Debye.
Definition: DebyeHuckel.h:1016
Cantera::DebyeHuckel::d2A_DebyedT2_TP
virtual double d2A_DebyedT2_TP(double temperature=-1.0, double pressure=-1.0) const
Value of the 2nd derivative of the Debye Huckel constant with respect to temperature as a function of...
Definition: DebyeHuckel.cpp:776
Cantera::DebyeHuckel::getParameters
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
Definition: DebyeHuckel.cpp:603
Cantera::DebyeHuckel::m_d2lnActCoeffMolaldT2
vector_fp m_d2lnActCoeffMolaldT2
2nd Derivative of log act coeff wrt T
Definition: DebyeHuckel.h:1095
Cantera::DebyeHuckel::m_IionicMolality
double m_IionicMolality
Current value of the ionic strength on the molality scale.
Definition: DebyeHuckel.h:961
Cantera::DebyeHuckel::_osmoticCoeffHelgesonFixedForm
double _osmoticCoeffHelgesonFixedForm() const
Formula for the osmotic coefficient that occurs in the GWB.
Definition: DebyeHuckel.cpp:894
Cantera::DebyeHuckel::m_densWaterSS
double m_densWaterSS
Storage for the density of water's standard state.
Definition: DebyeHuckel.h:1054
Cantera::DebyeHuckel::s_update_d2lnMolalityActCoeff_dT2
void s_update_d2lnMolalityActCoeff_dT2() const
Calculate the temperature 2nd derivative of the activity coefficient.
Definition: DebyeHuckel.cpp:1261
Cantera::DebyeHuckel::m_speciesCharge_Stoich
vector_fp m_speciesCharge_Stoich
Stoichiometric species charge -> This is for calculations of the ionic strength which ignore ion-ion ...
Definition: DebyeHuckel.h:1074
Cantera::DebyeHuckel::m_form_A_Debye
int m_form_A_Debye
Form of the constant outside the Debye-Huckel term called A.
Definition: DebyeHuckel.h:994
Cantera::DebyeHuckel::m_useHelgesonFixedForm
bool m_useHelgesonFixedForm
If true, then the fixed for of Helgeson's activity for water is used instead of the rigorous form obt...
Definition: DebyeHuckel.h:972
Cantera::DebyeHuckel::_nonpolarActCoeff
static double _nonpolarActCoeff(double IionicMolality)
Static function that implements the non-polar species salt-out modifications.
Definition: DebyeHuckel.cpp:880
Cantera::DebyeHuckel::cp_mole
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
Definition: DebyeHuckel.cpp:93
Cantera::DebyeHuckel::getMolalityActivityCoefficients
virtual void getMolalityActivityCoefficients(doublereal *acMolality) const
Get the array of non-dimensional molality-based activity coefficients at the current solution tempera...
Definition: DebyeHuckel.cpp:144
Cantera::DebyeHuckel::getPartialMolarEnthalpies
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: DebyeHuckel.cpp:177
Cantera::DebyeHuckel::getPartialMolarEntropies
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: DebyeHuckel.cpp:202
Cantera::DebyeHuckel::initThermoXML
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
Definition: DebyeHuckel.cpp:384
Cantera::DebyeHuckel::m_B_Debye
double m_B_Debye
Current value of the constant that appears in the denominator.
Definition: DebyeHuckel.h:1034
Cantera::DebyeHuckel::enthalpy_mole
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
Definition: DebyeHuckel.cpp:75
Cantera::DebyeHuckel::getPartialMolarVolumes
virtual void getPartialMolarVolumes(doublereal *vbar) const
Return an array of partial molar volumes for the species in the mixture.
Definition: DebyeHuckel.cpp:240
Cantera::DebyeHuckel::AionicRadius
double AionicRadius(int k=0) const
Reports the ionic radius of the kth species.
Definition: DebyeHuckel.cpp:826
Cantera::DebyeHuckel::getActivityConcentrations
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: DebyeHuckel.cpp:115
Cantera::DebyeHuckel::s_update_dlnMolalityActCoeff_dT
void s_update_dlnMolalityActCoeff_dT() const
Calculation of temperature derivative of activity coefficient.
Definition: DebyeHuckel.cpp:1151
Cantera::DebyeHuckel::s_update_lnMolalityActCoeff
void s_update_lnMolalityActCoeff() const
Calculate the log activity coefficients.
Definition: DebyeHuckel.cpp:928
Cantera::DebyeHuckel::getPartialMolarCp
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
Definition: DebyeHuckel.cpp:252
Cantera::DebyeHuckel::setBeta
void setBeta(const std::string &sp1, const std::string &sp2, double value)
Set the value for the beta interaction between species sp1 and sp2.
Definition: DebyeHuckel.cpp:369
Cantera::DebyeHuckel::m_dlnActCoeffMolaldP
vector_fp m_dlnActCoeffMolaldP
Derivative of log act coeff wrt P.
Definition: DebyeHuckel.h:1098
Cantera::DebyeHuckel::setDebyeHuckelModel
void setDebyeHuckelModel(const std::string &form)
Set the DebyeHuckel parameterization form.
Definition: DebyeHuckel.cpp:308
Cantera::DebyeHuckel::setA_Debye
void setA_Debye(double A)
Set the A_Debye parameter.
Definition: DebyeHuckel.cpp:332
Cantera::DebyeHuckel::m_dlnActCoeffMolaldT
vector_fp m_dlnActCoeffMolaldT
Derivative of log act coeff wrt T.
Definition: DebyeHuckel.h:1092
Cantera::DebyeHuckel::entropy_mole
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
Definition: DebyeHuckel.cpp:81
Cantera::DebyeHuckel::m_electrolyteSpeciesType
vector_int m_electrolyteSpeciesType
Vector containing the electrolyte species type.
Definition: DebyeHuckel.h:952
Cantera::DebyeHuckel::initThermo
virtual void initThermo()
Definition: DebyeHuckel.cpp:545
Cantera::DebyeHuckel::m_Aionic_default
double m_Aionic_default
Default ionic radius for species where it is not specified.
Definition: DebyeHuckel.h:958
Cantera::DebyeHuckel::m_B_Dot
vector_fp m_B_Dot
Array of B_Dot values.
Definition: DebyeHuckel.h:1042
Cantera::DebyeHuckel::m_maxIionicStrength
double m_maxIionicStrength
Maximum value of the ionic strength allowed in the calculation of the activity coefficients.
Definition: DebyeHuckel.h:965
Cantera::DebyeHuckel::gibbs_mole
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: DebyeHuckel.cpp:87
Cantera::DebyeHuckel::DebyeHuckel
DebyeHuckel(const std::string &inputFile="", const std::string &id="")
Full constructor for creating the phase.
Definition: DebyeHuckel.cpp:36
Cantera::DebyeHuckel::_lnactivityWaterHelgesonFixedForm
double _lnactivityWaterHelgesonFixedForm() const
Formula for the log of the water activity that occurs in the GWB.
Definition: DebyeHuckel.cpp:913
Cantera::DebyeHuckel::m_Aionic
vector_fp m_Aionic
a_k = Size of the ionic species in the DH formulation. units = meters
Definition: DebyeHuckel.h:955
Cantera::DebyeHuckel::dA_DebyedT_TP
virtual double dA_DebyedT_TP(double temperature=-1.0, double pressure=-1.0) const
Value of the derivative of the Debye Huckel constant with respect to temperature.
Definition: DebyeHuckel.cpp:752
Cantera::DebyeHuckel::getSpeciesParameters
virtual void getSpeciesParameters(const std::string &name, AnyMap &speciesNode) const
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
Definition: DebyeHuckel.cpp:668
Cantera::DebyeHuckel::setDefaultIonicRadius
void setDefaultIonicRadius(double value)
Set the default ionic radius [m] for each species.
Definition: DebyeHuckel.cpp:359
Cantera::DebyeHuckel::s_update_dlnMolalityActCoeff_dP
void s_update_dlnMolalityActCoeff_dP() const
Calculate the pressure derivative of the activity coefficient.
Definition: DebyeHuckel.cpp:1367
Cantera::DebyeHuckel::m_waterSS
PDSS_Water * m_waterSS
Pointer to the Water standard state object.
Definition: DebyeHuckel.h:1048
Cantera::DebyeHuckel::getChemPotentials
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: DebyeHuckel.cpp:157
Cantera::DebyeHuckel::m_IionicMolalityStoich
double m_IionicMolalityStoich
Stoichiometric ionic strength on the molality scale.
Definition: DebyeHuckel.h:975
Cantera::DebyeHuckel::m_waterProps
std::unique_ptr< WaterProps > m_waterProps
Pointer to the water property calculator.
Definition: DebyeHuckel.h:1057
Cantera::DebyeHuckel::getActivities
virtual void getActivities(doublereal *ac) const
Get the array of non-dimensional activities at the current solution temperature, pressure,...
Definition: DebyeHuckel.cpp:130
Cantera::DebyeHuckel::m_tmpV
vector_fp m_tmpV
vector of size m_kk, used as a temporary holding area.
Definition: DebyeHuckel.h:1060
Cantera::DebyeHuckel::m_lnActCoeffMolal
vector_fp m_lnActCoeffMolal
Logarithm of the activity coefficients on the molality scale.
Definition: DebyeHuckel.h:1089
Cantera::DebyeHuckel::A_Debye_TP
virtual double A_Debye_TP(double temperature=-1.0, double pressure=-1.0) const
Return the Debye Huckel constant as a function of temperature and pressure (Units = sqrt(kg/gmol))
Definition: DebyeHuckel.cpp:726
Cantera::DebyeHuckel::dA_DebyedP_TP
virtual double dA_DebyedP_TP(double temperature=-1.0, double pressure=-1.0) const
Value of the derivative of the Debye Huckel constant with respect to pressure, as a function of tempe...
Definition: DebyeHuckel.cpp:800
Cantera::DebyeHuckel::calcDensity
virtual void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input.
Definition: DebyeHuckel.cpp:101
Cantera::DebyeHuckel::standardConcentration
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: DebyeHuckel.cpp:124
Cantera::MolalityVPSSTP::setStateFromXML
virtual void setStateFromXML(const XML_Node &state)
Set equation of state parameter values from XML entries.
Definition: MolalityVPSSTP.cpp:242
Cantera::MolalityVPSSTP::addSpecies
virtual bool addSpecies(shared_ptr< Species > spec)
Definition: MolalityVPSSTP.cpp:365
Cantera::MolalityVPSSTP::initThermo
virtual void initThermo()
Definition: MolalityVPSSTP.cpp:291
Cantera::MolalityVPSSTP::m_Mnaught
doublereal m_Mnaught
This is the multiplication factor that goes inside log expressions involving the molalities of specie...
Definition: MolalityVPSSTP.h:600
Cantera::MolalityVPSSTP::calcMolalities
void calcMolalities() const
Calculates the molality of all species and stores the result internally.
Definition: MolalityVPSSTP.cpp:68
Cantera::MolalityVPSSTP::m_molalities
vector_fp m_molalities
Current value of the molalities of the species in the phase.
Definition: MolalityVPSSTP.h:604
Cantera::PDSS_ConstVol
Class for pressure dependent standard states that use a constant volume model.
Definition: PDSS_ConstVol.h:23
Cantera::PDSS_Water
Class for the liquid water pressure dependent standard state.
Definition: PDSS_Water.h:50
Cantera::PDSS_Water::density
virtual doublereal density() const
Return the standard state density at standard state.
Definition: PDSS_Water.cpp:217
Cantera::PDSS::molarVolume
virtual doublereal molarVolume() const
Return the molar volume at standard state.
Definition: PDSS.cpp:72
Cantera::Phase::assignDensity
void assignDensity(const double density_)
Set the internally stored constant density (kg/m^3) of the phase.
Definition: Phase.cpp:698
Cantera::Phase::mean_X
doublereal mean_X(const doublereal *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
Definition: Phase.cpp:717
Cantera::Phase::m_speciesCharge
vector_fp m_speciesCharge
Vector of species charges. length m_kk.
Definition: Phase.h:954
Cantera::Phase::checkSpeciesIndex
void checkSpeciesIndex(size_t k) const
Check that the specified species index is in range.
Definition: Phase.cpp:211
Cantera::Phase::name
std::string name() const
Return the name of the phase.
Definition: Phase.cpp:70
Cantera::Phase::nSpecies
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:273
Cantera::Phase::charge
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:630
Cantera::Phase::m_kk
size_t m_kk
Number of species in the phase.
Definition: Phase.h:943
Cantera::Phase::speciesName
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:200
Cantera::Phase::meanMolecularWeight
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:751
Cantera::Phase::moleFraction
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition: Phase.cpp:548
Cantera::Phase::temperature
doublereal temperature() const
Temperature (K).
Definition: Phase.h:654
Cantera::Phase::speciesNames
const std::vector< std::string > & speciesNames() const
Return a const reference to the vector of species names.
Definition: Phase.cpp:206
Cantera::Phase::speciesIndex
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition: Phase.cpp:187
Cantera::Phase::species
shared_ptr< Species > species(const std::string &name) const
Return the Species object for the named species.
Definition: Phase.cpp:950
Cantera::ThermoPhase::RT
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:782
Cantera::ThermoPhase::initThermoFile
void initThermoFile(const std::string &inputFile, const std::string &id)
Definition: ThermoPhase.cpp:1066
Cantera::ThermoPhase::m_input
AnyMap m_input
Data supplied via setParameters.
Definition: ThermoPhase.h:1898
Cantera::ThermoPhase::getParameters
virtual void getParameters(int &n, doublereal *const c) const
Get the equation of state parameters in a vector.
Definition: ThermoPhase.cpp:1193
Cantera::VPStandardStateTP::_updateStandardStateThermo
virtual void _updateStandardStateThermo() const
Updates the standard state thermodynamic functions at the current T and P of the solution.
Definition: VPStandardStateTP.cpp:271
Cantera::VPStandardStateTP::getStandardVolumes
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of the species standard states at the current T and P of the solution.
Definition: VPStandardStateTP.cpp:98
Cantera::VPStandardStateTP::getCp_R
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the species standard states at the cu...
Definition: VPStandardStateTP.cpp:92
Cantera::VPStandardStateTP::getEntropy_R
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Entropy functions for the standard state species at the current T and...
Definition: VPStandardStateTP.cpp:64
Cantera::VPStandardStateTP::pressure
virtual doublereal pressure() const
Returns the current pressure of the phase.
Definition: VPStandardStateTP.h:140
Cantera::VPStandardStateTP::getSpeciesParameters
virtual void getSpeciesParameters(const std::string &name, AnyMap &speciesNode) const
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
Definition: VPStandardStateTP.cpp:167
Cantera::VPStandardStateTP::getStandardChemPotentials
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: VPStandardStateTP.cpp:50
Cantera::VPStandardStateTP::getEnthalpy_RT
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
Definition: VPStandardStateTP.cpp:58
Cantera::WaterProps
The WaterProps class is used to house several approximation routines for properties of water.
Definition: WaterProps.h:100
Cantera::XML_Node
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
Cantera::XML_Node::attrib
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:493
Cantera::XML_Node::hasChild
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
Cantera::XML_Node::id
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:539
Cantera::XML_Node::findByName
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:680
Cantera::XML_Node::child
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:547
Cantera::XML_Node::hasAttrib
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:534
ctml.h
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
electrolytes.h
Header file for a common definitions used in electrolytes thermodynamics.
Cantera::importPhase
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Definition: ThermoFactory.cpp:250
Cantera
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:557
Cantera::npos
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
Cantera::interp_est
static int interp_est(const std::string &estString)
Utility function to assign an integer value from a string for the ElectrolyteSpeciesType field.
Definition: DebyeHuckel.cpp:283
Cantera::getFloat
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:166
Cantera::fpValue
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
Definition: stringUtils.cpp:128
Cantera::caseInsensitiveEquals
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
Definition: stringUtils.cpp:266
Cantera::SmallNumber
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:153
Cantera::GasConstant
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:113
Cantera::getMatrixValues
void getMatrixValues(const XML_Node &node, const std::vector< std::string > &keyStringRow, const std::vector< std::string > &keyStringCol, Array2D &retnValues, const bool convert, const bool matrixSymmetric)
This function interprets the value portion of an XML element as a series of "Matrix ids and entries" ...
Definition: ctml.cpp:364
Cantera::toSI
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string 'unit' to SI units.
Definition: global.cpp:170
Cantera::cEST_solvent
const int cEST_solvent
Electrolyte species type.
Definition: electrolytes.h:18
Cantera::getMap
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:332
stringUtils.h
Contains declarations for string manipulation functions within Cantera.