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