Cantera  3.2.0a5
Loading...
Searching...
No Matches
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, true);
317 size_t k2 = speciesIndex(sp2, true);
318 m_Beta_ij(k1, k2) = value;
319 m_Beta_ij(k2, k1) = value;
320}
321
323{
325 if (m_input.hasKey("activity-data")) {
326 auto& node = m_input["activity-data"].as<AnyMap>();
327 setDebyeHuckelModel(node["model"].asString());
328 if (node.hasKey("A_Debye")) {
329 if (node["A_Debye"] == "variable") {
330 setA_Debye(-1);
331 } else {
332 setA_Debye(node.convert("A_Debye", "kg^0.5/gmol^0.5"));
333 }
334 }
335 if (node.hasKey("B_Debye")) {
336 setB_Debye(node.convert("B_Debye", "kg^0.5/gmol^0.5/m"));
337 }
338 if (node.hasKey("max-ionic-strength")) {
339 setMaxIonicStrength(node["max-ionic-strength"].asDouble());
340 }
341 if (node.hasKey("use-Helgeson-fixed-form")) {
342 useHelgesonFixedForm(node["use-Helgeson-fixed-form"].asBool());
343 }
344 if (node.hasKey("default-ionic-radius")) {
345 setDefaultIonicRadius(node.convert("default-ionic-radius", "m"));
346 }
347 if (node.hasKey("B-dot")) {
348 setB_dot(node["B-dot"].asDouble());
349 }
350 if (node.hasKey("beta")) {
351 for (auto& item : node["beta"].asVector<AnyMap>()) {
352 auto& species = item["species"].asVector<string>(2);
353 setBeta(species[0], species[1], item["beta"].asDouble());
354 }
355 }
356 }
357
358 // Solvent
359 m_waterSS = dynamic_cast<PDSS_Water*>(providePDSS(0));
360 if (m_waterSS) {
361 // Initialize the water property calculator. It will share the internal
362 // eos water calculator.
363 if (m_form_A_Debye == A_DEBYE_WATER) {
364 m_waterProps = make_unique<WaterProps>(m_waterSS);
365 }
366 } else if (dynamic_cast<PDSS_ConstVol*>(providePDSS(0)) == 0) {
367 throw CanteraError("DebyeHuckel::initThermo", "Solvent standard state"
368 " model must be WaterIAPWS or constant_incompressible.");
369 }
370
371 // Solutes
372 for (size_t k = 1; k < nSpecies(); k++) {
373 if (dynamic_cast<PDSS_ConstVol*>(providePDSS(k)) == 0) {
374 throw CanteraError("DebyeHuckel::initThermo", "Solute standard"
375 " state model must be constant_incompressible.");
376 }
377 }
378}
379
380void DebyeHuckel::getParameters(AnyMap& phaseNode) const
381{
383 AnyMap activityNode;
384
385 switch (m_formDH) {
386 case DHFORM_DILUTE_LIMIT:
387 activityNode["model"] = "dilute-limit";
388 break;
389 case DHFORM_BDOT_AK:
390 activityNode["model"] = "B-dot-with-variable-a";
391 break;
392 case DHFORM_BDOT_ACOMMON:
393 activityNode["model"] = "B-dot-with-common-a";
394 break;
395 case DHFORM_BETAIJ:
396 activityNode["model"] = "beta_ij";
397 break;
398 case DHFORM_PITZER_BETAIJ:
399 activityNode["model"] = "Pitzer-with-beta_ij";
400 break;
401 }
402
403 if (m_form_A_Debye == A_DEBYE_WATER) {
404 activityNode["A_Debye"] = "variable";
405 } else if (m_A_Debye != A_Debye_default) {
406 activityNode["A_Debye"].setQuantity(m_A_Debye, "kg^0.5/gmol^0.5");
407 }
408
409 if (m_B_Debye != B_Debye_default) {
410 activityNode["B_Debye"].setQuantity(m_B_Debye, "kg^0.5/gmol^0.5/m");
411 }
412 if (m_maxIionicStrength != maxIionicStrength_default) {
413 activityNode["max-ionic-strength"] = m_maxIionicStrength;
414 }
416 activityNode["use-Helgeson-fixed-form"] = true;
417 }
418 if (!isnan(m_Aionic_default)) {
419 activityNode["default-ionic-radius"].setQuantity(m_Aionic_default, "m");
420 }
421 for (double B_dot : m_B_Dot) {
422 if (B_dot != 0.0) {
423 activityNode["B-dot"] = B_dot;
424 break;
425 }
426 }
427 if (m_Beta_ij.nRows() && m_Beta_ij.nColumns()) {
428 vector<AnyMap> beta;
429 for (size_t i = 0; i < m_kk; i++) {
430 for (size_t j = i; j < m_kk; j++) {
431 if (m_Beta_ij(i, j) != 0) {
432 AnyMap entry;
433 entry["species"] = vector<string>{
434 speciesName(i), speciesName(j)};
435 entry["beta"] = m_Beta_ij(i, j);
436 beta.push_back(std::move(entry));
437 }
438 }
439 }
440 activityNode["beta"] = std::move(beta);
441 }
442 phaseNode["activity-data"] = std::move(activityNode);
443}
444
445void DebyeHuckel::getSpeciesParameters(const string& name, AnyMap& speciesNode) const
446{
448 size_t k = speciesIndex(name, true);
449 AnyMap dhNode;
450 if (m_Aionic[k] != m_Aionic_default) {
451 dhNode["ionic-radius"].setQuantity(m_Aionic[k], "m");
452 }
453
454 int estDefault = cEST_nonpolarNeutral;
455 if (k == 0) {
456 estDefault = cEST_solvent;
457 }
458
459 if (m_speciesCharge_Stoich[k] != charge(k)) {
460 dhNode["weak-acid-charge"] = m_speciesCharge_Stoich[k];
461 estDefault = cEST_weakAcidAssociated;
462 } else if (fabs(charge(k)) > 0.0001) {
463 estDefault = cEST_chargedSpecies;
464 }
465
466 if (m_electrolyteSpeciesType[k] != estDefault) {
467 string estType;
468 switch (m_electrolyteSpeciesType[k]) {
469 case cEST_solvent:
470 estType = "solvent";
471 break;
472 case cEST_chargedSpecies:
473 estType = "charged-species";
474 break;
475 case cEST_weakAcidAssociated:
476 estType = "weak-acid-associated";
477 break;
478 case cEST_strongAcidAssociated:
479 estType = "strong-acid-associated";
480 break;
481 case cEST_polarNeutral:
482 estType = "polar-neutral";
483 break;
484 case cEST_nonpolarNeutral:
485 estType = "nonpolar-neutral";
486 break;
487 default:
488 throw CanteraError("DebyeHuckel::getSpeciesParameters",
489 "Unknown electrolyte species type ({}) for species '{}'",
491 }
492 dhNode["electrolyte-species-type"] = estType;
493 }
494
495 if (dhNode.size()) {
496 speciesNode["Debye-Huckel"] = std::move(dhNode);
497 }
498}
499
500
501double DebyeHuckel::A_Debye_TP(double tempArg, double presArg) const
502{
503 double T = temperature();
504 double A;
505 if (tempArg != -1.0) {
506 T = tempArg;
507 }
508 double P = pressure();
509 if (presArg != -1.0) {
510 P = presArg;
511 }
512
513 switch (m_form_A_Debye) {
514 case A_DEBYE_CONST:
515 A = m_A_Debye;
516 break;
517 case A_DEBYE_WATER:
518 A = m_waterProps->ADebye(T, P, 0);
519 m_A_Debye = A;
520 break;
521 default:
522 throw CanteraError("DebyeHuckel::A_Debye_TP", "shouldn't be here");
523 }
524 return A;
525}
526
527double DebyeHuckel::dA_DebyedT_TP(double tempArg, double presArg) const
528{
529 double T = temperature();
530 if (tempArg != -1.0) {
531 T = tempArg;
532 }
533 double P = pressure();
534 if (presArg != -1.0) {
535 P = presArg;
536 }
537 double dAdT;
538 switch (m_form_A_Debye) {
539 case A_DEBYE_CONST:
540 dAdT = 0.0;
541 break;
542 case A_DEBYE_WATER:
543 dAdT = m_waterProps->ADebye(T, P, 1);
544 break;
545 default:
546 throw CanteraError("DebyeHuckel::dA_DebyedT_TP", "shouldn't be here");
547 }
548 return dAdT;
549}
550
551double DebyeHuckel::d2A_DebyedT2_TP(double tempArg, double presArg) const
552{
553 double T = temperature();
554 if (tempArg != -1.0) {
555 T = tempArg;
556 }
557 double P = pressure();
558 if (presArg != -1.0) {
559 P = presArg;
560 }
561 double d2AdT2;
562 switch (m_form_A_Debye) {
563 case A_DEBYE_CONST:
564 d2AdT2 = 0.0;
565 break;
566 case A_DEBYE_WATER:
567 d2AdT2 = m_waterProps->ADebye(T, P, 2);
568 break;
569 default:
570 throw CanteraError("DebyeHuckel::d2A_DebyedT2_TP", "shouldn't be here");
571 }
572 return d2AdT2;
573}
574
575double DebyeHuckel::dA_DebyedP_TP(double tempArg, double presArg) const
576{
577 double T = temperature();
578 if (tempArg != -1.0) {
579 T = tempArg;
580 }
581 double P = pressure();
582 if (presArg != -1.0) {
583 P = presArg;
584 }
585 double dAdP;
586 switch (m_form_A_Debye) {
587 case A_DEBYE_CONST:
588 dAdP = 0.0;
589 break;
590 case A_DEBYE_WATER:
591 dAdP = m_waterProps->ADebye(T, P, 3);
592 break;
593 default:
594 throw CanteraError("DebyeHuckel::dA_DebyedP_TP", "shouldn't be here");
595 }
596 return dAdP;
597}
598
599// ---------- Other Property Functions
600
601double DebyeHuckel::AionicRadius(int k) const
602{
603 return m_Aionic[k];
604}
605
606// ------------ Private and Restricted Functions ------------------
607
608bool DebyeHuckel::addSpecies(shared_ptr<Species> spec)
609{
610 bool added = MolalityVPSSTP::addSpecies(spec);
611 if (added) {
612 m_lnActCoeffMolal.push_back(0.0);
613 m_dlnActCoeffMolaldT.push_back(0.0);
614 m_d2lnActCoeffMolaldT2.push_back(0.0);
615 m_dlnActCoeffMolaldP.push_back(0.0);
616 m_B_Dot.push_back(0.0);
617
618 // NAN will be replaced with default value
619 double Aionic = NAN;
620
621 // Guess electrolyte species type based on charge properties
622 int est = cEST_nonpolarNeutral;
623 double stoichCharge = spec->charge;
624 if (fabs(spec->charge) > 0.0001) {
625 est = cEST_chargedSpecies;
626 }
627
628 if (spec->input.hasKey("Debye-Huckel")) {
629 auto& dhNode = spec->input["Debye-Huckel"].as<AnyMap>();
630 Aionic = dhNode.convert("ionic-radius", "m", NAN);
631 if (dhNode.hasKey("weak-acid-charge")) {
632 stoichCharge = dhNode["weak-acid-charge"].asDouble();
633 if (fabs(stoichCharge - spec->charge) > 0.0001) {
634 est = cEST_weakAcidAssociated;
635 }
636 }
637 // Apply override of the electrolyte species type
638 if (dhNode.hasKey("electrolyte-species-type")) {
639 est = interp_est(dhNode["electrolyte-species-type"].asString());
640 }
641 }
642
643 if (m_electrolyteSpeciesType.size() == 0) {
644 est = cEST_solvent; // species 0 is the solvent
645 }
646
647 m_Aionic.push_back(Aionic);
648 m_speciesCharge_Stoich.push_back(stoichCharge);
649 m_electrolyteSpeciesType.push_back(est);
650 }
651 return added;
652}
653
654double DebyeHuckel::_nonpolarActCoeff(double IionicMolality)
655{
656 // These are coefficients to describe the increase in activity coeff for
657 // non-polar molecules due to the electrolyte becoming stronger (the so-
658 // called salt-out effect)
659 const static double npActCoeff[] = {0.1127, -0.01049, 1.545E-3};
660 double I2 = IionicMolality * IionicMolality;
661 double l10actCoeff =
662 npActCoeff[0] * IionicMolality +
663 npActCoeff[1] * I2 +
664 npActCoeff[2] * I2 * IionicMolality;
665 return pow(10.0 , l10actCoeff);
666}
667
669{
670 const double a0 = 1.454;
671 const double b0 = 0.02236;
672 const double c0 = 9.380E-3;
673 const double d0 = -5.362E-4;
674 double Is = m_IionicMolalityStoich;
675 if (Is <= 0.0) {
676 return 0.0;
677 }
678 double Is2 = Is * Is;
679 double bhat = 1.0 + a0 * sqrt(Is);
680 double func = bhat - 2.0 * log(bhat) - 1.0/bhat;
681 double v1 = m_A_Debye / (a0 * a0 * a0 * Is) * func;
682 double oc = 1.0 - v1 + b0 * Is / 2.0 + 2.0 * c0 * Is2 / 3.0
683 + 3.0 * d0 * Is2 * Is / 4.0;
684 return oc;
685}
686
688{
689 // Update the internally stored vector of molalities
691 double oc = _osmoticCoeffHelgesonFixedForm();
692 double sum = 0.0;
693 for (size_t k = 1; k < m_kk; k++) {
694 sum += std::max(m_molalities[k], 0.0);
695 }
696 if (sum > 2.0 * m_maxIionicStrength) {
697 sum = 2.0 * m_maxIionicStrength;
698 };
699 return - m_Mnaught * sum * oc;
700}
701
703{
704 double z_k, zs_k1, zs_k2;
705
706 // Update the internally stored vector of molalities
708
709 // Calculate the apparent (real) ionic strength.
710 //
711 // Note this is not the stoichiometric ionic strengh, where reactions of
712 // ions forming neutral salts are ignorred in calculating the ionic
713 // strength.
714 m_IionicMolality = 0.0;
715 for (size_t k = 0; k < m_kk; k++) {
716 z_k = m_speciesCharge[k];
717 m_IionicMolality += m_molalities[k] * z_k * z_k;
718 }
719 m_IionicMolality /= 2.0;
721
722 // Calculate the stoichiometric ionic charge
724 for (size_t k = 0; k < m_kk; k++) {
725 z_k = m_speciesCharge[k];
726 zs_k1 = m_speciesCharge_Stoich[k];
727 if (z_k == zs_k1) {
728 m_IionicMolalityStoich += m_molalities[k] * z_k * z_k;
729 } else {
730 zs_k2 = z_k - zs_k1;
731 m_IionicMolalityStoich += m_molalities[k] * (zs_k1 * zs_k1 + zs_k2 * zs_k2);
732 }
733 }
736
737 // Possibly update the stored value of the Debye-Huckel parameter A_Debye
738 // This parameter appears on the top of the activity coefficient expression.
739 // It depends on T (and P), as it depends explicitly on the temperature.
740 // Also, the dielectric constant is usually a fairly strong function of T,
741 // also.
743
744 // Calculate a safe value for the mole fraction of the solvent
745 double xmolSolvent = moleFraction(0);
746 xmolSolvent = std::max(8.689E-3, xmolSolvent);
747
748 int est;
749 double ac_nonPolar = 1.0;
750 double numTmp = m_A_Debye * sqrt(m_IionicMolality);
751 double denomTmp = m_B_Debye * sqrt(m_IionicMolality);
752 double coeff;
753 double lnActivitySolvent = 0.0;
754 double tmp;
755 double tmpLn;
756 double y, yp1, sigma;
757 switch (m_formDH) {
758 case DHFORM_DILUTE_LIMIT:
759 for (size_t k = 0; k < m_kk; k++) {
760 z_k = m_speciesCharge[k];
761 m_lnActCoeffMolal[k] = - z_k * z_k * numTmp;
762 }
763 lnActivitySolvent =
764 (xmolSolvent - 1.0)/xmolSolvent +
765 2.0 / 3.0 * m_A_Debye * m_Mnaught *
767 break;
768
769 case DHFORM_BDOT_AK:
770 ac_nonPolar = _nonpolarActCoeff(m_IionicMolality);
771 for (size_t k = 0; k < m_kk; k++) {
773 if (est == cEST_nonpolarNeutral) {
774 m_lnActCoeffMolal[k] = log(ac_nonPolar);
775 } else {
776 z_k = m_speciesCharge[k];
778 - z_k * z_k * numTmp / (1.0 + denomTmp * m_Aionic[k])
779 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
780 }
781 }
782
783 lnActivitySolvent = (xmolSolvent - 1.0)/xmolSolvent;
784 coeff = 2.0 / 3.0 * m_A_Debye * m_Mnaught
785 * sqrt(m_IionicMolality);
786 tmp = 0.0;
787 if (denomTmp > 0.0) {
788 for (size_t k = 0; k < m_kk; k++) {
789 if (k != 0 || m_Aionic[k] != 0.0) {
790 y = denomTmp * m_Aionic[k];
791 yp1 = y + 1.0;
792 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
793 z_k = m_speciesCharge[k];
794 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
795 }
796 }
797 }
798 lnActivitySolvent += coeff * tmp;
799 tmp = 0.0;
800 for (size_t k = 1; k < m_kk; k++) {
801 z_k = m_speciesCharge[k];
802 if (z_k != 0.0) {
803 tmp += m_B_Dot[k] * m_molalities[k];
804 }
805 }
806 lnActivitySolvent -=
807 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
808
809 // Special section to implement the Helgeson fixed form for the water
810 // brine activity coefficient.
812 lnActivitySolvent = _lnactivityWaterHelgesonFixedForm();
813 }
814 break;
815
816 case DHFORM_BDOT_ACOMMON:
817 denomTmp *= m_Aionic[0];
818 for (size_t k = 0; k < m_kk; k++) {
819 z_k = m_speciesCharge[k];
821 - z_k * z_k * numTmp / (1.0 + denomTmp)
822 + log(10.0) * m_B_Dot[k] * m_IionicMolality;
823 }
824 if (denomTmp > 0.0) {
825 y = denomTmp;
826 yp1 = y + 1.0;
827 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
828 } else {
829 sigma = 0.0;
830 }
831 lnActivitySolvent =
832 (xmolSolvent - 1.0)/xmolSolvent +
833 2.0 /3.0 * m_A_Debye * m_Mnaught *
834 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
835 tmp = 0.0;
836 for (size_t k = 1; k < m_kk; k++) {
837 z_k = m_speciesCharge[k];
838 if (z_k != 0.0) {
839 tmp += m_B_Dot[k] * m_molalities[k];
840 }
841 }
842 lnActivitySolvent -=
843 m_Mnaught * log(10.0) * m_IionicMolality * tmp / 2.0;
844 break;
845
846 case DHFORM_BETAIJ:
847 denomTmp = m_B_Debye * m_Aionic[0];
848 denomTmp *= sqrt(m_IionicMolality);
849 lnActivitySolvent =
850 (xmolSolvent - 1.0)/xmolSolvent;
851
852 for (size_t k = 1; k < m_kk; k++) {
853 z_k = m_speciesCharge[k];
855 - z_k * z_k * numTmp / (1.0 + denomTmp);
856 for (size_t j = 0; j < m_kk; j++) {
857 double beta = m_Beta_ij.value(k, j);
858 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] * beta;
859 }
860 }
861 if (denomTmp > 0.0) {
862 y = denomTmp;
863 yp1 = y + 1.0;
864 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
865 } else {
866 sigma = 0.0;
867 }
868 lnActivitySolvent =
869 (xmolSolvent - 1.0)/xmolSolvent +
870 2.0 /3.0 * m_A_Debye * m_Mnaught *
871 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
872 tmp = 0.0;
873 for (size_t k = 0; k < m_kk; k++) {
874 for (size_t j = 0; j < m_kk; j++) {
875 tmp +=
877 }
878 }
879 lnActivitySolvent -= m_Mnaught * tmp;
880 break;
881
882 case DHFORM_PITZER_BETAIJ:
883 denomTmp = m_B_Debye * sqrt(m_IionicMolality);
884 denomTmp *= m_Aionic[0];
885 numTmp = m_A_Debye * sqrt(m_IionicMolality);
886 tmpLn = log(1.0 + denomTmp);
887 for (size_t k = 1; k < m_kk; k++) {
888 z_k = m_speciesCharge[k];
890 - z_k * z_k * numTmp / 3.0 / (1.0 + denomTmp);
892 - 2.0 * z_k * z_k * m_A_Debye * tmpLn /
893 (3.0 * m_B_Debye * m_Aionic[0]);
894 for (size_t j = 0; j < m_kk; j++) {
895 m_lnActCoeffMolal[k] += 2.0 * m_molalities[j] *
896 m_Beta_ij.value(k, j);
897 }
898 }
899 sigma = 1.0 / (1.0 + denomTmp);
900 lnActivitySolvent =
901 (xmolSolvent - 1.0)/xmolSolvent +
902 2.0 /3.0 * m_A_Debye * m_Mnaught *
903 m_IionicMolality * sqrt(m_IionicMolality) * sigma;
904 tmp = 0.0;
905 for (size_t k = 0; k < m_kk; k++) {
906 for (size_t j = 0; j < m_kk; j++) {
907 tmp +=
909 }
910 }
911 lnActivitySolvent -= m_Mnaught * tmp;
912 break;
913
914 default:
915 throw CanteraError("DebyeHuckel::s_update_lnMolalityActCoeff", "ERROR");
916 }
917
918 // Above, we calculated the ln(activitySolvent). Translate that into the
919 // molar-based activity coefficient by dividing by the solvent mole
920 // fraction. Solvents are not on the molality scale.
921 xmolSolvent = moleFraction(0);
922 m_lnActCoeffMolal[0] = lnActivitySolvent - log(xmolSolvent);
923}
924
926{
927 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
928 // First we store dAdT explicitly here
929 double dAdT = dA_DebyedT_TP();
930 if (dAdT == 0.0) {
931 for (size_t k = 0; k < m_kk; k++) {
932 m_dlnActCoeffMolaldT[k] = 0.0;
933 }
934 return;
935 }
936
937 // Calculate a safe value for the mole fraction of the solvent
938 double xmolSolvent = moleFraction(0);
939 xmolSolvent = std::max(8.689E-3, xmolSolvent);
940 double sqrtI = sqrt(m_IionicMolality);
941 double numdAdTTmp = dAdT * sqrtI;
942 double denomTmp = m_B_Debye * sqrtI;
943 double d_lnActivitySolvent_dT = 0;
944
945 switch (m_formDH) {
946 case DHFORM_DILUTE_LIMIT:
947 for (size_t k = 1; k < m_kk; k++) {
949 m_lnActCoeffMolal[k] * dAdT / m_A_Debye;
950 }
951 d_lnActivitySolvent_dT = 2.0 / 3.0 * dAdT * m_Mnaught *
953 m_dlnActCoeffMolaldT[0] = d_lnActivitySolvent_dT;
954 break;
955
956 case DHFORM_BDOT_AK:
957 for (size_t k = 0; k < m_kk; k++) {
958 z_k = m_speciesCharge[k];
960 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp * m_Aionic[k]);
961 }
962
963 m_dlnActCoeffMolaldT[0] = 0.0;
964 coeff = 2.0 / 3.0 * dAdT * m_Mnaught * sqrtI;
965 tmp = 0.0;
966 if (denomTmp > 0.0) {
967 for (size_t k = 0; k < m_kk; k++) {
968 y = denomTmp * m_Aionic[k];
969 yp1 = y + 1.0;
970 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
971 z_k = m_speciesCharge[k];
972 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
973 }
974 }
975 m_dlnActCoeffMolaldT[0] += coeff * tmp;
976 break;
977
978 case DHFORM_BDOT_ACOMMON:
979 denomTmp *= m_Aionic[0];
980 for (size_t k = 0; k < m_kk; k++) {
981 z_k = m_speciesCharge[k];
983 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp);
984 }
985 if (denomTmp > 0.0) {
986 y = denomTmp;
987 yp1 = y + 1.0;
988 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
989 } else {
990 sigma = 0.0;
991 }
992 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
993 m_IionicMolality * sqrtI * sigma;
994 break;
995
996 case DHFORM_BETAIJ:
997 denomTmp *= m_Aionic[0];
998 for (size_t k = 1; k < m_kk; k++) {
999 z_k = m_speciesCharge[k];
1000 m_dlnActCoeffMolaldT[k] = -z_k*z_k * numdAdTTmp / (1.0 + denomTmp);
1001 }
1002 if (denomTmp > 0.0) {
1003 y = denomTmp;
1004 yp1 = y + 1.0;
1005 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1006 } else {
1007 sigma = 0.0;
1008 }
1009 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1010 m_IionicMolality * sqrtI * sigma;
1011 break;
1012
1013 case DHFORM_PITZER_BETAIJ:
1014 denomTmp *= m_Aionic[0];
1015 tmpLn = log(1.0 + denomTmp);
1016 for (size_t k = 1; k < m_kk; k++) {
1017 z_k = m_speciesCharge[k];
1019 - z_k * z_k * numdAdTTmp / (1.0 + denomTmp)
1020 - 2.0 * z_k * z_k * dAdT * tmpLn / (m_B_Debye * m_Aionic[0]);
1021 m_dlnActCoeffMolaldT[k] /= 3.0;
1022 }
1023
1024 sigma = 1.0 / (1.0 + denomTmp);
1025 m_dlnActCoeffMolaldT[0] = 2.0 /3.0 * dAdT * m_Mnaught *
1026 m_IionicMolality * sqrtI * sigma;
1027 break;
1028
1029 default:
1030 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dT",
1031 "ERROR");
1032 }
1033}
1034
1036{
1037 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1038 double dAdT = dA_DebyedT_TP();
1039 double d2AdT2 = d2A_DebyedT2_TP();
1040 if (d2AdT2 == 0.0 && dAdT == 0.0) {
1041 for (size_t k = 0; k < m_kk; k++) {
1042 m_d2lnActCoeffMolaldT2[k] = 0.0;
1043 }
1044 return;
1045 }
1046
1047 // Calculate a safe value for the mole fraction of the solvent
1048 double xmolSolvent = moleFraction(0);
1049 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1050 double sqrtI = sqrt(m_IionicMolality);
1051 double numd2AdT2Tmp = d2AdT2 * sqrtI;
1052 double denomTmp = m_B_Debye * sqrtI;
1053
1054 switch (m_formDH) {
1055 case DHFORM_DILUTE_LIMIT:
1056 for (size_t k = 0; k < m_kk; k++) {
1058 m_lnActCoeffMolal[k] * d2AdT2 / m_A_Debye;
1059 }
1060 break;
1061
1062 case DHFORM_BDOT_AK:
1063 for (size_t k = 0; k < m_kk; k++) {
1064 z_k = m_speciesCharge[k];
1066 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp * m_Aionic[k]);
1067 }
1068
1069 m_d2lnActCoeffMolaldT2[0] = 0.0;
1070 coeff = 2.0 / 3.0 * d2AdT2 * m_Mnaught * sqrtI;
1071 tmp = 0.0;
1072 if (denomTmp > 0.0) {
1073 for (size_t k = 0; k < m_kk; k++) {
1074 y = denomTmp * m_Aionic[k];
1075 yp1 = y + 1.0;
1076 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1077 z_k = m_speciesCharge[k];
1078 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1079 }
1080 }
1081 m_d2lnActCoeffMolaldT2[0] += coeff * tmp;
1082 break;
1083
1084 case DHFORM_BDOT_ACOMMON:
1085 denomTmp *= m_Aionic[0];
1086 for (size_t k = 0; k < m_kk; k++) {
1087 z_k = m_speciesCharge[k];
1089 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1090 }
1091 if (denomTmp > 0.0) {
1092 y = denomTmp;
1093 yp1 = y + 1.0;
1094 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1095 } else {
1096 sigma = 0.0;
1097 }
1098 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1099 m_IionicMolality * sqrtI * sigma;
1100 break;
1101
1102 case DHFORM_BETAIJ:
1103 denomTmp *= m_Aionic[0];
1104 for (size_t k = 1; k < m_kk; k++) {
1105 z_k = m_speciesCharge[k];
1106 m_d2lnActCoeffMolaldT2[k] = -z_k*z_k * numd2AdT2Tmp / (1.0 + denomTmp);
1107 }
1108 if (denomTmp > 0.0) {
1109 y = denomTmp;
1110 yp1 = y + 1.0;
1111 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 -2.0*log(yp1));
1112 } else {
1113 sigma = 0.0;
1114 }
1115 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1116 m_IionicMolality * sqrtI * sigma;
1117 break;
1118
1119 case DHFORM_PITZER_BETAIJ:
1120 denomTmp *= m_Aionic[0];
1121 tmpLn = log(1.0 + denomTmp);
1122 for (size_t k = 1; k < m_kk; k++) {
1123 z_k = m_speciesCharge[k];
1125 - z_k * z_k * numd2AdT2Tmp / (1.0 + denomTmp)
1126 - 2.0 * z_k * z_k * d2AdT2 * tmpLn / (m_B_Debye * m_Aionic[0]);
1127 m_d2lnActCoeffMolaldT2[k] /= 3.0;
1128 }
1129
1130 sigma = 1.0 / (1.0 + denomTmp);
1131 m_d2lnActCoeffMolaldT2[0] = 2.0 /3.0 * d2AdT2 * m_Mnaught *
1132 m_IionicMolality * sqrtI * sigma;
1133 break;
1134
1135 default:
1136 throw CanteraError("DebyeHuckel::s_update_d2lnMolalityActCoeff_dT2",
1137 "ERROR");
1138 }
1139}
1140
1142{
1143 double z_k, coeff, tmp, y, yp1, sigma, tmpLn;
1144 int est;
1145 double dAdP = dA_DebyedP_TP();
1146 if (dAdP == 0.0) {
1147 for (size_t k = 0; k < m_kk; k++) {
1148 m_dlnActCoeffMolaldP[k] = 0.0;
1149 }
1150 return;
1151 }
1152
1153 // Calculate a safe value for the mole fraction of the solvent
1154 double xmolSolvent = moleFraction(0);
1155 xmolSolvent = std::max(8.689E-3, xmolSolvent);
1156 double sqrtI = sqrt(m_IionicMolality);
1157 double numdAdPTmp = dAdP * sqrtI;
1158 double denomTmp = m_B_Debye * sqrtI;
1159
1160 switch (m_formDH) {
1161 case DHFORM_DILUTE_LIMIT:
1162 for (size_t k = 0; k < m_kk; k++) {
1164 m_lnActCoeffMolal[k] * dAdP / m_A_Debye;
1165 }
1166 break;
1167
1168 case DHFORM_BDOT_AK:
1169 for (size_t k = 0; k < m_kk; k++) {
1170 est = m_electrolyteSpeciesType[k];
1171 if (est == cEST_nonpolarNeutral) {
1172 m_lnActCoeffMolal[k] = 0.0;
1173 } else {
1174 z_k = m_speciesCharge[k];
1176 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp * m_Aionic[k]);
1177 }
1178 }
1179
1180 m_dlnActCoeffMolaldP[0] = 0.0;
1181 coeff = 2.0 / 3.0 * dAdP * m_Mnaught * sqrtI;
1182 tmp = 0.0;
1183 if (denomTmp > 0.0) {
1184 for (size_t k = 0; k < m_kk; k++) {
1185 y = denomTmp * m_Aionic[k];
1186 yp1 = y + 1.0;
1187 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1188 z_k = m_speciesCharge[k];
1189 tmp += m_molalities[k] * z_k * z_k * sigma / 2.0;
1190 }
1191 }
1192 m_dlnActCoeffMolaldP[0] += coeff * tmp;
1193 break;
1194
1195 case DHFORM_BDOT_ACOMMON:
1196 denomTmp *= m_Aionic[0];
1197 for (size_t k = 0; k < m_kk; k++) {
1198 z_k = m_speciesCharge[k];
1200 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp);
1201 }
1202 if (denomTmp > 0.0) {
1203 y = denomTmp;
1204 yp1 = y + 1.0;
1205 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1206 } else {
1207 sigma = 0.0;
1208 }
1210 2.0 /3.0 * dAdP * m_Mnaught *
1211 m_IionicMolality * sqrtI * sigma;
1212 break;
1213
1214 case DHFORM_BETAIJ:
1215 denomTmp *= m_Aionic[0];
1216 for (size_t k = 1; k < m_kk; k++) {
1217 z_k = m_speciesCharge[k];
1218 m_dlnActCoeffMolaldP[k] = - z_k*z_k * numdAdPTmp / (1.0 + denomTmp);
1219 }
1220 if (denomTmp > 0.0) {
1221 y = denomTmp;
1222 yp1 = y + 1.0;
1223 sigma = 3.0 / (y * y * y) * (yp1 - 1.0/yp1 - 2.0*log(yp1));
1224 } else {
1225 sigma = 0.0;
1226 }
1227 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1228 m_IionicMolality * sqrtI * sigma;
1229 break;
1230
1231 case DHFORM_PITZER_BETAIJ:
1232 denomTmp *= m_Aionic[0];
1233 tmpLn = log(1.0 + denomTmp);
1234 for (size_t k = 1; k < m_kk; k++) {
1235 z_k = m_speciesCharge[k];
1237 - z_k * z_k * numdAdPTmp / (1.0 + denomTmp)
1238 - 2.0 * z_k * z_k * dAdP * tmpLn
1239 / (m_B_Debye * m_Aionic[0]);
1240 m_dlnActCoeffMolaldP[k] /= 3.0;
1241 }
1242
1243 sigma = 1.0 / (1.0 + denomTmp);
1244 m_dlnActCoeffMolaldP[0] = 2.0 /3.0 * dAdP * m_Mnaught *
1245 m_IionicMolality * sqrtI * sigma;
1246 break;
1247
1248 default:
1249 throw CanteraError("DebyeHuckel::s_update_dlnMolalityActCoeff_dP",
1250 "ERROR");
1251 }
1252}
1253
1254}
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:431
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
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:270
size_t m_kk
Number of species in the phase.
Definition Phase.h:921
double temperature() const
Temperature (K).
Definition Phase.h:629
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:174
size_t speciesIndex(const string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:147
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition Phase.cpp:504
shared_ptr< Species > species(const string &name) const
Return the Species object for the named species.
Definition Phase.cpp:937
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:605
vector< double > m_speciesCharge
Vector of species charges.
Definition Phase.h:932
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
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.