Loading [MathJax]/extensions/tex2jax.js
Cantera  3.2.0a1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
21
22#include <cstdio>
23
24namespace Cantera
25{
26
27namespace {
28double A_Debye_default = 1.172576; // units = sqrt(kg/gmol)
29double B_Debye_default = 3.28640E9; // units = sqrt(kg/gmol) / m
30double maxIionicStrength_default = 30.0;
31}
32
33DebyeHuckel::DebyeHuckel(const string& inputFile, const string& id_)
34 : m_maxIionicStrength(maxIionicStrength_default)
35 , m_A_Debye(A_Debye_default)
36 , m_B_Debye(B_Debye_default)
37{
38 initThermoFile(inputFile, id_);
39}
40
41DebyeHuckel::~DebyeHuckel()
42{
43 // Defined in .cpp to limit dependence on WaterProps.h
44}
45
46// ------- Mechanical Equation of State Properties ------------------------
47
49{
50 if (m_waterSS) {
51 // Store the internal density of the water SS. Note, we would have to do
52 // this for all other species if they had pressure dependent properties.
54 }
56}
57
58// ------- Activities and Activity Concentrations
59
61{
62 double c_solvent = standardConcentration();
64 for (size_t k = 0; k < m_kk; k++) {
65 c[k] *= c_solvent;
66 }
67}
68
70{
71 double mvSolvent = providePDSS(0)->molarVolume();
72 return 1.0 / mvSolvent;
73}
74
75void DebyeHuckel::getActivities(double* ac) const
76{
78
79 // Update the molality array, m_molalities(). This requires an update due to
80 // mole fractions
82 for (size_t k = 1; k < m_kk; k++) {
83 ac[k] = m_molalities[k] * exp(m_lnActCoeffMolal[k]);
84 }
85 double xmolSolvent = moleFraction(0);
86 ac[0] = exp(m_lnActCoeffMolal[0]) * xmolSolvent;
87}
88
90{
92 A_Debye_TP(-1.0, -1.0);
94 copy(m_lnActCoeffMolal.begin(), m_lnActCoeffMolal.end(), acMolality);
95 for (size_t k = 0; k < m_kk; k++) {
96 acMolality[k] = exp(acMolality[k]);
97 }
98}
99
100// ------ Partial Molar Properties of the Solution -----------------
101
102void DebyeHuckel::getChemPotentials(double* mu) const
103{
104 double xx;
105
106 // First get the standard chemical potentials in molar form. This requires
107 // updates of standard state as a function of T and P
109
110 // Update the activity coefficients. This also updates the internal molality
111 // array.
113 double xmolSolvent = moleFraction(0);
114 for (size_t k = 1; k < m_kk; k++) {
115 xx = std::max(m_molalities[k], SmallNumber);
116 mu[k] += RT() * (log(xx) + m_lnActCoeffMolal[k]);
117 }
118 xx = std::max(xmolSolvent, SmallNumber);
119 mu[0] += RT() * (log(xx) + m_lnActCoeffMolal[0]);
120}
121
123{
124 // Get the nondimensional standard state enthalpies
125 getEnthalpy_RT(hbar);
126
127 // Dimensionalize it.
128 for (size_t k = 0; k < m_kk; k++) {
129 hbar[k] *= RT();
130 }
131
132 // Check to see whether activity coefficients are temperature
133 // dependent. If they are, then calculate the their temperature
134 // derivatives and add them into the result.
135 double dAdT = dA_DebyedT_TP();
136 if (dAdT != 0.0) {
137 // Update the activity coefficients, This also update the
138 // internally stored molalities.
141 for (size_t k = 0; k < m_kk; k++) {
142 hbar[k] -= RT() * temperature() * m_dlnActCoeffMolaldT[k];
143 }
144 }
145}
146
148{
149 // Get the standard state entropies at the temperature and pressure of the
150 // solution.
151 getEntropy_R(sbar);
152
153 // Dimensionalize the entropies
154 for (size_t k = 0; k < m_kk; k++) {
155 sbar[k] *= GasConstant;
156 }
157
158 // Update the activity coefficients, This also update the internally stored
159 // molalities.
161
162 // First we will add in the obvious dependence on the T term out front of
163 // the log activity term
164 double mm;
165 for (size_t k = 1; k < m_kk; k++) {
166 mm = std::max(SmallNumber, m_molalities[k]);
167 sbar[k] -= GasConstant * (log(mm) + m_lnActCoeffMolal[k]);
168 }
169 double xmolSolvent = moleFraction(0);
170 mm = std::max(SmallNumber, xmolSolvent);
171 sbar[0] -= GasConstant *(log(mm) + m_lnActCoeffMolal[0]);
172
173 // Check to see whether activity coefficients are temperature dependent. If
174 // they are, then calculate the their temperature derivatives and add them
175 // into the result.
176 double dAdT = dA_DebyedT_TP();
177 if (dAdT != 0.0) {
179 for (size_t k = 0; k < m_kk; k++) {
180 sbar[k] -= RT() * m_dlnActCoeffMolaldT[k];
181 }
182 }
183}
184
186{
187 getStandardVolumes(vbar);
188
189 // Update the derivatives wrt the activity coefficients.
192 for (size_t k = 0; k < m_kk; k++) {
193 vbar[k] += RT() * m_dlnActCoeffMolaldP[k];
194 }
195}
196
197void DebyeHuckel::getPartialMolarCp(double* cpbar) const
198{
199 getCp_R(cpbar);
200 for (size_t k = 0; k < m_kk; k++) {
201 cpbar[k] *= GasConstant;
202 }
203
204 // Check to see whether activity coefficients are temperature dependent. If
205 // they are, then calculate the their temperature derivatives and add them
206 // into the result.
207 double dAdT = dA_DebyedT_TP();
208 if (dAdT != 0.0) {
209 // Update the activity coefficients, This also update the internally
210 // stored molalities.
214 for (size_t k = 0; k < m_kk; k++) {
215 cpbar[k] -= (2.0 * RT() * m_dlnActCoeffMolaldT[k] +
217 }
218 }
219}
220
221// -------------- Utilities -------------------------------
222
223//! Utility function to assign an integer value from a string for the
224//! ElectrolyteSpeciesType field.
225/*!
226 * @param estString input string that will be interpreted
227 */
228static int interp_est(const string& estString)
229{
230 if (caseInsensitiveEquals(estString, "solvent")) {
231 return cEST_solvent;
232 } else if (estString == "charged-species"
233 || caseInsensitiveEquals(estString, "chargedspecies")) {
234 return cEST_chargedSpecies;
235 } else if (estString == "weak-acid-associated"
236 || caseInsensitiveEquals(estString, "weakacidassociated")) {
237 return cEST_weakAcidAssociated;
238 } else if (estString == "strong-acid-associated"
239 || caseInsensitiveEquals(estString, "strongacidassociated")) {
240 return cEST_strongAcidAssociated;
241 } else if (estString == "polar-neutral"
242 || caseInsensitiveEquals(estString, "polarneutral")) {
243 return cEST_polarNeutral;
244 } else if (estString == "nonpolar-neutral"
245 || caseInsensitiveEquals(estString, "nonpolarneutral")) {
246 return cEST_nonpolarNeutral;
247 } else {
248 throw CanteraError("interp_est (DebyeHuckel)",
249 "Invalid electrolyte species type '{}'", estString);
250 }
251}
252
253void DebyeHuckel::setDebyeHuckelModel(const string& model) {
254 if (model == ""
255 || model == "dilute-limit"
256 || caseInsensitiveEquals(model, "Dilute_limit")) {
257 m_formDH = DHFORM_DILUTE_LIMIT;
258 } else if (model == "B-dot-with-variable-a"
259 || caseInsensitiveEquals(model, "Bdot_with_variable_a")) {
260 m_formDH = DHFORM_BDOT_AK;
261 } else if (model == "B-dot-with-common-a"
262 || caseInsensitiveEquals(model, "Bdot_with_common_a")) {
263 m_formDH = DHFORM_BDOT_ACOMMON;
264 } else if (caseInsensitiveEquals(model, "beta_ij")) {
265 m_formDH = DHFORM_BETAIJ;
266 m_Beta_ij.resize(m_kk, m_kk, 0.0);
267 } else if (model == "Pitzer-with-beta_ij"
268 || caseInsensitiveEquals(model, "Pitzer_with_Beta_ij")) {
269 m_formDH = DHFORM_PITZER_BETAIJ;
270 m_Beta_ij.resize(m_kk, m_kk, 0.0);
271 } else {
272 throw CanteraError("DebyeHuckel::setDebyeHuckelModel",
273 "Unknown model '{}'", model);
274 }
275}
276
278{
279 if (A < 0) {
280 m_form_A_Debye = A_DEBYE_WATER;
281 } else {
282 m_form_A_Debye = A_DEBYE_CONST;
283 m_A_Debye = A;
284 }
285}
286
287void DebyeHuckel::setB_dot(double bdot)
288{
289 if (m_formDH == DHFORM_BETAIJ || m_formDH == DHFORM_DILUTE_LIMIT ||
290 m_formDH == DHFORM_PITZER_BETAIJ) {
291 throw CanteraError("DebyeHuckel::setB_dot",
292 "B_dot entry in the wrong DH form");
293 }
294 // Set B_dot parameters for charged species
295 for (size_t k = 0; k < nSpecies(); k++) {
296 if (fabs(charge(k)) > 0.0001) {
297 m_B_Dot[k] = bdot;
298 } else {
299 m_B_Dot[k] = 0.0;
300 }
301 }
302}
303
305{
306 m_Aionic_default = value;
307 for (size_t k = 0; k < m_kk; k++) {
308 if (std::isnan(m_Aionic[k])) {
309 m_Aionic[k] = value;
310 }
311 }
312}
313
314void DebyeHuckel::setBeta(const string& sp1, const string& sp2, double value)
315{
316 size_t k1 = speciesIndex(sp1);
317 if (k1 == npos) {
318 throw CanteraError("DebyeHuckel::setBeta", "Species '{}' not found", sp1);
319 }
320 size_t k2 = speciesIndex(sp2);
321 if (k2 == npos) {
322 throw CanteraError("DebyeHuckel::setBeta", "Species '{}' not found", sp2);
323 }
324 m_Beta_ij(k1, k2) = value;
325 m_Beta_ij(k2, k1) = value;
326}
327
329{
331 if (m_input.hasKey("activity-data")) {
332 auto& node = m_input["activity-data"].as<AnyMap>();
333 setDebyeHuckelModel(node["model"].asString());
334 if (node.hasKey("A_Debye")) {
335 if (node["A_Debye"] == "variable") {
336 setA_Debye(-1);
337 } else {
338 setA_Debye(node.convert("A_Debye", "kg^0.5/gmol^0.5"));
339 }
340 }
341 if (node.hasKey("B_Debye")) {
342 setB_Debye(node.convert("B_Debye", "kg^0.5/gmol^0.5/m"));
343 }
344 if (node.hasKey("max-ionic-strength")) {
345 setMaxIonicStrength(node["max-ionic-strength"].asDouble());
346 }
347 if (node.hasKey("use-Helgeson-fixed-form")) {
348 useHelgesonFixedForm(node["use-Helgeson-fixed-form"].asBool());
349 }
350 if (node.hasKey("default-ionic-radius")) {
351 setDefaultIonicRadius(node.convert("default-ionic-radius", "m"));
352 }
353 if (node.hasKey("B-dot")) {
354 setB_dot(node["B-dot"].asDouble());
355 }
356 if (node.hasKey("beta")) {
357 for (auto& item : node["beta"].asVector<AnyMap>()) {
358 auto& species = item["species"].asVector<string>(2);
359 setBeta(species[0], species[1], item["beta"].asDouble());
360 }
361 }
362 }
363
364 // Solvent
365 m_waterSS = dynamic_cast<PDSS_Water*>(providePDSS(0));
366 if (m_waterSS) {
367 // Initialize the water property calculator. It will share the internal
368 // eos water calculator.
369 if (m_form_A_Debye == A_DEBYE_WATER) {
370 m_waterProps = make_unique<WaterProps>(m_waterSS);
371 }
372 } else if (dynamic_cast<PDSS_ConstVol*>(providePDSS(0)) == 0) {
373 throw CanteraError("DebyeHuckel::initThermo", "Solvent standard state"
374 " model must be WaterIAPWS or constant_incompressible.");
375 }
376
377 // Solutes
378 for (size_t k = 1; k < nSpecies(); k++) {
379 if (dynamic_cast<PDSS_ConstVol*>(providePDSS(k)) == 0) {
380 throw CanteraError("DebyeHuckel::initThermo", "Solute standard"
381 " state model must be constant_incompressible.");
382 }
383 }
384}
385
386void DebyeHuckel::getParameters(AnyMap& phaseNode) const
387{
389 AnyMap activityNode;
390
391 switch (m_formDH) {
392 case DHFORM_DILUTE_LIMIT:
393 activityNode["model"] = "dilute-limit";
394 break;
395 case DHFORM_BDOT_AK:
396 activityNode["model"] = "B-dot-with-variable-a";
397 break;
398 case DHFORM_BDOT_ACOMMON:
399 activityNode["model"] = "B-dot-with-common-a";
400 break;
401 case DHFORM_BETAIJ:
402 activityNode["model"] = "beta_ij";
403 break;
404 case DHFORM_PITZER_BETAIJ:
405 activityNode["model"] = "Pitzer-with-beta_ij";
406 break;
407 }
408
409 if (m_form_A_Debye == A_DEBYE_WATER) {
410 activityNode["A_Debye"] = "variable";
411 } else if (m_A_Debye != A_Debye_default) {
412 activityNode["A_Debye"].setQuantity(m_A_Debye, "kg^0.5/gmol^0.5");
413 }
414
415 if (m_B_Debye != B_Debye_default) {
416 activityNode["B_Debye"].setQuantity(m_B_Debye, "kg^0.5/gmol^0.5/m");
417 }
418 if (m_maxIionicStrength != maxIionicStrength_default) {
419 activityNode["max-ionic-strength"] = m_maxIionicStrength;
420 }
422 activityNode["use-Helgeson-fixed-form"] = true;
423 }
424 if (!isnan(m_Aionic_default)) {
425 activityNode["default-ionic-radius"].setQuantity(m_Aionic_default, "m");
426 }
427 for (double B_dot : m_B_Dot) {
428 if (B_dot != 0.0) {
429 activityNode["B-dot"] = B_dot;
430 break;
431 }
432 }
433 if (m_Beta_ij.nRows() && m_Beta_ij.nColumns()) {
434 vector<AnyMap> beta;
435 for (size_t i = 0; i < m_kk; i++) {
436 for (size_t j = i; j < m_kk; j++) {
437 if (m_Beta_ij(i, j) != 0) {
438 AnyMap entry;
439 entry["species"] = vector<string>{
440 speciesName(i), speciesName(j)};
441 entry["beta"] = m_Beta_ij(i, j);
442 beta.push_back(std::move(entry));
443 }
444 }
445 }
446 activityNode["beta"] = std::move(beta);
447 }
448 phaseNode["activity-data"] = std::move(activityNode);
449}
450
451void DebyeHuckel::getSpeciesParameters(const string& name, AnyMap& speciesNode) const
452{
454 size_t k = speciesIndex(name);
456 AnyMap dhNode;
457 if (m_Aionic[k] != m_Aionic_default) {
458 dhNode["ionic-radius"].setQuantity(m_Aionic[k], "m");
459 }
460
461 int estDefault = cEST_nonpolarNeutral;
462 if (k == 0) {
463 estDefault = cEST_solvent;
464 }
465
466 if (m_speciesCharge_Stoich[k] != charge(k)) {
467 dhNode["weak-acid-charge"] = m_speciesCharge_Stoich[k];
468 estDefault = cEST_weakAcidAssociated;
469 } else if (fabs(charge(k)) > 0.0001) {
470 estDefault = cEST_chargedSpecies;
471 }
472
473 if (m_electrolyteSpeciesType[k] != estDefault) {
474 string estType;
475 switch (m_electrolyteSpeciesType[k]) {
476 case cEST_solvent:
477 estType = "solvent";
478 break;
479 case cEST_chargedSpecies:
480 estType = "charged-species";
481 break;
482 case cEST_weakAcidAssociated:
483 estType = "weak-acid-associated";
484 break;
485 case cEST_strongAcidAssociated:
486 estType = "strong-acid-associated";
487 break;
488 case cEST_polarNeutral:
489 estType = "polar-neutral";
490 break;
491 case cEST_nonpolarNeutral:
492 estType = "nonpolar-neutral";
493 break;
494 default:
495 throw CanteraError("DebyeHuckel::getSpeciesParameters",
496 "Unknown electrolyte species type ({}) for species '{}'",
498 }
499 dhNode["electrolyte-species-type"] = estType;
500 }
501
502 if (dhNode.size()) {
503 speciesNode["Debye-Huckel"] = std::move(dhNode);
504 }
505}
506
507
508double DebyeHuckel::A_Debye_TP(double tempArg, double presArg) const
509{
510 double T = temperature();
511 double A;
512 if (tempArg != -1.0) {
513 T = tempArg;
514 }
515 double P = pressure();
516 if (presArg != -1.0) {
517 P = presArg;
518 }
519
520 switch (m_form_A_Debye) {
521 case A_DEBYE_CONST:
522 A = m_A_Debye;
523 break;
524 case A_DEBYE_WATER:
525 A = m_waterProps->ADebye(T, P, 0);
526 m_A_Debye = A;
527 break;
528 default:
529 throw CanteraError("DebyeHuckel::A_Debye_TP", "shouldn't be here");
530 }
531 return A;
532}
533
534double DebyeHuckel::dA_DebyedT_TP(double tempArg, double presArg) const
535{
536 double T = temperature();
537 if (tempArg != -1.0) {
538 T = tempArg;
539 }
540 double P = pressure();
541 if (presArg != -1.0) {
542 P = presArg;
543 }
544 double dAdT;
545 switch (m_form_A_Debye) {
546 case A_DEBYE_CONST:
547 dAdT = 0.0;
548 break;
549 case A_DEBYE_WATER:
550 dAdT = m_waterProps->ADebye(T, P, 1);
551 break;
552 default:
553 throw CanteraError("DebyeHuckel::dA_DebyedT_TP", "shouldn't be here");
554 }
555 return dAdT;
556}
557
558double DebyeHuckel::d2A_DebyedT2_TP(double tempArg, double presArg) const
559{
560 double T = temperature();
561 if (tempArg != -1.0) {
562 T = tempArg;
563 }
564 double P = pressure();
565 if (presArg != -1.0) {
566 P = presArg;
567 }
568 double d2AdT2;
569 switch (m_form_A_Debye) {
570 case A_DEBYE_CONST:
571 d2AdT2 = 0.0;
572 break;
573 case A_DEBYE_WATER:
574 d2AdT2 = m_waterProps->ADebye(T, P, 2);
575 break;
576 default:
577 throw CanteraError("DebyeHuckel::d2A_DebyedT2_TP", "shouldn't be here");
578 }
579 return d2AdT2;
580}
581
582double DebyeHuckel::dA_DebyedP_TP(double tempArg, double presArg) const
583{
584 double T = temperature();
585 if (tempArg != -1.0) {
586 T = tempArg;
587 }
588 double P = pressure();
589 if (presArg != -1.0) {
590 P = presArg;
591 }
592 double dAdP;
593 switch (m_form_A_Debye) {
594 case A_DEBYE_CONST:
595 dAdP = 0.0;
596 break;
597 case A_DEBYE_WATER:
598 dAdP = m_waterProps->ADebye(T, P, 3);
599 break;
600 default:
601 throw CanteraError("DebyeHuckel::dA_DebyedP_TP", "shouldn't be here");
602 }
603 return dAdP;
604}
605
606// ---------- Other Property Functions
607
608double DebyeHuckel::AionicRadius(int k) const
609{
610 return m_Aionic[k];
611}
612
613// ------------ Private and Restricted Functions ------------------
614
615bool DebyeHuckel::addSpecies(shared_ptr<Species> spec)
616{
617 bool added = MolalityVPSSTP::addSpecies(spec);
618 if (added) {
619 m_lnActCoeffMolal.push_back(0.0);
620 m_dlnActCoeffMolaldT.push_back(0.0);
621 m_d2lnActCoeffMolaldT2.push_back(0.0);
622 m_dlnActCoeffMolaldP.push_back(0.0);
623 m_B_Dot.push_back(0.0);
624
625 // NAN will be replaced with default value
626 double Aionic = NAN;
627
628 // Guess electrolyte species type based on charge properties
629 int est = cEST_nonpolarNeutral;
630 double stoichCharge = spec->charge;
631 if (fabs(spec->charge) > 0.0001) {
632 est = cEST_chargedSpecies;
633 }
634
635 if (spec->input.hasKey("Debye-Huckel")) {
636 auto& dhNode = spec->input["Debye-Huckel"].as<AnyMap>();
637 Aionic = dhNode.convert("ionic-radius", "m", NAN);
638 if (dhNode.hasKey("weak-acid-charge")) {
639 stoichCharge = dhNode["weak-acid-charge"].asDouble();
640 if (fabs(stoichCharge - spec->charge) > 0.0001) {
641 est = cEST_weakAcidAssociated;
642 }
643 }
644 // Apply override of the electrolyte species type
645 if (dhNode.hasKey("electrolyte-species-type")) {
646 est = interp_est(dhNode["electrolyte-species-type"].asString());
647 }
648 }
649
650 if (m_electrolyteSpeciesType.size() == 0) {
651 est = cEST_solvent; // species 0 is the solvent
652 }
653
654 m_Aionic.push_back(Aionic);
655 m_speciesCharge_Stoich.push_back(stoichCharge);
656 m_electrolyteSpeciesType.push_back(est);
657 }
658 return added;
659}
660
661double DebyeHuckel::_nonpolarActCoeff(double IionicMolality)
662{
663 // These are coefficients to describe the increase in activity coeff for
664 // non-polar molecules due to the electrolyte becoming stronger (the so-
665 // called salt-out effect)
666 const static double npActCoeff[] = {0.1127, -0.01049, 1.545E-3};
667 double I2 = IionicMolality * IionicMolality;
668 double l10actCoeff =
669 npActCoeff[0] * IionicMolality +
670 npActCoeff[1] * I2 +
671 npActCoeff[2] * I2 * IionicMolality;
672 return pow(10.0 , l10actCoeff);
673}
674
676{
677 const double a0 = 1.454;
678 const double b0 = 0.02236;
679 const double c0 = 9.380E-3;
680 const double d0 = -5.362E-4;
681 double Is = m_IionicMolalityStoich;
682 if (Is <= 0.0) {
683 return 0.0;
684 }
685 double Is2 = Is * Is;
686 double bhat = 1.0 + a0 * sqrt(Is);
687 double func = bhat - 2.0 * log(bhat) - 1.0/bhat;
688 double v1 = m_A_Debye / (a0 * a0 * a0 * Is) * func;
689 double oc = 1.0 - v1 + b0 * Is / 2.0 + 2.0 * c0 * Is2 / 3.0
690 + 3.0 * d0 * Is2 * Is / 4.0;
691 return oc;
692}
693
695{
696 // Update the internally stored vector of molalities
698 double oc = _osmoticCoeffHelgesonFixedForm();
699 double sum = 0.0;
700 for (size_t k = 1; k < m_kk; k++) {
701 sum += std::max(m_molalities[k], 0.0);
702 }
703 if (sum > 2.0 * m_maxIionicStrength) {
704 sum = 2.0 * m_maxIionicStrength;
705 };
706 return - m_Mnaught * sum * oc;
707}
708
710{
711 double z_k, zs_k1, zs_k2;
712
713 // Update the internally stored vector of molalities
715
716 // Calculate the apparent (real) ionic strength.
717 //
718 // Note this is not the stoichiometric ionic strengh, where reactions of
719 // ions forming neutral salts are ignorred in calculating the ionic
720 // strength.
721 m_IionicMolality = 0.0;
722 for (size_t k = 0; k < m_kk; k++) {
723 z_k = m_speciesCharge[k];
724 m_IionicMolality += m_molalities[k] * z_k * z_k;
725 }
726 m_IionicMolality /= 2.0;
728
729 // Calculate the stoichiometric ionic charge
731 for (size_t k = 0; k < m_kk; k++) {
732 z_k = m_speciesCharge[k];
733 zs_k1 = m_speciesCharge_Stoich[k];
734 if (z_k == zs_k1) {
735 m_IionicMolalityStoich += m_molalities[k] * z_k * z_k;
736 } else {
737 zs_k2 = z_k - zs_k1;
738 m_IionicMolalityStoich += m_molalities[k] * (zs_k1 * zs_k1 + zs_k2 * zs_k2);
739 }
740 }
743
744 // Possibly update the stored value of the Debye-Huckel parameter A_Debye
745 // This parameter appears on the top of the activity coefficient expression.
746 // It depends on T (and P), as it depends explicitly on the temperature.
747 // Also, the dielectric constant is usually a fairly strong function of T,
748 // also.
750
751 // Calculate a safe value for the mole fraction of the solvent
752 double xmolSolvent = moleFraction(0);
753 xmolSolvent = std::max(8.689E-3, xmolSolvent);
754
755 int est;
756 double ac_nonPolar = 1.0;
757 double numTmp = m_A_Debye * sqrt(m_IionicMolality);
758 double denomTmp = m_B_Debye * sqrt(m_IionicMolality);
759 double coeff;
760 double lnActivitySolvent = 0.0;
761 double tmp;
762 double tmpLn;
763 double y, yp1, sigma;
764 switch (m_formDH) {
765 case DHFORM_DILUTE_LIMIT:
766 for (size_t k = 0; k < m_kk; k++) {
767 z_k = m_speciesCharge[k];
768 m_lnActCoeffMolal[k] = - z_k * z_k * numTmp;
769 }
770 lnActivitySolvent =
771 (xmolSolvent - 1.0)/xmolSolvent +
772 2.0 / 3.0 * m_A_Debye * m_Mnaught *
774 break;
775
776 case DHFORM_BDOT_AK:
777 ac_nonPolar = _nonpolarActCoeff(m_IionicMolality);
778 for (size_t k = 0; k < m_kk; k++) {
780 if (est == cEST_nonpolarNeutral) {
781 m_lnActCoeffMolal[k] = log(ac_nonPolar);
782 } else {
783 z_k = m_speciesCharge[k];
785 - z_k * z_k * numTmp / (1.0 + denomTmp * m_Aionic[k])
786 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
787 }
788 }
789
790 lnActivitySolvent = (xmolSolvent - 1.0)/xmolSolvent;
791 coeff = 2.0 / 3.0 * m_A_Debye * m_Mnaught
792 * sqrt(m_IionicMolality);
793 tmp = 0.0;
794 if (denomTmp > 0.0) {
795 for (size_t k = 0; k < m_kk; k++) {
796 if (k != 0 || m_Aionic[k] != 0.0) {
797 y = denomTmp * m_Aionic[k];
798 yp1 = y + 1.0;
799 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
800 z_k = m_speciesCharge[k];
801 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
802 }
803 }
804 }
805 lnActivitySolvent += coeff * tmp;
806 tmp = 0.0;
807 for (size_t k = 1; k < m_kk; k++) {
808 z_k = m_speciesCharge[k];
809 if (z_k != 0.0) {
810 tmp += m_B_Dot[k] * m_molalities[k];
811 }
812 }
813 lnActivitySolvent -=
814 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
815
816 // Special section to implement the Helgeson fixed form for the water
817 // brine activity coefficient.
819 lnActivitySolvent = _lnactivityWaterHelgesonFixedForm();
820 }
821 break;
822
823 case DHFORM_BDOT_ACOMMON:
824 denomTmp *= m_Aionic[0];
825 for (size_t k = 0; k < m_kk; k++) {
826 z_k = m_speciesCharge[k];
828 - z_k * z_k * numTmp / (1.0 + denomTmp)
829 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
830 }
831 if (denomTmp > 0.0) {
832 y = denomTmp;
833 yp1 = y + 1.0;
834 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
835 } else {
836 sigma = 0.0;
837 }
838 lnActivitySolvent =
839 (xmolSolvent - 1.0)/xmolSolvent +
840 2.0 /3.0 * m_A_Debye * m_Mnaught *
841 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
842 tmp = 0.0;
843 for (size_t k = 1; k < m_kk; k++) {
844 z_k = m_speciesCharge[k];
845 if (z_k != 0.0) {
846 tmp += m_B_Dot[k] * m_molalities[k];
847 }
848 }
849 lnActivitySolvent -=
850 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
851 break;
852
853 case DHFORM_BETAIJ:
854 denomTmp = m_B_Debye * m_Aionic[0];
855 denomTmp *= sqrt(m_IionicMolality);
856 lnActivitySolvent =
857 (xmolSolvent - 1.0)/xmolSolvent;
858
859 for (size_t k = 1; k < m_kk; k++) {
860 z_k = m_speciesCharge[k];
862 - z_k * z_k * numTmp / (1.0 + denomTmp);
863 for (size_t j = 0; j < m_kk; j++) {
864 double beta = m_Beta_ij.value(k, j);
865 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] * beta;
866 }
867 }
868 if (denomTmp > 0.0) {
869 y = denomTmp;
870 yp1 = y + 1.0;
871 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
872 } else {
873 sigma = 0.0;
874 }
875 lnActivitySolvent =
876 (xmolSolvent - 1.0)/xmolSolvent +
877 2.0 /3.0 * m_A_Debye * m_Mnaught *
878 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
879 tmp = 0.0;
880 for (size_t k = 0; k < m_kk; k++) {
881 for (size_t j = 0; j < m_kk; j++) {
882 tmp +=
884 }
885 }
886 lnActivitySolvent -= m_Mnaught * tmp;
887 break;
888
889 case DHFORM_PITZER_BETAIJ:
890 denomTmp = m_B_Debye * sqrt(m_IionicMolality);
891 denomTmp *= m_Aionic[0];
892 numTmp = m_A_Debye * sqrt(m_IionicMolality);
893 tmpLn = log(1.0 + denomTmp);
894 for (size_t k = 1; k < m_kk; k++) {
895 z_k = m_speciesCharge[k];
897 - z_k * z_k * numTmp / 3.0 / (1.0 + denomTmp);
899 - 2.0 * z_k * z_k * m_A_Debye * tmpLn /
900 (3.0 * m_B_Debye * m_Aionic[0]);
901 for (size_t j = 0; j < m_kk; j++) {
902 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] *
903 m_Beta_ij.value(k, j);
904 }
905 }
906 sigma = 1.0 / (1.0 + denomTmp);
907 lnActivitySolvent =
908 (xmolSolvent - 1.0)/xmolSolvent +
909 2.0 /3.0 * m_A_Debye * m_Mnaught *
910 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
911 tmp = 0.0;
912 for (size_t k = 0; k < m_kk; k++) {
913 for (size_t j = 0; j < m_kk; j++) {
914 tmp +=
916 }
917 }
918 lnActivitySolvent -= m_Mnaught * tmp;
919 break;
920
921 default:
922 throw CanteraError("DebyeHuckel::s_update_lnMolalityActCoeff", "ERROR");
923 }
924
925 // Above, we calculated the ln(activitySolvent). Translate that into the
926 // molar-based activity coefficient by dividing by the solvent mole
927 // fraction. Solvents are not on the molality scale.
928 xmolSolvent = moleFraction(0);
929 m_lnActCoeffMolal[0] = lnActivitySolvent - log(xmolSolvent);
930}
931
933{
934 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
935 // First we store dAdT explicitly here
936 double dAdT = dA_DebyedT_TP();
937 if (dAdT == 0.0) {
938 for (size_t k = 0; k < m_kk; k++) {
939 m_dlnActCoeffMolaldT[k] = 0.0;
940 }
941 return;
942 }
943
944 // Calculate a safe value for the mole fraction of the solvent
945 double xmolSolvent = moleFraction(0);
946 xmolSolvent = std::max(8.689E-3, xmolSolvent);
947 double sqrtI = sqrt(m_IionicMolality);
948 double numdAdTTmp = dAdT * sqrtI;
949 double denomTmp = m_B_Debye * sqrtI;
950 double d_lnActivitySolvent_dT = 0;
951
952 switch (m_formDH) {
953 case DHFORM_DILUTE_LIMIT:
954 for (size_t k = 1; k < m_kk; k++) {
956 m_lnActCoeffMolal[k] * dAdT / m_A_Debye;
957 }
958 d_lnActivitySolvent_dT = 2.0 / 3.0 * dAdT * m_Mnaught *
960 m_dlnActCoeffMolaldT[0] = d_lnActivitySolvent_dT;
961 break;
962
963 case DHFORM_BDOT_AK:
964 for (size_t k = 0; k < m_kk; k++) {
965 z_k = m_speciesCharge[k];
967 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp * m_Aionic[k]);
968 }
969
970 m_dlnActCoeffMolaldT[0] = 0.0;
971 coeff = 2.0 / 3.0 * dAdT * m_Mnaught * sqrtI;
972 tmp = 0.0;
973 if (denomTmp > 0.0) {
974 for (size_t k = 0; k < m_kk; k++) {
975 y = denomTmp * m_Aionic[k];
976 yp1 = y + 1.0;
977 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
978 z_k = m_speciesCharge[k];
979 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
980 }
981 }
982 m_dlnActCoeffMolaldT[0] += coeff * tmp;
983 break;
984
985 case DHFORM_BDOT_ACOMMON:
986 denomTmp *= m_Aionic[0];
987 for (size_t k = 0; k < m_kk; k++) {
988 z_k = m_speciesCharge[k];
990 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp);
991 }
992 if (denomTmp > 0.0) {
993 y = denomTmp;
994 yp1 = y + 1.0;
995 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
996 } else {
997 sigma = 0.0;
998 }
999 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1000 m_IionicMolality * sqrtI * sigma;
1001 break;
1002
1003 case DHFORM_BETAIJ:
1004 denomTmp *= m_Aionic[0];
1005 for (size_t k = 1; k < m_kk; k++) {
1006 z_k = m_speciesCharge[k];
1007 m_dlnActCoeffMolaldT[k] = -z_k*z_k * numdAdTTmp / (1.0 + denomTmp);
1008 }
1009 if (denomTmp > 0.0) {
1010 y = denomTmp;
1011 yp1 = y + 1.0;
1012 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1013 } else {
1014 sigma = 0.0;
1015 }
1016 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1017 m_IionicMolality * sqrtI * sigma;
1018 break;
1019
1020 case DHFORM_PITZER_BETAIJ:
1021 denomTmp *= m_Aionic[0];
1022 tmpLn = log(1.0 + denomTmp);
1023 for (size_t k = 1; k < m_kk; k++) {
1024 z_k = m_speciesCharge[k];
1026 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp)
1027 - 2.0 * z_k * z_k * dAdT * tmpLn / (m_B_Debye * m_Aionic[0]);
1028 m_dlnActCoeffMolaldT[k] /= 3.0;
1029 }
1030
1031 sigma = 1.0 / (1.0 + denomTmp);
1032 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1033 m_IionicMolality * sqrtI * sigma;
1034 break;
1035
1036 default:
1037 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dT",
1038 "ERROR");
1039 }
1040}
1041
1043{
1044 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1045 double dAdT = dA_DebyedT_TP();
1046 double d2AdT2 = d2A_DebyedT2_TP();
1047 if (d2AdT2 == 0.0 && dAdT == 0.0) {
1048 for (size_t k = 0; k < m_kk; k++) {
1049 m_d2lnActCoeffMolaldT2[k] = 0.0;
1050 }
1051 return;
1052 }
1053
1054 // Calculate a safe value for the mole fraction of the solvent
1055 double xmolSolvent = moleFraction(0);
1056 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1057 double sqrtI = sqrt(m_IionicMolality);
1058 double numd2AdT2Tmp = d2AdT2 * sqrtI;
1059 double denomTmp = m_B_Debye * sqrtI;
1060
1061 switch (m_formDH) {
1062 case DHFORM_DILUTE_LIMIT:
1063 for (size_t k = 0; k < m_kk; k++) {
1065 m_lnActCoeffMolal[k] * d2AdT2 / m_A_Debye;
1066 }
1067 break;
1068
1069 case DHFORM_BDOT_AK:
1070 for (size_t k = 0; k < m_kk; k++) {
1071 z_k = m_speciesCharge[k];
1073 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp * m_Aionic[k]);
1074 }
1075
1076 m_d2lnActCoeffMolaldT2[0] = 0.0;
1077 coeff = 2.0 / 3.0 * d2AdT2 * m_Mnaught * sqrtI;
1078 tmp = 0.0;
1079 if (denomTmp > 0.0) {
1080 for (size_t k = 0; k < m_kk; k++) {
1081 y = denomTmp * m_Aionic[k];
1082 yp1 = y + 1.0;
1083 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1084 z_k = m_speciesCharge[k];
1085 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1086 }
1087 }
1088 m_d2lnActCoeffMolaldT2[0] += coeff * tmp;
1089 break;
1090
1091 case DHFORM_BDOT_ACOMMON:
1092 denomTmp *= m_Aionic[0];
1093 for (size_t k = 0; k < m_kk; k++) {
1094 z_k = m_speciesCharge[k];
1096 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1097 }
1098 if (denomTmp > 0.0) {
1099 y = denomTmp;
1100 yp1 = y + 1.0;
1101 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1102 } else {
1103 sigma = 0.0;
1104 }
1105 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1106 m_IionicMolality * sqrtI * sigma;
1107 break;
1108
1109 case DHFORM_BETAIJ:
1110 denomTmp *= m_Aionic[0];
1111 for (size_t k = 1; k < m_kk; k++) {
1112 z_k = m_speciesCharge[k];
1113 m_d2lnActCoeffMolaldT2[k] = -z_k*z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1114 }
1115 if (denomTmp > 0.0) {
1116 y = denomTmp;
1117 yp1 = y + 1.0;
1118 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
1119 } else {
1120 sigma = 0.0;
1121 }
1122 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1123 m_IionicMolality * sqrtI * sigma;
1124 break;
1125
1126 case DHFORM_PITZER_BETAIJ:
1127 denomTmp *= m_Aionic[0];
1128 tmpLn = log(1.0 + denomTmp);
1129 for (size_t k = 1; k < m_kk; k++) {
1130 z_k = m_speciesCharge[k];
1132 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp)
1133 - 2.0 * z_k * z_k * d2AdT2 * tmpLn / (m_B_Debye * m_Aionic[0]);
1134 m_d2lnActCoeffMolaldT2[k] /= 3.0;
1135 }
1136
1137 sigma = 1.0 / (1.0 + denomTmp);
1138 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1139 m_IionicMolality * sqrtI * sigma;
1140 break;
1141
1142 default:
1143 throw CanteraError("DebyeHuckel::s_update_d2lnMolalityActCoeff_dT2",
1144 "ERROR");
1145 }
1146}
1147
1149{
1150 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1151 int est;
1152 double dAdP = dA_DebyedP_TP();
1153 if (dAdP == 0.0) {
1154 for (size_t k = 0; k < m_kk; k++) {
1155 m_dlnActCoeffMolaldP[k] = 0.0;
1156 }
1157 return;
1158 }
1159
1160 // Calculate a safe value for the mole fraction of the solvent
1161 double xmolSolvent = moleFraction(0);
1162 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1163 double sqrtI = sqrt(m_IionicMolality);
1164 double numdAdPTmp = dAdP * sqrtI;
1165 double denomTmp = m_B_Debye * sqrtI;
1166
1167 switch (m_formDH) {
1168 case DHFORM_DILUTE_LIMIT:
1169 for (size_t k = 0; k < m_kk; k++) {
1171 m_lnActCoeffMolal[k] * dAdP / m_A_Debye;
1172 }
1173 break;
1174
1175 case DHFORM_BDOT_AK:
1176 for (size_t k = 0; k < m_kk; k++) {
1177 est = m_electrolyteSpeciesType[k];
1178 if (est == cEST_nonpolarNeutral) {
1179 m_lnActCoeffMolal[k] = 0.0;
1180 } else {
1181 z_k = m_speciesCharge[k];
1183 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp * m_Aionic[k]);
1184 }
1185 }
1186
1187 m_dlnActCoeffMolaldP[0] = 0.0;
1188 coeff = 2.0 / 3.0 * dAdP * m_Mnaught * sqrtI;
1189 tmp = 0.0;
1190 if (denomTmp > 0.0) {
1191 for (size_t k = 0; k < m_kk; k++) {
1192 y = denomTmp * m_Aionic[k];
1193 yp1 = y + 1.0;
1194 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1195 z_k = m_speciesCharge[k];
1196 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1197 }
1198 }
1199 m_dlnActCoeffMolaldP[0] += coeff * tmp;
1200 break;
1201
1202 case DHFORM_BDOT_ACOMMON:
1203 denomTmp *= m_Aionic[0];
1204 for (size_t k = 0; k < m_kk; k++) {
1205 z_k = m_speciesCharge[k];
1207 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp);
1208 }
1209 if (denomTmp > 0.0) {
1210 y = denomTmp;
1211 yp1 = y + 1.0;
1212 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1213 } else {
1214 sigma = 0.0;
1215 }
1217 2.0 /3.0 * dAdP * m_Mnaught *
1218 m_IionicMolality * sqrtI * sigma;
1219 break;
1220
1221 case DHFORM_BETAIJ:
1222 denomTmp *= m_Aionic[0];
1223 for (size_t k = 1; k < m_kk; k++) {
1224 z_k = m_speciesCharge[k];
1225 m_dlnActCoeffMolaldP[k] = - z_k*z_k * numdAdPTmp / (1.0 + denomTmp);
1226 }
1227 if (denomTmp > 0.0) {
1228 y = denomTmp;
1229 yp1 = y + 1.0;
1230 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1231 } else {
1232 sigma = 0.0;
1233 }
1234 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1235 m_IionicMolality * sqrtI * sigma;
1236 break;
1237
1238 case DHFORM_PITZER_BETAIJ:
1239 denomTmp *= m_Aionic[0];
1240 tmpLn = log(1.0 + denomTmp);
1241 for (size_t k = 1; k < m_kk; k++) {
1242 z_k = m_speciesCharge[k];
1244 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp)
1245 - 2.0 * z_k * z_k * dAdP * tmpLn
1246 / (m_B_Debye * m_Aionic[0]);
1247 m_dlnActCoeffMolaldP[k] /= 3.0;
1248 }
1249
1250 sigma = 1.0 / (1.0 + denomTmp);
1251 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1252 m_IionicMolality * sqrtI * sigma;
1253 break;
1254
1255 default:
1256 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dP",
1257 "ERROR");
1258 }
1259}
1260
1261}
Headers for the DebyeHuckel ThermoPhase object, which models dilute electrolyte solutions (see Thermo...
Declarations for the class PDSS_ConstVol (pressure dependent standard state) which handles calculatio...
Implementation of a pressure dependent standard state virtual function for a Pure Water Phase (see Sp...
Declaration for class Cantera::Species.
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:432
size_t size() const
Returns the number of elements in this map.
Definition AnyMap.cpp:1728
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
double convert(const string &key, const string &units) const
Convert the item stored by the given key to the units specified in units.
Definition AnyMap.cpp:1595
size_t nRows() const
Number of rows.
Definition Array.h:176
size_t nColumns() const
Number of columns.
Definition Array.h:181
double & value(size_t i, size_t j)
Returns a changeable reference to position in the matrix.
Definition Array.h:160
virtual 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:47
Base class for exceptions thrown by Cantera classes.
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...
unique_ptr< WaterProps > m_waterProps
Pointer to the water property calculator.
int m_formDH
form of the Debye-Huckel parameterization used in the model.
DebyeHuckel(const string &inputFile="", const string &id="")
Full constructor for creating the phase.
double m_A_Debye
Current value of the Debye Constant, A_Debye.
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...
void getPartialMolarEnthalpies(double *hbar) const override
Returns an array of partial molar enthalpies for the species in the mixture.
void getChemPotentials(double *mu) const override
Get the species chemical potentials. Units: J/kmol.
vector< double > m_B_Dot
Array of B_Dot values.
double m_IionicMolality
Current value of the ionic strength on the molality scale.
double _osmoticCoeffHelgesonFixedForm() const
Formula for the osmotic coefficient that occurs in the GWB.
double m_densWaterSS
Storage for the density of water's standard state.
void s_update_d2lnMolalityActCoeff_dT2() const
Calculate the temperature 2nd derivative of the activity coefficient.
void getSpeciesParameters(const string &name, AnyMap &speciesNode) const override
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
int m_form_A_Debye
Form of the constant outside the Debye-Huckel term called A.
bool m_useHelgesonFixedForm
If true, then the fixed for of Helgeson's activity for water is used instead of the rigorous form obt...
static double _nonpolarActCoeff(double IionicMolality)
Static function that implements the non-polar species salt-out modifications.
vector< int > m_electrolyteSpeciesType
Vector containing the electrolyte species type.
double m_B_Debye
Current value of the constant that appears in the denominator.
void getParameters(AnyMap &phaseNode) const override
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
double AionicRadius(int k=0) const
Reports the ionic radius of the kth species.
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
void getActivityConcentrations(double *c) const override
This method returns an array of generalized concentrations.
void s_update_dlnMolalityActCoeff_dT() const
Calculation of temperature derivative of activity coefficient.
void s_update_lnMolalityActCoeff() const
Calculate the log activity coefficients.
vector< double > m_Aionic
a_k = Size of the ionic species in the DH formulation. units = meters
void getPartialMolarVolumes(double *vbar) const override
Return an array of partial molar volumes for the species in the mixture.
void setA_Debye(double A)
Set the A_Debye parameter.
void calcDensity() override
Calculate the density of the mixture using the partial molar volumes and mole fractions as input.
vector< double > m_dlnActCoeffMolaldT
Derivative of log act coeff wrt T.
double m_Aionic_default
Default ionic radius for species where it is not specified.
void setDebyeHuckelModel(const string &form)
Set the DebyeHuckel parameterization form.
vector< double > m_speciesCharge_Stoich
Stoichiometric species charge -> This is for calculations of the ionic strength which ignore ion-ion ...
double m_maxIionicStrength
Maximum value of the ionic strength allowed in the calculation of the activity coefficients.
double _lnactivityWaterHelgesonFixedForm() const
Formula for the log of the water activity that occurs in the GWB.
void setBeta(const string &sp1, const string &sp2, double value)
Set the value for the beta interaction between species sp1 and sp2.
void getActivities(double *ac) const override
Get the array of non-dimensional activities at the current solution temperature, pressure,...
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.
void getPartialMolarCp(double *cpbar) const override
Return an array of partial molar heat capacities for the species in the mixture.
void setDefaultIonicRadius(double value)
Set the default ionic radius [m] for each species.
vector< double > m_d2lnActCoeffMolaldT2
2nd Derivative of log act coeff wrt T
double standardConcentration(size_t k=0) const override
Return the standard concentration for the kth species.
void s_update_dlnMolalityActCoeff_dP() const
Calculate the pressure derivative of the activity coefficient.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
PDSS_Water * m_waterSS
Pointer to the Water standard state object.
double m_IionicMolalityStoich
Stoichiometric ionic strength on the molality scale.
vector< double > m_lnActCoeffMolal
Logarithm of the activity coefficients on the molality scale.
vector< double > m_dlnActCoeffMolaldP
Derivative of log act coeff wrt P.
void getMolalityActivityCoefficients(double *acMolality) const override
Get the array of non-dimensional molality-based activity coefficients at the current solution tempera...
void getPartialMolarEntropies(double *sbar) const override
Returns an array of partial molar entropies of the species in the solution.
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))
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...
double m_Mnaught
This is the multiplication factor that goes inside log expressions involving the molalities of specie...
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
vector< double > m_molalities
Current value of the molalities of the species in the phase.
void calcMolalities() const
Calculates the molality of all species and stores the result internally.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
Class for pressure dependent standard states that use a constant volume model.
Class for the liquid water pressure dependent standard state.
Definition PDSS_Water.h:50
double density() const override
Return the standard state density at standard state.
virtual double molarVolume() const
Return the molar volume at standard state.
Definition PDSS.cpp:63
void checkSpeciesIndex(size_t k) const
Check that the specified species index is in range.
Definition Phase.cpp:153
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:232
size_t m_kk
Number of species in the phase.
Definition Phase.h:855
double temperature() const
Temperature (K).
Definition Phase.h:563
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:142
size_t speciesIndex(const string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:129
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition Phase.cpp:439
shared_ptr< Species > species(const string &name) const
Return the Species object for the named species.
Definition Phase.cpp:874
double 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:539
vector< double > m_speciesCharge
Vector of species charges. length m_kk.
Definition Phase.h:866
string name() const
Return the name of the phase.
Definition Phase.cpp:20
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
double RT() const
Return the Gas Constant multiplied by the current temperature.
void initThermoFile(const string &inputFile, const string &id)
Initialize a ThermoPhase object using an input file.
virtual void getSpeciesParameters(const string &name, AnyMap &speciesNode) const
Get phase-specific parameters of a Species object such that an identical one could be reconstructed a...
AnyMap m_input
Data supplied via setParameters.
double pressure() const override
Returns the current pressure of the phase.
void getEntropy_R(double *sr) const override
Get the array of nondimensional Entropy functions for the standard state species at the current T and...
virtual void _updateStandardStateThermo() const
Updates the standard state thermodynamic functions at the current T and P of the solution.
void getStandardChemPotentials(double *mu) const override
Get the array of chemical potentials at unit activity for the species at their standard states at the...
void getCp_R(double *cpr) const override
Get the nondimensional Heat Capacities at constant pressure for the species standard states at the cu...
void getEnthalpy_RT(double *hrt) const override
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
void getStandardVolumes(double *vol) const override
Get the molar volumes of the species standard states at the current T and P of the solution.
virtual void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input.
Header file for a common definitions used in electrolytes thermodynamics.
bool caseInsensitiveEquals(const string &input, const string &test)
Case insensitive equality predicate.
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:120
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180
static int interp_est(const string &estString)
Utility function to assign an integer value from a string for the ElectrolyteSpeciesType field.
const double SmallNumber
smallest number to compare to zero.
Definition ct_defs.h:158
const int cEST_solvent
Electrolyte species type.
Contains declarations for string manipulation functions within Cantera.