31double A_Debye_default = 1.172576;
32double maxIionicStrength_default = 100.0;
33double crop_ln_gamma_o_min_default = -6.0;
34double crop_ln_gamma_o_max_default = 3.0;
35double crop_ln_gamma_k_min_default = -5.0;
36double crop_ln_gamma_k_max_default = 15.0;
44 m_formPitzerTemp(PITZER_TEMP_CONSTANT),
45 m_IionicMolality(0.0),
46 m_maxIionicStrength(maxIionicStrength_default),
47 m_TempPitzerRef(298.15),
48 m_form_A_Debye(A_DEBYE_CONST),
49 m_A_Debye(A_Debye_default),
51 m_molalitiesAreCropped(false),
69 CROP_ln_gamma_o_min(crop_ln_gamma_o_min_default),
70 CROP_ln_gamma_o_max(crop_ln_gamma_o_max_default),
71 CROP_ln_gamma_k_min(crop_ln_gamma_k_min_default),
72 CROP_ln_gamma_k_max(crop_ln_gamma_k_max_default),
79 m_formPitzerTemp(PITZER_TEMP_CONSTANT),
80 m_IionicMolality(0.0),
81 m_maxIionicStrength(maxIionicStrength_default),
82 m_TempPitzerRef(298.15),
83 m_form_A_Debye(A_DEBYE_CONST),
84 m_A_Debye(A_Debye_default),
86 m_molalitiesAreCropped(false),
104 CROP_ln_gamma_o_min(crop_ln_gamma_o_min_default),
105 CROP_ln_gamma_o_max(crop_ln_gamma_o_max_default),
106 CROP_ln_gamma_k_min(crop_ln_gamma_k_min_default),
107 CROP_ln_gamma_k_max(crop_ln_gamma_k_max_default),
126 for (
size_t k = 0; k <
m_kk; k++) {
138 size_t kcation =
npos;
139 double xcation = 0.0;
140 size_t kanion =
npos;
141 for (
size_t k = 0; k <
m_kk; k++) {
147 }
else if (
charge(k) < 0.0) {
148 if (
m_tmpV[k] > xcation) {
154 if (kcation ==
npos || kanion ==
npos) {
157 double xuse = xcation;
159 if (xanion < xcation) {
161 if (
charge(kcation) != 1.0) {
165 if (
charge(kanion) != 1.0) {
169 xuse = xuse / factor;
198 return cp - beta * beta * tt * molarV / kappa_t;
227 for (
size_t k = 1; k <
m_kk; k++) {
236 double mvSolvent =
m_tmpV[0];
240 return 1.0 / mvSolvent;
249 s_update_lnMolalityActCoeff();
252 for (
size_t k = 1; k <
m_kk; k++) {
263 s_update_lnMolalityActCoeff();
265 for (
size_t k = 0; k <
m_kk; k++) {
266 acMolality[k] = exp(acMolality[k]);
282 s_update_lnMolalityActCoeff();
284 for (
size_t k = 1; k <
m_kk; k++) {
298 for (
size_t k = 0; k <
m_kk; k++) {
304 s_update_lnMolalityActCoeff();
306 for (
size_t k = 0; k <
m_kk; k++) {
318 for (
size_t k = 0; k <
m_kk; k++) {
324 s_update_lnMolalityActCoeff();
329 for (
size_t k = 1; k <
m_kk; k++) {
341 for (
size_t k = 0; k <
m_kk; k++) {
352 s_update_lnMolalityActCoeff();
354 for (
size_t k = 0; k <
m_kk; k++) {
362 for (
size_t k = 0; k <
m_kk; k++) {
368 s_update_lnMolalityActCoeff();
371 for (
size_t k = 0; k <
m_kk; k++) {
389static void check_nParams(
const std::string& method,
size_t nParams,
390 size_t m_formPitzerTemp)
392 if (m_formPitzerTemp == PITZER_TEMP_CONSTANT && nParams != 1) {
393 throw CanteraError(method,
"'constant' temperature model requires one"
394 " coefficient for each of parameter, but {} were given", nParams);
395 }
else if (m_formPitzerTemp == PITZER_TEMP_LINEAR && nParams != 2) {
396 throw CanteraError(method,
"'linear' temperature model requires two"
397 " coefficients for each parameter, but {} were given", nParams);
399 if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1 && nParams != 5) {
400 throw CanteraError(method,
"'complex' temperature model requires five"
401 " coefficients for each parameter, but {} were given", nParams);
405void HMWSoln::setBinarySalt(
const std::string& sp1,
const std::string& sp2,
406 size_t nParams,
double* beta0,
double* beta1,
double* beta2,
407 double* Cphi,
double alpha1,
double alpha2)
412 throw CanteraError(
"HMWSoln::setBinarySalt",
"Species '{}' not found", sp1);
413 }
else if (k2 ==
npos) {
414 throw CanteraError(
"HMWSoln::setBinarySalt",
"Species '{}' not found", sp2);
419 throw CanteraError(
"HMWSoln::setBinarySalt",
"Species '{}' and '{}' "
420 "do not have opposite charges ({}, {})", sp1, sp2,
430 for (
size_t n = 0; n < nParams; n++) {
436 m_Alpha1MX_ij[c] = alpha1;
440void HMWSoln::setTheta(
const std::string& sp1,
const std::string& sp2,
441 size_t nParams,
double* theta)
446 throw CanteraError(
"HMWSoln::setTheta",
"Species '{}' not found", sp1);
447 }
else if (k2 ==
npos) {
448 throw CanteraError(
"HMWSoln::setTheta",
"Species '{}' not found", sp2);
451 throw CanteraError(
"HMWSoln::setTheta",
"Species '{}' and '{}' "
452 "should both have the same (non-zero) charge ({}, {})", sp1, sp2,
458 for (
size_t n = 0; n < nParams; n++) {
463void HMWSoln::setPsi(
const std::string& sp1,
const std::string& sp2,
464 const std::string& sp3,
size_t nParams,
double* psi)
470 throw CanteraError(
"HMWSoln::setPsi",
"Species '{}' not found", sp1);
471 }
else if (k2 ==
npos) {
472 throw CanteraError(
"HMWSoln::setPsi",
"Species '{}' not found", sp2);
473 }
else if (k3 ==
npos) {
474 throw CanteraError(
"HMWSoln::setPsi",
"Species '{}' not found", sp3);
479 throw CanteraError(
"HMWSoln::setPsi",
"All species must be ions and"
480 " must include at least one cation and one anion, but given species"
481 " (charges) were: {} ({}), {} ({}), and {} ({}).",
492 for (
size_t n = 0; n < nParams; n++) {
499void HMWSoln::setLambda(
const std::string& sp1,
const std::string& sp2,
500 size_t nParams,
double* lambda)
505 throw CanteraError(
"HMWSoln::setLambda",
"Species '{}' not found", sp1);
506 }
else if (k2 ==
npos) {
507 throw CanteraError(
"HMWSoln::setLambda",
"Species '{}' not found", sp2);
511 throw CanteraError(
"HMWSoln::setLambda",
"Expected at least one neutral"
512 " species, but given species (charges) were: {} ({}) and {} ({}).",
519 size_t c = k1*
m_kk + k2;
520 for (
size_t n = 0; n < nParams; n++) {
526void HMWSoln::setMunnn(
const std::string& sp,
size_t nParams,
double* munnn)
530 throw CanteraError(
"HMWSoln::setMunnn",
"Species '{}' not found", sp);
534 throw CanteraError(
"HMWSoln::setMunnn",
"Expected a neutral species,"
535 " got {} ({}).", sp,
charge(k));
538 for (
size_t n = 0; n < nParams; n++) {
544void HMWSoln::setZeta(
const std::string& sp1,
const std::string& sp2,
545 const std::string& sp3,
size_t nParams,
double* psi)
551 throw CanteraError(
"HMWSoln::setZeta",
"Species '{}' not found", sp1);
552 }
else if (k2 ==
npos) {
553 throw CanteraError(
"HMWSoln::setZeta",
"Species '{}' not found", sp2);
554 }
else if (k3 ==
npos) {
555 throw CanteraError(
"HMWSoln::setZeta",
"Species '{}' not found", sp3);
560 throw CanteraError(
"HMWSoln::setZeta",
"Requires one neutral species, "
561 "one cation, and one anion, but given species (charges) were: "
562 "{} ({}), {} ({}), and {} ({}).",
569 }
else if (
charge(k3) == 0) {
581 for (
size_t n = 0; n < nParams; n++) {
587void HMWSoln::setPitzerTempModel(
const std::string& model)
596 throw CanteraError(
"HMWSoln::setPitzerTempModel",
597 "Unknown Pitzer ActivityCoeff Temp model: {}", model);
611void HMWSoln::setCroppingCoefficients(
double ln_gamma_k_min,
612 double ln_gamma_k_max,
double ln_gamma_o_min,
double ln_gamma_o_max)
614 CROP_ln_gamma_k_min = ln_gamma_k_min;
615 CROP_ln_gamma_k_max = ln_gamma_k_max;
616 CROP_ln_gamma_o_min = ln_gamma_o_min;
617 CROP_ln_gamma_o_max = ln_gamma_o_max;
620vector_fp getSizedVector(
const AnyMap& item,
const std::string& key,
size_t nCoeffs)
623 if (item[key].is<double>()) {
626 v.push_back(item[key].asDouble());
628 v = item[key].asVector<
double>(1, nCoeffs);
630 if (v.size() == 1 && nCoeffs == 5) {
643 setPitzerTempModel(actData[
"temperature-model"].asString());
651 if (actData.hasKey(
"A_Debye")) {
652 if (actData[
"A_Debye"] ==
"variable") {
655 setA_Debye(actData.convert(
"A_Debye",
"kg^0.5/gmol^0.5"));
658 if (actData.hasKey(
"max-ionic-strength")) {
659 setMaxIonicStrength(actData[
"max-ionic-strength"].asDouble());
661 if (actData.hasKey(
"interactions")) {
662 for (
auto& item : actData[
"interactions"].asVector<AnyMap>()) {
663 auto&
species = item[
"species"].asVector<
string>(1, 3);
668 if (nsp == 2 && q0 * q1 < 0) {
670 vector_fp beta0 = getSizedVector(item,
"beta0", nCoeffs);
671 vector_fp beta1 = getSizedVector(item,
"beta1", nCoeffs);
672 vector_fp beta2 = getSizedVector(item,
"beta2", nCoeffs);
673 vector_fp Cphi = getSizedVector(item,
"Cphi", nCoeffs);
674 if (beta0.size() != beta1.size() || beta0.size() != beta2.size()
675 || beta0.size() != Cphi.size()) {
677 "Inconsistent binary salt array sizes ({}, {}, {}, {})",
678 beta0.size(), beta1.size(), beta2.size(), Cphi.size());
680 double alpha1 = item[
"alpha1"].asDouble();
681 double alpha2 = item.getDouble(
"alpha2", 0.0);
683 beta0.data(), beta1.data(), beta2.data(), Cphi.data(),
685 }
else if (nsp == 2 && q0 * q1 > 0) {
687 vector_fp theta = getSizedVector(item,
"theta", nCoeffs);
689 }
else if (nsp == 2 && q0 * q1 == 0) {
691 vector_fp lambda = getSizedVector(item,
"lambda", nCoeffs);
693 }
else if (nsp == 3 && q0 * q1 * q2 != 0) {
695 vector_fp psi = getSizedVector(item,
"psi", nCoeffs);
697 psi.size(), psi.data());
698 }
else if (nsp == 3 && q0 * q1 * q2 == 0) {
700 vector_fp zeta = getSizedVector(item,
"zeta", nCoeffs);
702 zeta.size(), zeta.data());
703 }
else if (nsp == 1) {
705 vector_fp mu = getSizedVector(item,
"mu", nCoeffs);
706 setMunnn(
species[0], mu.size(), mu.data());
710 if (actData.hasKey(
"cropping-coefficients")) {
711 auto& crop = actData[
"cropping-coefficients"].as<
AnyMap>();
712 setCroppingCoefficients(
713 crop.getDouble(
"ln_gamma_k_min", crop_ln_gamma_k_min_default),
714 crop.getDouble(
"ln_gamma_k_max", crop_ln_gamma_k_max_default),
715 crop.getDouble(
"ln_gamma_o_min", crop_ln_gamma_o_min_default),
716 crop.getDouble(
"ln_gamma_o_max", crop_ln_gamma_o_max_default));
722 for (
int i = 0; i < 17; i++) {
744 for (
size_t k = 0; k <
m_kk; k++) {
746 if (fabs(mf[k] *
charge(k)) > MaxC) {
753 if (fabs(sum) > 1.0E-30) {
755 if (mf[kHp] > sum * 1.1) {
769 if (mf[kOHm] > -sum * 1.1) {
781 if (notDone && kMaxC !=
npos) {
782 if (mf[kMaxC] > (1.1 * sum /
charge(kMaxC))) {
783 mf[kMaxC] -= sum /
charge(kMaxC);
784 mf[0] += sum /
charge(kMaxC);
803void assignTrimmed(
AnyMap& interaction,
const std::string& key,
vector_fp& values) {
804 while (values.size() > 1 && values.back() == 0) {
807 if (values.size() == 1) {
808 interaction[key] = values[0];
810 interaction[key] = values;
820 activityNode[
"temperature-model"] =
"linear";
823 activityNode[
"temperature-model"] =
"complex";
828 activityNode[
"A_Debye"] =
"variable";
829 }
else if (
m_A_Debye != A_Debye_default) {
830 activityNode[
"A_Debye"].setQuantity(
m_A_Debye,
"kg^0.5/gmol^0.5");
836 vector<AnyMap> interactions;
839 for (
size_t i = 1; i <
m_kk; i++) {
840 for (
size_t j = 1; j <
m_kk; j++) {
841 size_t c = i*
m_kk + j;
843 bool lambda_found =
false;
844 for (
size_t n = 0; n < nParams; n++) {
852 interaction[
"species"] = vector<std::string>{
855 for (
size_t n = 0; n < nParams; n++) {
858 assignTrimmed(interaction,
"lambda", lambda);
859 interactions.push_back(std::move(interaction));
864 if (c == 0 || i > j) {
869 bool salt_found =
false;
870 for (
size_t n = 0; n < nParams; n++) {
880 interaction[
"species"] = vector<std::string>{
882 vector_fp beta0(nParams), beta1(nParams), beta2(nParams), Cphi(nParams);
883 size_t last_nonzero = 0;
884 for (
size_t n = 0; n < nParams; n++) {
889 if (beta0[n] || beta1[n] || beta2[n] || Cphi[n]) {
893 if (last_nonzero == 0) {
894 interaction[
"beta0"] = beta0[0];
895 interaction[
"beta1"] = beta1[0];
896 interaction[
"beta2"] = beta2[0];
897 interaction[
"Cphi"] = Cphi[0];
899 beta0.resize(1 + last_nonzero);
900 beta1.resize(1 + last_nonzero);
901 beta2.resize(1 + last_nonzero);
902 Cphi.resize(1 + last_nonzero);
903 interaction[
"beta0"] = beta0;
904 interaction[
"beta1"] = beta1;
905 interaction[
"beta2"] = beta2;
906 interaction[
"Cphi"] = Cphi;
908 interaction[
"alpha1"] = m_Alpha1MX_ij[c];
912 interactions.push_back(std::move(interaction));
917 bool theta_found =
false;
918 for (
size_t n = 0; n < nParams; n++) {
926 interaction[
"species"] = vector<std::string>{
929 for (
size_t n = 0; n < nParams; n++) {
932 assignTrimmed(interaction,
"theta", theta);
933 interactions.push_back(std::move(interaction));
942 for (
size_t i = 1; i <
m_kk; i++) {
946 for (
size_t j = i + 1; j <
m_kk; j++) {
950 for (
size_t k = j + 1; k <
m_kk; k++) {
955 for (
size_t n = 0; n < nParams; n++) {
958 interaction[
"species"] = vector<std::string>{
961 for (
size_t m = 0; m < nParams; m++) {
964 assignTrimmed(interaction,
"psi", psi);
965 interactions.push_back(std::move(interaction));
974 for (
size_t i = 1; i <
m_kk; i++) {
978 for (
size_t j = 1; j <
m_kk; j++) {
982 for (
size_t k = 1; k <
m_kk; k++) {
987 for (
size_t n = 0; n < nParams; n++) {
990 interaction[
"species"] = vector<std::string>{
993 for (
size_t m = 0; m < nParams; m++) {
996 assignTrimmed(interaction,
"zeta", zeta);
997 interactions.push_back(std::move(interaction));
1006 for (
size_t i = 1; i <
m_kk; i++) {
1007 for (
size_t n = 0; n < nParams; n++) {
1010 interaction[
"species"] = vector<std::string>{
speciesName(i)};
1012 for (
size_t m = 0; m < nParams; m++) {
1015 assignTrimmed(interaction,
"mu", mu);
1016 interactions.push_back(std::move(interaction));
1022 activityNode[
"interactions"] = std::move(interactions);
1025 if (CROP_ln_gamma_k_min != crop_ln_gamma_k_min_default) {
1026 croppingCoeffs[
"ln_gamma_k_min"] = CROP_ln_gamma_k_min;
1028 if (CROP_ln_gamma_k_max != crop_ln_gamma_k_max_default) {
1029 croppingCoeffs[
"ln_gamma_k_max"] = CROP_ln_gamma_k_max;
1031 if (CROP_ln_gamma_o_min != crop_ln_gamma_o_min_default) {
1032 croppingCoeffs[
"ln_gamma_o_min"] = CROP_ln_gamma_o_min;
1034 if (CROP_ln_gamma_o_max != crop_ln_gamma_o_max_default) {
1035 croppingCoeffs[
"ln_gamma_o_max"] = CROP_ln_gamma_o_max;
1037 if (croppingCoeffs.
size()) {
1038 activityNode[
"cropping-coefficients"] = std::move(croppingCoeffs);
1041 phaseNode[
"activity-data"] = std::move(activityNode);
1046 if (id_.size() > 0) {
1047 string idp = phaseNode.
id();
1050 "phasenode and Id are incompatible");
1055 if (!phaseNode.
hasChild(
"thermo")) {
1057 "no thermo XML node");
1063 if (thermoNode.
hasChild(
"activityCoefficients")) {
1064 XML_Node& scNode = thermoNode.
child(
"activityCoefficients");
1068 string formString = scNode.
attrib(
"TempModel");
1069 if (formString !=
"") {
1070 setPitzerTempModel(formString);
1076 formString = scNode.
attrib(
"TempReference");
1077 if (formString !=
"") {
1088 if (thermoNode.
hasChild(
"activityCoefficients")) {
1089 XML_Node& acNode = thermoNode.
child(
"activityCoefficients");
1102 if (acNode.
hasChild(
"maxIonicStrength")) {
1103 setMaxIonicStrength(
getFloat(acNode,
"maxIonicStrength"));
1106 for (
const auto& xmlACChild : acNode.
children()) {
1107 string nodeName = xmlACChild->name();
1130 if (acNode.
hasChild(
"croppingCoefficients")) {
1132 setCroppingCoefficients(
1133 getFloat(cropNode.
child(
"ln_gamma_k_min"),
"pureSolventValue"),
1134 getFloat(cropNode.
child(
"ln_gamma_k_max"),
"pureSolventValue"),
1135 getFloat(cropNode.
child(
"ln_gamma_o_min"),
"pureSolventValue"),
1136 getFloat(cropNode.
child(
"ln_gamma_o_max"),
"pureSolventValue"));
1147 if (tempArg != -1.0) {
1151 if (presArg != -1.0) {
1170 throw CanteraError(
"HMWSoln::A_Debye_TP",
"shouldn't be here");
1178 if (tempArg != -1.0) {
1182 if (presArg != -1.0) {
1194 throw CanteraError(
"HMWSoln::dA_DebyedT_TP",
"shouldn't be here");
1202 if (tempArg != -1.0) {
1206 if (presArg != -1.0) {
1219 dAdP = cached.
value;
1222 cached.
value = dAdP;
1226 throw CanteraError(
"HMWSoln::dA_DebyedP_TP",
"shouldn't be here");
1234 double dAphidT = dAdT /3.0;
1236 if (tempArg != -1.0) {
1245 double dAphidP = dAdP /3.0;
1247 if (tempArg != -1.0) {
1256 if (tempArg != -1.0) {
1261 double d2Aphi = d2 / 3.0;
1262 return 2.0 * A_L / T + 4.0 *
GasConstant * T * T *d2Aphi;
1268 if (tempArg != -1.0) {
1272 if (presArg != -1.0) {
1284 throw CanteraError(
"HMWSoln::d2A_DebyedT2_TP",
"shouldn't be here");
1298 size_t maxCounterIJlen = 1 + (
m_kk-1) * (
m_kk-2) / 2;
1301 int TCoeffLength = 1;
1332 m_Alpha1MX_ij.resize(maxCounterIJlen, 2.0);
1373 m_BMX_IJ.resize(maxCounterIJlen, 0.0);
1385 m_Phi_IJ.resize(maxCounterIJlen, 0.0);
1394 m_CMX_IJ.resize(maxCounterIJlen, 0.0);
1406void HMWSoln::s_update_lnMolalityActCoeff()
const
1434 double lnActCoeffMolal0 = - log(xx) + (xx - 1.0)/xx;
1435 double lnxs = log(xx);
1437 for (
size_t k = 1; k <
m_kk; k++) {
1472 doublereal Imax = 0.0;
1475 for (
size_t k = 0; k <
m_kk; k++) {
1481 if (cropMethod == 0) {
1488 for (
size_t i = 1; i < (
m_kk - 1); i++) {
1489 double charge_i =
charge(i);
1490 double abs_charge_i = fabs(charge_i);
1491 if (charge_i == 0.0) {
1494 for (
size_t j = (i+1); j <
m_kk; j++) {
1495 double charge_j =
charge(j);
1496 double abs_charge_j = fabs(charge_j);
1499 if (charge_i * charge_j < 0) {
1504 if (Imax > Iac_max) {
1508 if (Imax > Iac_max) {
1513 if (Imax > Iac_max) {
1517 if (Imax > Iac_max) {
1527 for (
int times = 0; times< 10; times++) {
1528 double anion_charge = 0.0;
1529 double cation_charge = 0.0;
1530 size_t anion_contrib_max_i =
npos;
1531 double anion_contrib_max = -1.0;
1532 size_t cation_contrib_max_i =
npos;
1533 double cation_contrib_max = -1.0;
1534 for (
size_t i = 0; i <
m_kk; i++) {
1535 double charge_i =
charge(i);
1536 if (charge_i < 0.0) {
1538 anion_charge += anion_contrib;
1539 if (anion_contrib > anion_contrib_max) {
1540 anion_contrib_max = anion_contrib;
1541 anion_contrib_max_i = i;
1543 }
else if (charge_i > 0.0) {
1545 cation_charge += cation_contrib;
1546 if (cation_contrib > cation_contrib_max) {
1547 cation_contrib_max = cation_contrib;
1548 cation_contrib_max_i = i;
1552 double total_charge = cation_charge - anion_charge;
1553 if (total_charge > 1.0E-8) {
1554 double desiredCrop = total_charge/
charge(cation_contrib_max_i);
1556 if (desiredCrop < maxCrop) {
1562 }
else if (total_charge < -1.0E-8) {
1563 double desiredCrop = total_charge/
charge(anion_contrib_max_i);
1565 if (desiredCrop < maxCrop) {
1577 if (cropMethod == 1) {
1580 double xmolSolvent = molF[0];
1586 double poly = MC_apCut_ + MC_bpCut_ * xmolSolvent + MC_dpCut_* xmolSolvent * xmolSolvent;
1587 double p = xmolSolvent + MC_epCut_ + exp(- xmolSolvent/ MC_cpCut_) * poly;
1589 for (
size_t k = 0; k <
m_kk; k++) {
1597 for (
size_t k = 0; k <
m_kk; k++) {
1602 for (
size_t k = 0; k <
m_kk; k++) {
1615 for (
size_t i = 0; i <
m_kk; i++) {
1617 size_t nc =
m_kk * i;
1621 for (
size_t i = 1; i < (
m_kk - 1); i++) {
1622 size_t n =
m_kk * i + i;
1624 for (
size_t j = (i+1); j <
m_kk; j++) {
1626 size_t nc =
m_kk * i + j;
1636 if (BinSalt.
name() !=
"binarySaltParameters") {
1638 "Incorrect name for processing this routine: " + BinSalt.
name());
1641 string iName = BinSalt.
attrib(
"cation");
1643 throw CanteraError(
"HMWSoln::readXMLBinarySalt",
"no cation attrib");
1645 string jName = BinSalt.
attrib(
"anion");
1647 throw CanteraError(
"HMWSoln::readXMLBinarySalt",
"no anion attrib");
1661 if (beta0.size() != beta1.size() || beta0.size() != beta2.size() ||
1662 beta0.size() != Cphi.size()) {
1663 throw CanteraError(
"HMWSoln::readXMLBinarySalt",
"Inconsistent"
1664 " array sizes ({}, {}, {}, {})", beta0.size(), beta1.size(),
1665 beta2.size(), Cphi.size());
1668 beta0.resize(5, 0.0);
1669 beta1.resize(5, 0.0);
1670 beta2.resize(5, 0.0);
1671 Cphi.resize(5, 0.0);
1673 double alpha1 =
getFloat(BinSalt,
"Alpha1");
1674 double alpha2 = 0.0;
1676 setBinarySalt(iName, jName, beta0.size(), beta0.data(), beta1.data(),
1677 beta2.data(), Cphi.data(), alpha1, alpha2);
1682 string ispName, jspName;
1683 if (node.
name() ==
"thetaAnion") {
1684 ispName = node.
attrib(
"anion1");
1685 if (ispName ==
"") {
1686 throw CanteraError(
"HMWSoln::readXMLTheta",
"no anion1 attrib");
1688 jspName = node.
attrib(
"anion2");
1689 if (jspName ==
"") {
1690 throw CanteraError(
"HMWSoln::readXMLTheta",
"no anion2 attrib");
1692 }
else if (node.
name() ==
"thetaCation") {
1693 ispName = node.
attrib(
"cation1");
1694 if (ispName ==
"") {
1695 throw CanteraError(
"HMWSoln::readXMLTheta",
"no cation1 attrib");
1697 jspName = node.
attrib(
"cation2");
1698 if (jspName ==
"") {
1699 throw CanteraError(
"HMWSoln::readXMLTheta",
"no cation2 attrib");
1703 "Incorrect name for processing this routine: " + node.
name());
1715 theta.resize(5, 0.0);
1717 setTheta(ispName, jspName, theta.size(), theta.data());
1722 string iName, jName, kName;
1723 if (node.
name() ==
"psiCommonCation") {
1724 kName = node.
attrib(
"cation");
1726 throw CanteraError(
"HMWSoln::readXMLPsi",
"no cation attrib");
1728 iName = node.
attrib(
"anion1");
1730 throw CanteraError(
"HMWSoln::readXMLPsi",
"no anion1 attrib");
1732 jName = node.
attrib(
"anion2");
1734 throw CanteraError(
"HMWSoln::readXMLPsi",
"no anion2 attrib");
1736 }
else if (node.
name() ==
"psiCommonAnion") {
1737 kName = node.
attrib(
"anion");
1739 throw CanteraError(
"HMWSoln::readXMLPsi",
"no anion attrib");
1741 iName = node.
attrib(
"cation1");
1743 throw CanteraError(
"HMWSoln::readXMLPsi",
"no cation1 attrib");
1745 jName = node.
attrib(
"cation2");
1747 throw CanteraError(
"HMWSoln::readXMLPsi",
"no cation2 attrib");
1751 "Incorrect name for processing this routine: " + node.
name());
1766 setPsi(iName, jName, kName, psi.size(), psi.data());
1772 if (node.
name() !=
"lambdaNeutral") {
1774 "Incorrect name for processing this routine: " + node.
name());
1776 string iName = node.
attrib(
"species1");
1778 throw CanteraError(
"HMWSoln::readXMLLambdaNeutral",
"no species1 attrib");
1780 string jName = node.
attrib(
"species2");
1782 throw CanteraError(
"HMWSoln::readXMLLambdaNeutral",
"no species2 attrib");
1794 lambda.resize(5, 0.0);
1796 setLambda(iName, jName, lambda.size(), lambda.data());
1801 if (node.
name() !=
"MunnnNeutral") {
1803 "Incorrect name for processing this routine: " + node.
name());
1805 string iName = node.
attrib(
"species1");
1807 throw CanteraError(
"HMWSoln::readXMLMunnnNeutral",
"no species1 attrib");
1819 munnn.resize(5, 0.0);
1821 setMunnn(iName, munnn.size(), munnn.data());
1826 if (node.
name() !=
"zetaCation") {
1828 "Incorrect name for processing this routine: " + node.
name());
1831 string iName = node.
attrib(
"neutral");
1833 throw CanteraError(
"HMWSoln::readXMLZetaCation",
"no neutral attrib");
1835 string jName = node.
attrib(
"cation1");
1837 throw CanteraError(
"HMWSoln::readXMLZetaCation",
"no cation1 attrib");
1839 string kName = node.
attrib(
"anion1");
1841 throw CanteraError(
"HMWSoln::readXMLZetaCation",
"no anion1 attrib");
1854 zeta.resize(5, 0.0);
1856 setZeta(iName, jName, kName, zeta.size(), zeta.data());
1861 double IMS_gamma_o_min_ = 1.0E-5;
1862 double IMS_gamma_k_min_ = 10.0;
1863 double IMS_slopefCut_ = 0.6;
1865 IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_);
1867 bool converged =
false;
1869 for (
int its = 0; its < 100 && !converged; its++) {
1871 IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_) -IMS_efCut_;
1872 IMS_bfCut_ = IMS_afCut_ /
IMS_cCut_ + IMS_slopefCut_ - 1.0;
1878 IMS_efCut_ = - eterm * tmp;
1879 if (fabs(IMS_efCut_ - oldV) < 1.0E-14) {
1885 " failed to converge on the f polynomial");
1888 double f_0 = IMS_afCut_ + IMS_efCut_;
1889 double f_prime_0 = 1.0 - IMS_afCut_ /
IMS_cCut_ + IMS_bfCut_;
1891 for (
int its = 0; its < 100 && !converged; its++) {
1893 double lng_0 = -log(IMS_gamma_o_min_) - f_prime_0 / f_0;
1894 IMS_agCut_ = exp(lng_0) - IMS_egCut_;
1901 IMS_egCut_ = - eterm * tmp;
1902 if (fabs(IMS_egCut_ - oldV) < 1.0E-14) {
1908 " failed to converge on the g polynomial");
1914 double MC_X_o_min_ = 0.35;
1916 double MC_slopepCut_ = 0.02;
1920 MC_apCut_ = MC_X_o_min_;
1922 bool converged =
false;
1925 for (
int its = 0; its < 500 && !converged; its++) {
1927 MC_apCut_ = damp *(MC_X_o_min_ - MC_epCut_) + (1-damp) * MC_apCut_;
1928 double MC_bpCutNew = MC_apCut_ / MC_cpCut_ + MC_slopepCut_ - 1.0;
1929 MC_bpCut_ = damp * MC_bpCutNew + (1-damp) * MC_bpCut_;
1930 double MC_dpCutNew = ((- MC_apCut_/MC_cpCut_ + MC_bpCut_ - MC_bpCut_ *
MC_X_o_cutoff_/MC_cpCut_)
1933 MC_dpCut_ = damp * MC_dpCutNew + (1-damp) * MC_dpCut_;
1936 MC_epCut_ = - eterm * tmp;
1937 double diff = MC_epCut_ - oldV;
1938 if (fabs(diff) < 1.0E-14) {
1944 " failed to converge on the p polynomial");
1951 const double twoT = 2.0 * T;
1952 const double invT = 1.0 / T;
1953 const double invT2 = invT * invT;
1954 const double twoinvT3 = 2.0 * invT * invT2;
1955 double tinv = 0.0, tln = 0.0, tlin = 0.0, tquad = 0.0;
1965 for (
size_t i = 1; i < (
m_kk - 1); i++) {
1966 for (
size_t j = (i+1); j <
m_kk; j++) {
1968 size_t n =
m_kk*i + j;
1978 case PITZER_TEMP_CONSTANT:
1980 case PITZER_TEMP_LINEAR:
1983 + beta0MX_coeff[1]*tlin;
1987 + beta1MX_coeff[1]*tlin;
1991 + beta2MX_coeff[1]*tlin;
1995 + CphiMX_coeff[1]*tlin;
1998 m_Theta_ij[counterIJ] = Theta_coeff[0] + Theta_coeff[1]*tlin;
2003 case PITZER_TEMP_COMPLEX1:
2005 + beta0MX_coeff[1]*tlin
2006 + beta0MX_coeff[2]*tquad
2007 + beta0MX_coeff[3]*tinv
2008 + beta0MX_coeff[4]*tln;
2010 + beta1MX_coeff[1]*tlin
2011 + beta1MX_coeff[2]*tquad
2012 + beta1MX_coeff[3]*tinv
2013 + beta1MX_coeff[4]*tln;
2015 + beta2MX_coeff[1]*tlin
2016 + beta2MX_coeff[2]*tquad
2017 + beta2MX_coeff[3]*tinv
2018 + beta2MX_coeff[4]*tln;
2020 + CphiMX_coeff[1]*tlin
2021 + CphiMX_coeff[2]*tquad
2022 + CphiMX_coeff[3]*tinv
2023 + CphiMX_coeff[4]*tln;
2025 + Theta_coeff[1]*tlin
2026 + Theta_coeff[2]*tquad
2027 + Theta_coeff[3]*tinv
2028 + Theta_coeff[4]*tln;
2030 + beta0MX_coeff[2]*twoT
2031 - beta0MX_coeff[3]*invT2
2032 + beta0MX_coeff[4]*invT;
2034 + beta1MX_coeff[2]*twoT
2035 - beta1MX_coeff[3]*invT2
2036 + beta1MX_coeff[4]*invT;
2038 + beta2MX_coeff[2]*twoT
2039 - beta2MX_coeff[3]*invT2
2040 + beta2MX_coeff[4]*invT;
2042 + CphiMX_coeff[2]*twoT
2043 - CphiMX_coeff[3]*invT2
2044 + CphiMX_coeff[4]*invT;
2046 + Theta_coeff[2]*twoT
2047 - Theta_coeff[3]*invT2
2048 + Theta_coeff[4]*invT;
2052 + beta0MX_coeff[2]*2.0
2053 + beta0MX_coeff[3]*twoinvT3
2054 - beta0MX_coeff[4]*invT2;
2056 + beta1MX_coeff[2]*2.0
2057 + beta1MX_coeff[3]*twoinvT3
2058 - beta1MX_coeff[4]*invT2;
2060 + beta2MX_coeff[2]*2.0
2061 + beta2MX_coeff[3]*twoinvT3
2062 - beta2MX_coeff[4]*invT2;
2064 + CphiMX_coeff[2]*2.0
2065 + CphiMX_coeff[3]*twoinvT3
2066 - CphiMX_coeff[4]*invT2;
2068 + Theta_coeff[2]*2.0
2069 + Theta_coeff[3]*twoinvT3
2070 - Theta_coeff[4]*invT2;
2080 for (
size_t i = 1; i <
m_kk; i++) {
2082 for (
size_t j = 1; j <
m_kk; j++) {
2083 size_t n = i *
m_kk + j;
2086 case PITZER_TEMP_CONSTANT:
2089 case PITZER_TEMP_LINEAR:
2090 m_Lambda_nj(i,j) = Lambda_coeff[0] + Lambda_coeff[1]*tlin;
2094 case PITZER_TEMP_COMPLEX1:
2096 + Lambda_coeff[1]*tlin
2097 + Lambda_coeff[2]*tquad
2098 + Lambda_coeff[3]*tinv
2099 + Lambda_coeff[4]*tln;
2102 + Lambda_coeff[2]*twoT
2103 - Lambda_coeff[3]*invT2
2104 + Lambda_coeff[4]*invT;
2108 + Lambda_coeff[3]*twoinvT3
2109 - Lambda_coeff[4]*invT2;
2115 case PITZER_TEMP_CONSTANT:
2118 case PITZER_TEMP_LINEAR:
2119 m_Mu_nnn[i] = Mu_coeff[0] + Mu_coeff[1]*tlin;
2123 case PITZER_TEMP_COMPLEX1:
2135 + Mu_coeff[3]*twoinvT3
2136 - Mu_coeff[4]*invT2;
2144 case PITZER_TEMP_CONSTANT:
2145 for (
size_t i = 1; i <
m_kk; i++) {
2146 for (
size_t j = 1; j <
m_kk; j++) {
2147 for (
size_t k = 1; k <
m_kk; k++) {
2155 case PITZER_TEMP_LINEAR:
2156 for (
size_t i = 1; i <
m_kk; i++) {
2157 for (
size_t j = 1; j <
m_kk; j++) {
2158 for (
size_t k = 1; k <
m_kk; k++) {
2161 m_Psi_ijk[n] = Psi_coeff[0] + Psi_coeff[1]*tlin;
2168 case PITZER_TEMP_COMPLEX1:
2169 for (
size_t i = 1; i <
m_kk; i++) {
2170 for (
size_t j = 1; j <
m_kk; j++) {
2171 for (
size_t k = 1; k <
m_kk; k++) {
2176 + Psi_coeff[2]*tquad
2181 - Psi_coeff[3]*invT2
2182 + Psi_coeff[4]*invT;
2185 + Psi_coeff[3]*twoinvT3
2186 - Psi_coeff[4]*invT2;
2204 double etheta[5][5], etheta_prime[5][5], sqrtIs;
2211 double molarcharge = 0.0;
2215 double molalitysumUncropped = 0.0;
2221 for (
size_t n = 1; n <
m_kk; n++) {
2225 molarcharge += fabs(
charge(n)) * molality[n];
2240 for (
int z1 = 1; z1 <=4; z1++) {
2241 for (
int z2 =1; z2 <=4; z2++) {
2242 calc_thetas(z1, z2, ðeta[z1][z2], ðeta_prime[z1][z2]);
2249 for (
size_t i = 1; i < (
m_kk - 1); i++) {
2250 for (
size_t j = (i+1); j <
m_kk; j++) {
2252 size_t n =
m_kk*i + j;
2258 double x1 = sqrtIs * m_Alpha1MX_ij[counterIJ];
2259 if (x1 > 1.0E-100) {
2260 m_gfunc_IJ[counterIJ] = 2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
2262 (1.0-(1.0 + x1 + 0.5 * x1 * x1) * exp(-x1)) / (x1 * x1);
2270 if (x2 > 1.0E-100) {
2271 m_g2func_IJ[counterIJ] = 2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
2273 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
2288 for (
size_t i = 1; i <
m_kk - 1; i++) {
2289 for (
size_t j = i+1; j <
m_kk; j++) {
2291 size_t n =
m_kk*i + j;
2301 if (Is > 1.0E-150) {
2318 for (
size_t i = 1; i <
m_kk-1; i++) {
2319 for (
size_t j = i+1; j <
m_kk; j++) {
2321 size_t n =
m_kk*i + j;
2337 for (
size_t i = 1; i <
m_kk-1; i++) {
2338 for (
size_t j = i+1; j <
m_kk; j++) {
2340 size_t n =
m_kk*i + j;
2346 int z1 = (int) fabs(
charge(i));
2347 int z2 = (int) fabs(
charge(j));
2362 double F = -Aphi * (sqrt(Is) / (1.0 + 1.2*sqrt(Is))
2363 + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
2364 for (
size_t i = 1; i <
m_kk-1; i++) {
2365 for (
size_t j = i+1; j <
m_kk; j++) {
2367 size_t n =
m_kk*i + j;
2384 for (
size_t i = 1; i <
m_kk; i++) {
2397 for (
size_t j = 1; j <
m_kk; j++) {
2399 size_t n =
m_kk*i + j;
2404 sum1 += molality[j] *
2410 for (
size_t k = j+1; k <
m_kk; k++) {
2414 sum3 += molality[j]*molality[k]*
m_Psi_ijk[n];
2423 sum2 += molality[j]*(2.0*
m_Phi_IJ[counterIJ]);
2425 for (
size_t k = 1; k <
m_kk; k++) {
2429 sum2 += molality[j]*molality[k]*
m_Psi_ijk[n];
2434 sum4 += (fabs(
charge(i))*
2435 molality[j]*molality[k]*
m_CMX_IJ[counterIJ2]);
2445 for (
size_t k = 1; k <
m_kk; k++) {
2452 sum5 += molality[j]*molality[k]*zeta;
2476 for (
size_t j = 1; j <
m_kk; j++) {
2478 size_t n =
m_kk*i + j;
2483 sum1 += molality[j]*
2486 for (
size_t k = j+1; k <
m_kk; k++) {
2490 sum3 += molality[j]*molality[k]*
m_Psi_ijk[n];
2500 sum2 += molality[j]*(2.0*
m_Phi_IJ[counterIJ]);
2502 for (
size_t k = 1; k <
m_kk; k++) {
2506 sum2 += molality[j]*molality[k]*
m_Psi_ijk[n];
2511 molality[j]*molality[k]*
m_CMX_IJ[counterIJ2];
2520 for (
size_t k = 1; k <
m_kk; k++) {
2528 sum5 += molality[j]*molality[k]*zeta;
2544 for (
size_t j = 1; j <
m_kk; j++) {
2548 for (
size_t k = 1; k <
m_kk; k++) {
2551 sum3 += molality[j]*molality[k]*
m_Psi_ijk[n];
2556 double sum2 = 3.0 * molality[i]* molality[i] *
m_Mu_nnn[i];
2578 double term1 = -Aphi * pow(Is,1.5) / (1.0 + 1.2 * sqrt(Is));
2580 for (
size_t j = 1; j <
m_kk; j++) {
2583 for (
size_t k = 1; k <
m_kk; k++) {
2586 size_t n =
m_kk*j + k;
2589 sum1 += molality[j]*molality[k]*
2594 for (
size_t k = j+1; k <
m_kk; k++) {
2595 if (j == (
m_kk-1)) {
2597 throw CanteraError(
"HMWSoln::s_updatePitzer_lnMolalityActCoeff",
2598 "logic error 1 in Step 9 of hmw_act");
2603 size_t n =
m_kk*j + k;
2605 sum2 += molality[j]*molality[k]*
m_PhiPhi_IJ[counterIJ];
2606 for (
size_t m = 1; m <
m_kk; m++) {
2610 sum2 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk[n];
2619 for (
size_t k = j+1; k <
m_kk; k++) {
2622 throw CanteraError(
"HMWSoln::s_updatePitzer_lnMolalityActCoeff",
2623 "logic error 2 in Step 9 of hmw_act");
2628 size_t n =
m_kk*j + k;
2630 sum3 += molality[j]*molality[k]*
m_PhiPhi_IJ[counterIJ];
2631 for (
size_t m = 1; m <
m_kk; m++) {
2634 sum3 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk[n];
2643 for (
size_t k = 1; k <
m_kk; k++) {
2653 }
else if (k == j) {
2654 sum6 += 0.5 * molality[j]*molality[k]*
m_Lambda_nj(j,k);
2659 for (
size_t m = 1; m <
m_kk; m++) {
2665 sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta;
2671 sum7 += molality[j]*molality[j]*molality[j]*
m_Mu_nnn[j];
2674 double sum_m_phi_minus_1 = 2.0 *
2675 (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
2678 double osmotic_coef;
2679 if (molalitysumUncropped > 1.0E-150) {
2680 osmotic_coef = 1.0 + (sum_m_phi_minus_1 / molalitysumUncropped);
2684 double lnwateract = -(
m_weightSolvent/1000.0) * molalitysumUncropped * osmotic_coef;
2711 for (
size_t k = 1; k <
m_kk; k++) {
2735 double etheta[5][5], etheta_prime[5][5], sqrtIs;
2742 double molarcharge = 0.0;
2746 double molalitysum = 0.0;
2752 for (
size_t n = 1; n <
m_kk; n++) {
2756 molarcharge += fabs(
charge(n)) * molality[n];
2757 molalitysum += molality[n];
2771 for (
int z1 = 1; z1 <=4; z1++) {
2772 for (
int z2 =1; z2 <=4; z2++) {
2773 calc_thetas(z1, z2, ðeta[z1][z2], ðeta_prime[z1][z2]);
2780 for (
size_t i = 1; i < (
m_kk - 1); i++) {
2781 for (
size_t j = (i+1); j <
m_kk; j++) {
2783 size_t n =
m_kk*i + j;
2789 double x1 = sqrtIs * m_Alpha1MX_ij[counterIJ];
2790 if (x1 > 1.0E-100) {
2791 m_gfunc_IJ[counterIJ] = 2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
2793 (1.0-(1.0 + x1 + 0.5 * x1 *x1) * exp(-x1)) / (x1 * x1);
2801 if (x2 > 1.0E-100) {
2802 m_g2func_IJ[counterIJ] = 2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
2804 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
2820 for (
size_t i = 1; i <
m_kk - 1; i++) {
2821 for (
size_t j = i+1; j <
m_kk; j++) {
2823 size_t n =
m_kk*i + j;
2832 if (Is > 1.0E-150) {
2848 for (
size_t i = 1; i <
m_kk-1; i++) {
2849 for (
size_t j = i+1; j <
m_kk; j++) {
2851 size_t n =
m_kk*i + j;
2866 for (
size_t i = 1; i <
m_kk-1; i++) {
2867 for (
size_t j = i+1; j <
m_kk; j++) {
2869 size_t n =
m_kk*i + j;
2888 double dAphidT = dA_DebyedT /3.0;
2889 double dFdT = -dAphidT * (sqrt(Is) / (1.0 + 1.2*sqrt(Is))
2890 + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
2891 for (
size_t i = 1; i <
m_kk-1; i++) {
2892 for (
size_t j = i+1; j <
m_kk; j++) {
2894 size_t n =
m_kk*i + j;
2911 for (
size_t i = 1; i <
m_kk; i++) {
2921 for (
size_t j = 1; j <
m_kk; j++) {
2923 size_t n =
m_kk*i + j;
2928 sum1 += molality[j]*
2934 for (
size_t k = j+1; k <
m_kk; k++) {
2947 sum2 += molality[j]*(2.0*
m_Phi_IJ_L[counterIJ]);
2949 for (
size_t k = 1; k <
m_kk; k++) {
2959 molality[j]*molality[k]*
m_CMX_IJ_L[counterIJ2];
2970 for (
size_t k = 1; k <
m_kk; k++) {
2976 if (zeta_L != 0.0) {
2977 sum5 += molality[j]*molality[k]*zeta_L;
2986 zsqdFdT + sum1 + sum2 + sum3 + sum4 + sum5;
2999 for (
size_t j = 1; j <
m_kk; j++) {
3001 size_t n =
m_kk*i + j;
3006 sum1 += molality[j]*
3009 for (
size_t k = j+1; k <
m_kk; k++) {
3023 sum2 += molality[j]*(2.0*
m_Phi_IJ_L[counterIJ]);
3025 for (
size_t k = 1; k <
m_kk; k++) {
3033 sum4 += fabs(
charge(i)) *
3034 molality[j]*molality[k]*
m_CMX_IJ_L[counterIJ2];
3042 for (
size_t k = 1; k <
m_kk; k++) {
3049 if (zeta_L != 0.0) {
3050 sum5 += molality[j]*molality[k]*zeta_L;
3057 zsqdFdT + sum1 + sum2 + sum3 + sum4 + sum5;
3067 for (
size_t j = 1; j <
m_kk; j++) {
3071 for (
size_t k = 1; k <
m_kk; k++) {
3079 double sum2 = 3.0 * molality[i] * molality[i] *
m_Mu_nnn_L[i];
3099 double term1 = -dAphidT * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
3101 for (
size_t j = 1; j <
m_kk; j++) {
3104 for (
size_t k = 1; k <
m_kk; k++) {
3107 size_t n =
m_kk*j + k;
3109 sum1 += molality[j]*molality[k]*
3114 for (
size_t k = j+1; k <
m_kk; k++) {
3115 if (j == (
m_kk-1)) {
3117 throw CanteraError(
"HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dT",
3118 "logic error 1 in Step 9 of hmw_act");
3123 size_t n =
m_kk*j + k;
3126 for (
size_t m = 1; m <
m_kk; m++) {
3130 sum2 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_L[n];
3139 for (
size_t k = j+1; k <
m_kk; k++) {
3142 throw CanteraError(
"HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dT",
3143 "logic error 2 in Step 9 of hmw_act");
3148 size_t n =
m_kk*j + k;
3151 for (
size_t m = 1; m <
m_kk; m++) {
3154 sum3 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_L[n];
3163 for (
size_t k = 1; k <
m_kk; k++) {
3173 }
else if (k == j) {
3179 for (
size_t m = 1; m <
m_kk; m++) {
3184 if (zeta_L != 0.0) {
3185 sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_L;
3191 sum7 += molality[j]*molality[j]*molality[j]*
m_Mu_nnn_L[j];
3194 double sum_m_phi_minus_1 = 2.0 *
3195 (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
3198 double d_osmotic_coef_dT;
3199 if (molalitysum > 1.0E-150) {
3200 d_osmotic_coef_dT = 0.0 + (sum_m_phi_minus_1 / molalitysum);
3202 d_osmotic_coef_dT = 0.0;
3205 double d_lnwateract_dT = -(
m_weightSolvent/1000.0) * molalitysum * d_osmotic_coef_dT;
3230 for (
size_t k = 1; k <
m_kk; k++) {
3249 double etheta[5][5], etheta_prime[5][5], sqrtIs;
3256 double molarcharge = 0.0;
3260 double molalitysum = 0.0;
3266 for (
size_t n = 1; n <
m_kk; n++) {
3270 molarcharge += fabs(
charge(n)) * molality[n];
3271 molalitysum += molality[n];
3285 for (
int z1 = 1; z1 <=4; z1++) {
3286 for (
int z2 =1; z2 <=4; z2++) {
3287 calc_thetas(z1, z2, ðeta[z1][z2], ðeta_prime[z1][z2]);
3294 for (
size_t i = 1; i < (
m_kk - 1); i++) {
3295 for (
size_t j = (i+1); j <
m_kk; j++) {
3297 size_t n =
m_kk*i + j;
3303 double x1 = sqrtIs * m_Alpha1MX_ij[counterIJ];
3304 if (x1 > 1.0E-100) {
3305 m_gfunc_IJ[counterIJ] = 2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 *x1);
3307 (1.0-(1.0 + x1 + 0.5*x1 * x1) * exp(-x1)) / (x1 * x1);
3315 if (x2 > 1.0E-100) {
3316 m_g2func_IJ[counterIJ] = 2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
3318 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
3334 for (
size_t i = 1; i <
m_kk - 1; i++) {
3335 for (
size_t j = i+1; j <
m_kk; j++) {
3337 size_t n =
m_kk*i + j;
3346 if (Is > 1.0E-150) {
3362 for (
size_t i = 1; i <
m_kk-1; i++) {
3363 for (
size_t j = i+1; j <
m_kk; j++) {
3365 size_t n =
m_kk*i + j;
3380 for (
size_t i = 1; i <
m_kk-1; i++) {
3381 for (
size_t j = i+1; j <
m_kk; j++) {
3383 size_t n =
m_kk*i + j;
3402 double d2FdT2 = -d2AphidT2 * (sqrt(Is) / (1.0 + 1.2*sqrt(Is))
3403 + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
3404 for (
size_t i = 1; i <
m_kk-1; i++) {
3405 for (
size_t j = i+1; j <
m_kk; j++) {
3407 size_t n =
m_kk*i + j;
3419 d2FdT2 += molality[i]*molality[j] *
m_Phiprime_IJ[counterIJ];
3424 for (
size_t i = 1; i <
m_kk; i++) {
3434 for (
size_t j = 1; j <
m_kk; j++) {
3436 size_t n =
m_kk*i + j;
3441 sum1 += molality[j]*
3447 for (
size_t k = j+1; k <
m_kk; k++) {
3462 for (
size_t k = 1; k <
m_kk; k++) {
3471 sum4 += fabs(
charge(i)) *
3481 for (
size_t k = 1; k <
m_kk; k++) {
3487 if (zeta_LL != 0.0) {
3488 sum5 += molality[j]*molality[k]*zeta_LL;
3497 zsqd2FdT2 + sum1 + sum2 + sum3 + sum4 + sum5;
3509 for (
size_t j = 1; j <
m_kk; j++) {
3511 size_t n =
m_kk*i + j;
3516 sum1 += molality[j]*
3519 for (
size_t k = j+1; k <
m_kk; k++) {
3535 for (
size_t k = 1; k <
m_kk; k++) {
3543 sum4 += fabs(
charge(i)) *
3553 for (
size_t k = 1; k <
m_kk; k++) {
3560 if (zeta_LL != 0.0) {
3561 sum5 += molality[j]*molality[k]*zeta_LL;
3568 zsqd2FdT2 + sum1 + sum2 + sum3 + sum4 + sum5;
3577 for (
size_t j = 1; j <
m_kk; j++) {
3581 for (
size_t k = 1; k <
m_kk; k++) {
3589 double sum2 = 3.0 * molality[i] * molality[i] *
m_Mu_nnn_LL[i];
3608 double term1 = -d2AphidT2 * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
3610 for (
size_t j = 1; j <
m_kk; j++) {
3613 for (
size_t k = 1; k <
m_kk; k++) {
3616 size_t n =
m_kk*j + k;
3619 sum1 += molality[j]*molality[k] *
3624 for (
size_t k = j+1; k <
m_kk; k++) {
3625 if (j == (
m_kk-1)) {
3627 throw CanteraError(
"HMWSoln::s_updatePitzer_d2lnMolalityActCoeff_dT2",
3628 "logic error 1 in Step 9 of hmw_act");
3633 size_t n =
m_kk*j + k;
3636 for (
size_t m = 1; m <
m_kk; m++) {
3640 sum2 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_LL[n];
3649 for (
size_t k = j+1; k <
m_kk; k++) {
3652 throw CanteraError(
"HMWSoln::s_updatePitzer_d2lnMolalityActCoeff_dT2",
3653 "logic error 2 in Step 9 of hmw_act");
3658 size_t n =
m_kk*j + k;
3662 for (
size_t m = 1; m <
m_kk; m++) {
3665 sum3 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_LL[n];
3674 for (
size_t k = 1; k <
m_kk; k++) {
3684 }
else if (k == j) {
3690 for (
size_t m = 1; m <
m_kk; m++) {
3695 if (zeta_LL != 0.0) {
3696 sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_LL;
3703 sum7 += molality[j] * molality[j] * molality[j] *
m_Mu_nnn_LL[j];
3706 double sum_m_phi_minus_1 = 2.0 *
3707 (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
3710 double d2_osmotic_coef_dT2;
3711 if (molalitysum > 1.0E-150) {
3712 d2_osmotic_coef_dT2 = 0.0 + (sum_m_phi_minus_1 / molalitysum);
3714 d2_osmotic_coef_dT2 = 0.0;
3716 double d2_lnwateract_dT2 = -(
m_weightSolvent/1000.0) * molalitysum * d2_osmotic_coef_dT2;
3738 for (
size_t k = 1; k <
m_kk; k++) {
3756 double etheta[5][5], etheta_prime[5][5], sqrtIs;
3763 double molarcharge = 0.0;
3767 double molalitysum = 0.0;
3775 for (
size_t n = 1; n <
m_kk; n++) {
3779 molarcharge += fabs(
charge(n)) * molality[n];
3780 molalitysum += molality[n];
3794 for (
int z1 = 1; z1 <=4; z1++) {
3795 for (
int z2 =1; z2 <=4; z2++) {
3796 calc_thetas(z1, z2, ðeta[z1][z2], ðeta_prime[z1][z2]);
3803 for (
size_t i = 1; i < (
m_kk - 1); i++) {
3804 for (
size_t j = (i+1); j <
m_kk; j++) {
3806 size_t n =
m_kk*i + j;
3812 double x1 = sqrtIs * m_Alpha1MX_ij[counterIJ];
3813 if (x1 > 1.0E-100) {
3814 m_gfunc_IJ[counterIJ] = 2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
3816 (1.0-(1.0 + x1 + 0.5 * x1 * x1) * exp(-x1)) / (x1 * x1);
3824 if (x2 > 1.0E-100) {
3825 m_g2func_IJ[counterIJ] = 2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
3827 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
3843 for (
size_t i = 1; i <
m_kk - 1; i++) {
3844 for (
size_t j = i+1; j <
m_kk; j++) {
3846 size_t n =
m_kk*i + j;
3855 if (Is > 1.0E-150) {
3871 for (
size_t i = 1; i <
m_kk-1; i++) {
3872 for (
size_t j = i+1; j <
m_kk; j++) {
3874 size_t n =
m_kk*i + j;
3889 for (
size_t i = 1; i <
m_kk-1; i++) {
3890 for (
size_t j = i+1; j <
m_kk; j++) {
3892 size_t n =
m_kk*i + j;
3911 double dAphidP = dA_DebyedP /3.0;
3912 double dFdP = -dAphidP * (sqrt(Is) / (1.0 + 1.2*sqrt(Is))
3913 + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
3914 for (
size_t i = 1; i <
m_kk-1; i++) {
3915 for (
size_t j = i+1; j <
m_kk; j++) {
3917 size_t n =
m_kk*i + j;
3934 for (
size_t i = 1; i <
m_kk; i++) {
3944 for (
size_t j = 1; j <
m_kk; j++) {
3946 size_t n =
m_kk*i + j;
3951 sum1 += molality[j]*
3957 for (
size_t k = j+1; k <
m_kk; k++) {
3970 sum2 += molality[j]*(2.0*
m_Phi_IJ_P[counterIJ]);
3972 for (
size_t k = 1; k <
m_kk; k++) {
3981 sum4 += fabs(
charge(i)) *
3982 molality[j]*molality[k]*
m_CMX_IJ_P[counterIJ2];
3991 for (
size_t k = 1; k <
m_kk; k++) {
3997 if (zeta_P != 0.0) {
3998 sum5 += molality[j]*molality[k]*zeta_P;
4008 zsqdFdP + sum1 + sum2 + sum3 + sum4 + sum5;
4020 for (
size_t j = 1; j <
m_kk; j++) {
4022 size_t n =
m_kk*i + j;
4027 sum1 += molality[j] *
4030 for (
size_t k = j+1; k <
m_kk; k++) {
4044 sum2 += molality[j]*(2.0*
m_Phi_IJ_P[counterIJ]);
4046 for (
size_t k = 1; k <
m_kk; k++) {
4055 molality[j]*molality[k]*
m_CMX_IJ_P[counterIJ2];
4064 for (
size_t k = 1; k <
m_kk; k++) {
4071 if (zeta_P != 0.0) {
4072 sum5 += molality[j]*molality[k]*zeta_P;
4079 zsqdFdP + sum1 + sum2 + sum3 + sum4 + sum5;
4086 for (
size_t j = 1; j <
m_kk; j++) {
4090 for (
size_t k = 1; k <
m_kk; k++) {
4098 double sum2 = 3.0 * molality[i] * molality[i] *
m_Mu_nnn_P[i];
4117 double term1 = -dAphidP * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
4119 for (
size_t j = 1; j <
m_kk; j++) {
4122 for (
size_t k = 1; k <
m_kk; k++) {
4125 size_t n =
m_kk*j + k;
4127 sum1 += molality[j]*molality[k]*
4132 for (
size_t k = j+1; k <
m_kk; k++) {
4133 if (j == (
m_kk-1)) {
4135 throw CanteraError(
"HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dP",
4136 "logic error 1 in Step 9 of hmw_act");
4141 size_t n =
m_kk*j + k;
4144 for (
size_t m = 1; m <
m_kk; m++) {
4148 sum2 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_P[n];
4157 for (
size_t k = j+1; k <
m_kk; k++) {
4160 throw CanteraError(
"HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dP",
4161 "logic error 2 in Step 9 of hmw_act");
4166 size_t n =
m_kk*j + k;
4170 for (
size_t m = 1; m <
m_kk; m++) {
4173 sum3 += molality[j]*molality[k]*molality[m]*
m_Psi_ijk_P[n];
4182 for (
size_t k = 1; k <
m_kk; k++) {
4192 }
else if (k == j) {
4198 for (
size_t m = 1; m <
m_kk; m++) {
4203 if (zeta_P != 0.0) {
4204 sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_P;
4211 sum7 += molality[j] * molality[j] * molality[j] *
m_Mu_nnn_P[j];
4214 double sum_m_phi_minus_1 = 2.0 *
4215 (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
4219 double d_osmotic_coef_dP;
4220 if (molalitysum > 1.0E-150) {
4221 d_osmotic_coef_dP = 0.0 + (sum_m_phi_minus_1 / molalitysum);
4223 d_osmotic_coef_dP = 0.0;
4225 double d_lnwateract_dP = -(
m_weightSolvent/1000.0) * molalitysum * d_osmotic_coef_dP;
4238 if( m_last_is == is ) {
4245 double c1 = 4.581, c2 = 0.7237, c3 = 0.0120, c4 = 0.528;
4246 double aphi = 0.392;
4247 if (is < 1.0E-150) {
4248 for (
int i = 0; i < 17; i++) {
4257 for (
int i=1; i<=4; i++) {
4258 for (
int j=i; j<=4; j++) {
4262 double zprod = (double)ij;
4265 double x = 6.0* zprod * aphi * sqrt(is);
4267 double jfunc = x / (4.0 + c1*pow(x,-c2)*exp(-c3*pow(x,c4)));
4269 double t = c3 * c4 * pow(x,c4);
4270 double dj = c1* pow(x,(-c2-1.0)) * (c2+t) * exp(-c3*pow(x,c4));
4271 double jprime = (jfunc/x)*(1.0 + jfunc*dj);
4273 elambda[ij] = zprod*jfunc / (4.0*is);
4274 elambda1[ij] = (3.0*zprod*zprod*aphi*jprime/(4.0*sqrt(is))
4281 double* etheta,
double* etheta_prime)
const
4288 "we shouldn't be here");
4290 "called with one species being neutral");
4296 *etheta_prime = 0.0;
4299 double f1 = (double)i / (2.0 * j);
4300 double f2 = (double)j / (2.0 * i);
4315 for (
size_t k = 1; k <
m_kk; k++) {
4322 double eterm = std::exp(-xoverc);
4324 double fptmp = IMS_bfCut_ - IMS_afCut_ /
IMS_cCut_ - IMS_bfCut_*xoverc
4325 + 2.0*IMS_dfCut_*xmolSolvent - IMS_dfCut_*xmolSolvent*xoverc;
4326 double f_prime = 1.0 + eterm*fptmp;
4327 double f = xmolSolvent + IMS_efCut_
4328 + eterm * (IMS_afCut_ + xmolSolvent * (IMS_bfCut_ + IMS_dfCut_*xmolSolvent));
4330 double gptmp = IMS_bgCut_ - IMS_agCut_ /
IMS_cCut_ - IMS_bgCut_*xoverc
4331 + 2.0*IMS_dgCut_*xmolSolvent - IMS_dgCut_*xmolSolvent*xoverc;
4332 double g_prime = 1.0 + eterm*gptmp;
4333 double g = xmolSolvent + IMS_egCut_
4334 + eterm * (IMS_agCut_ + xmolSolvent * (IMS_bgCut_ + IMS_dgCut_*xmolSolvent));
4336 double tmp = (xmolSolvent / g * g_prime + (1.0 - xmolSolvent) / f * f_prime);
4337 double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
4338 double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
4340 tmp = log(xx) + lngammak;
4341 for (
size_t k = 1; k <
m_kk; k++) {
4358 writelog(
"Index Name MoleF MolalityCropped Charge\n");
4359 for (
size_t k = 0; k <
m_kk; k++) {
4360 writelogf(
"%2d %-16s %14.7le %14.7le %5.1f \n",
4364 writelog(
"\n Species Species beta0MX "
4365 "beta1MX beta2MX CphiMX alphaMX thetaij\n");
4366 for (
size_t i = 1; i <
m_kk - 1; i++) {
4367 for (
size_t j = i+1; j <
m_kk; j++) {
4368 size_t n = i *
m_kk + j;
4370 writelogf(
" %-16s %-16s %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f \n",
4378 writelog(
"\n Species Species Species psi \n");
4379 for (
size_t i = 1; i <
m_kk; i++) {
4380 for (
size_t j = 1; j <
m_kk; j++) {
4381 for (
size_t k = 1; k <
m_kk; k++) {
4384 writelogf(
" %-16s %-16s %-16s %9.5f \n",
4401 doublereal afac = -1.0 *(lnGammaClMs2 - lnGammaCLMs1);
4402 for (
size_t k = 0; k <
m_kk; k++) {
4403 acMolality[k] *= exp(
charge(k) * afac);
4416 doublereal afac = -1.0 *(lnGammaClMs2 - lnGammaCLMs1);
4417 for (
size_t k = 0; k <
m_kk; k++) {
4431 doublereal afac = -1.0 *(dlnGammaClM_dT_s2 - dlnGammaCLM_dT_s1);
4432 for (
size_t k = 0; k <
m_kk; k++) {
4446 doublereal afac = -1.0 *(d2lnGammaClM_dT2_s2 - d2lnGammaCLM_dT2_s1);
4447 for (
size_t k = 0; k <
m_kk; k++) {
4461 doublereal afac = -1.0 *(dlnGammaClM_dP_s2 - dlnGammaCLM_dP_s1);
4462 for (
size_t k = 0; k <
m_kk; k++) {
4471 doublereal lnGammaClMs2 = - A * sqrtIs /(1.0 + 1.5 * sqrtIs);
4472 return lnGammaClMs2;
4479 return - dAdT * sqrtIs /(1.0 + 1.5 * sqrtIs);
4486 return - d2AdT2 * sqrtIs /(1.0 + 1.5 * sqrtIs);
4493 return - dAdP * sqrtIs /(1.0 + 1.5 * sqrtIs);
Headers for the HMWSoln ThermoPhase object, which models concentrated electrolyte solutions (see Ther...
Implementation of a pressure dependent standard state virtual function for a Pure Water Phase (see Sp...
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.
size_t size() const
Returns the number of elements in this map.
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
doublereal * ptrColumn(size_t j)
Return a pointer to the top of column j, columns are contiguous in memory.
void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
Base class for exceptions thrown by Cantera classes.
vector_fp m_CMX_IJ_P
Derivative of m_CMX_IJ wrt P. Vector index is counterIJ.
void calcIMSCutoffParams_()
Precalculate the IMS Cutoff parameters for typeCutoff = 2.
Array2D m_Theta_ij_coeff
Array of coefficients for Theta_ij[i][j] in the Pitzer/HMW formulation.
vector_fp m_BphiMX_IJ_P
Derivative of BphiMX_IJ wrt P. Vector index is counterIJ.
doublereal MC_X_o_cutoff_
value of the solvent mole fraction that centers the cutoff polynomials for the cutoff =1 process;
virtual void applyphScale(doublereal *acMolality) const
Apply the current phScale to a set of activity Coefficients or activities.
Array2D m_Beta0MX_ij_coeff
Array of coefficients for Beta0, a variable in Pitzer's papers.
vector_fp m_PhiPhi_IJ
Intermediate variable called PhiPhi in Pitzer's paper.
vector_fp m_Theta_ij_L
Derivative of Theta_ij[i][j] wrt T. Vector index is counterIJ.
vector_fp m_BMX_IJ_L
Derivative of BMX_IJ wrt T. Vector index is counterIJ.
vector_fp m_BMX_IJ_P
Derivative of BMX_IJ wrt P. Vector index is counterIJ.
double m_A_Debye
A_Debye: this expression appears on the top of the ln actCoeff term in the general Debye-Huckel expre...
void readXMLLambdaNeutral(XML_Node &BinSalt)
Process an XML node called "lambdaNeutral".
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_fp m_Phi_IJ_LL
Derivative of m_Phi_IJ wrt TT. Vector index is counterIJ.
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
vector_fp m_Beta0MX_ij_P
Derivative of Beta0_ij[i][j] wrt P. Vector index is counterIJ.
Array2D m_Lambda_nj_P
Derivative of Lambda_nj[i][j] wrt P.
void s_updateScaling_pHScaling_dT() const
Apply the current phScale to a set of derivatives of the activity Coefficients wrt temperature.
double m_IionicMolality
Current value of the ionic strength on the molality scale Associated Salts, if present in the mechani...
vector_fp m_PhiPhi_IJ_L
Derivative of m_PhiPhi_IJ wrt T. Vector index is counterIJ.
void calcMCCutoffParams_()
Calculate molality cut-off parameters.
vector_fp m_dlnActCoeffMolaldT_Scaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt T.
Array2D m_Beta2MX_ij_coeff
Array of coefficients for Beta2, a variable in Pitzer's papers.
vector_fp m_BphiMX_IJ_LL
Derivative of BphiMX_IJ wrt TT. Vector index is counterIJ.
HMWSoln(const std::string &inputFile="", const std::string &id="")
Construct and initialize an HMWSoln ThermoPhase object directly from an ASCII input file.
void s_update_d2lnMolalityActCoeff_dT2() const
This function calculates the temperature second derivative of the natural logarithm of the molality a...
doublereal IMS_cCut_
Parameter in the polyExp cutoff treatment having to do with rate of exp decay.
doublereal IMS_slopegCut_
Parameter in the polyExp cutoff treatment.
int m_form_A_Debye
Form of the constant outside the Debye-Huckel term called A.
void getUnscaledMolalityActivityCoefficients(doublereal *acMolality) const
Get the array of unscaled non-dimensional molality based activity coefficients at the current solutio...
vector_int CROP_speciesCropped_
This is a boolean-type vector indicating whether a species's activity coefficient is in the cropped r...
vector_fp m_Psi_ijk_L
Derivative of Psi_ijk[n] wrt T.
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
vector_fp m_Phiprime_IJ
Intermediate variable called Phiprime in Pitzer's paper.
doublereal s_NBS_CLM_dlnMolalityActCoeff_dP() const
Calculate the pressure derivative of the Chlorine activity coefficient.
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
vector_fp m_Beta1MX_ij
Array of 2D data used in the Pitzer/HMW formulation.
vector_fp m_lnActCoeffMolal_Unscaled
Logarithm of the activity coefficients on the molality scale.
Array2D m_Lambda_nj_L
Derivative of Lambda_nj[i][j] wrt T. see m_Lambda_ij.
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Initialize the phase parameters from an XML file.
vector_fp m_BprimeMX_IJ_P
Derivative of BprimeMX wrt P. Vector index is counterIJ.
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
vector_fp m_h2func_IJ
hfunc2, was called gprime in Pitzer's paper.
vector_fp m_Alpha2MX_ij
Array of 2D data used in the Pitzer/HMW formulation.
doublereal IMS_X_o_cutoff_
value of the solute mole fraction that centers the cutoff polynomials for the cutoff =1 process;
vector_fp m_Psi_ijk_P
Derivative of Psi_ijk[n] wrt P.
virtual void getPartialMolarVolumes(doublereal *vbar) const
Return an array of partial molar volumes for the species in the mixture.
vector_fp m_dlnActCoeffMolaldT_Unscaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt T.
doublereal s_NBS_CLM_dlnMolalityActCoeff_dT() const
Calculate the temperature derivative of the Chlorine activity coefficient on the NBS scale.
vector_fp m_PhiPhi_IJ_LL
Derivative of m_PhiPhi_IJ wrt TT. Vector index is counterIJ.
vector_fp m_CMX_IJ_L
Derivative of m_CMX_IJ wrt T. Vector index is counterIJ.
void s_updateScaling_pHScaling_dP() const
Apply the current phScale to a set of derivatives of the activity Coefficients wrt pressure.
void printCoeffs() const
Print out all of the input Pitzer coefficients.
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized activity concentrations.
vector_fp m_BphiMX_IJ
Intermediate variable called BphiMX in Pitzer's paper.
void s_update_dlnMolalityActCoeff_dT() const
This function calculates the temperature derivative of the natural logarithm of the molality activity...
vector_fp m_CphiMX_ij
Array of 2D data used in the Pitzer/HMW formulation.
vector_fp m_CphiMX_ij_L
Derivative of Cphi_ij[i][j] wrt T. Vector index is counterIJ.
double ADebye_V(double temperature=-1.0, double pressure=-1.0) const
Return Pitzer's definition of A_V.
vector_fp m_Beta0MX_ij_L
Derivative of Beta0_ij[i][j] wrt T. Vector index is counterIJ.
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
vector_fp m_Phi_IJ_P
Derivative of m_Phi_IJ wrt P. Vector index is counterIJ.
void counterIJ_setup() const
Set up a counter variable for keeping track of symmetric binary interactions amongst the solute speci...
vector_fp m_hfunc_IJ
hfunc, was called gprime in Pitzer's paper.
vector_fp m_Theta_ij_P
Derivative of Theta_ij[i][j] wrt P. Vector index is counterIJ.
vector_fp m_Beta1MX_ij_LL
Derivative of Beta1_ij[i][j] wrt TT. Vector index is counterIJ.
vector_fp m_Mu_nnn
Mu coefficient for the self-ternary neutral coefficient.
vector_fp m_d2lnActCoeffMolaldT2_Scaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt TT.
Array2D m_Psi_ijk_coeff
Array of coefficients for Psi_ijk[n] in the Pitzer/HMW formulation.
void readXMLZetaCation(const XML_Node &BinSalt)
Process an XML node called "zetaCation".
vector_fp m_CphiMX_ij_LL
Derivative of Cphi_ij[i][j] wrt TT. Vector index is counterIJ.
vector_fp m_Beta2MX_ij_L
Derivative of Beta2_ij[i][j] wrt T. Vector index is counterIJ.
void readXMLPsi(XML_Node &BinSalt)
Process an XML node called "psiCommonAnion" or "psiCommonCation".
void setA_Debye(double A)
Set the A_Debye parameter.
int m_formPitzerTemp
This is the form of the temperature dependence of Pitzer parameterization used in the model.
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
vector_fp m_Mu_nnn_LL
Mu coefficient 2nd temperature derivative for the self-ternary neutral coefficient.
vector_fp m_BMX_IJ_LL
Derivative of BMX_IJ wrt TT. Vector index is counterIJ.
void s_updatePitzer_CoeffWRTemp(int doDerivs=2) const
Calculates the Pitzer coefficients' dependence on the temperature.
vector_fp m_molalitiesCropped
Cropped and modified values of the molalities used in activity coefficient calculations.
vector_fp m_Psi_ijk_LL
Derivative of Psi_ijk[n] wrt TT.
doublereal s_NBS_CLM_d2lnMolalityActCoeff_dT2() const
Calculate the second temperature derivative of the Chlorine activity coefficient on the NBS scale.
virtual void initThermo()
void s_updatePitzer_dlnMolalityActCoeff_dP() const
Calculates the Pressure derivative of the natural logarithm of the molality activity coefficients.
vector_fp m_Beta2MX_ij_P
Derivative of Beta2_ij[i][j] wrt P. Vector index is counterIJ.
Array2D m_Lambda_nj
Lambda coefficient for the ij interaction.
vector_fp m_Phi_IJ
Intermediate variable called Phi in Pitzer's paper.
vector_fp m_Beta2MX_ij
Array of 2D data used in the Pitzer/HMW formulation.
vector_fp m_BprimeMX_IJ_L
Derivative of BprimeMX wrt T. Vector index is counterIJ.
vector_fp m_PhiPhi_IJ_P
Derivative of m_PhiPhi_IJ wrt P. Vector index is counterIJ.
void calc_thetas(int z1, int z2, double *etheta, double *etheta_prime) const
Calculate etheta and etheta_prime.
vector_fp m_Beta2MX_ij_LL
Derivative of Beta2_ij[i][j] wrt TT. Vector index is counterIJ.
vector_fp m_d2lnActCoeffMolaldT2_Unscaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt TT.
Array2D m_Mu_nnn_coeff
Array of coefficients form_Mu_nnn term.
double ADebye_L(double temperature=-1.0, double pressure=-1.0) const
Return Pitzer's definition of A_L.
vector_fp m_Mu_nnn_P
Mu coefficient pressure derivative for the self-ternary neutral coefficient.
vector_fp m_CMX_IJ
Intermediate variable called CMX in Pitzer's paper.
PDSS * m_waterSS
Water standard state calculator.
void calc_lambdas(double is) const
Calculate the lambda interactions.
double elambda1[17]
This is elambda1, MEC.
virtual doublereal relative_molal_enthalpy() const
Excess molar enthalpy of the solution from the mixing process on a molality basis.
vector_fp m_Phi_IJ_L
Derivative of m_Phi_IJ wrt T. Vector index is counterIJ.
vector_fp m_Theta_ij_LL
Derivative of Theta_ij[i][j] wrt TT. Vector index is counterIJ.
double m_maxIionicStrength
Maximum value of the ionic strength allowed in the calculation of the activity coefficients.
vector_fp m_BphiMX_IJ_L
Derivative of BphiMX_IJ wrt T. Vector index is counterIJ.
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
vector_fp m_dlnActCoeffMolaldP_Unscaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt P.
vector_fp m_BprimeMX_IJ_LL
Derivative of BprimeMX wrt TT. Vector index is counterIJ.
vector_fp IMS_lnActCoeffMolal_
Logarithm of the molal activity coefficients.
void s_updatePitzer_dlnMolalityActCoeff_dT() const
Calculates the temperature derivative of the natural logarithm of the molality activity coefficients.
void s_updatePitzer_lnMolalityActCoeff() const
Calculate the Pitzer portion of the activity coefficients.
vector_fp m_CMX_IJ_LL
Derivative of m_CMX_IJ wrt TT. Vector index is counterIJ.
vector_fp m_gamma_tmp
Intermediate storage of the activity coefficient itself.
vector_fp m_Psi_ijk
Array of 3D data used in the Pitzer/HMW formulation.
void readXMLMunnnNeutral(XML_Node &BinSalt)
Process an XML node called "MunnnNeutral".
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 as a function of tem...
virtual doublereal relative_enthalpy() const
Excess molar enthalpy of the solution from the mixing process.
vector_fp m_Beta1MX_ij_P
Derivative of Beta1_ij[i][j] wrt P. Vector index is counterIJ.
vector_fp m_Mu_nnn_L
Mu coefficient temperature derivative for the self-ternary neutral coefficient.
Array2D m_Lambda_nj_LL
Derivative of Lambda_nj[i][j] wrt TT.
void s_updatePitzer_d2lnMolalityActCoeff_dT2() const
This function calculates the temperature second derivative of the natural logarithm of the molality a...
void readXMLTheta(XML_Node &BinSalt)
Process an XML node called "thetaAnion" or "thetaCation".
Array2D m_Lambda_nj_coeff
Array of coefficients for Lambda_nj[i][j] in the Pitzer/HMW formulation.
vector_fp m_Theta_ij
Array of 2D data for Theta_ij[i][j] in the Pitzer/HMW formulation.
void initLengths()
Initialize all of the species-dependent lengths in the object.
vector_fp m_Beta0MX_ij
Array of 2D data used in the Pitzer/HMW formulation.
vector_fp m_BMX_IJ
Intermediate variable called BMX in Pitzer's paper.
vector_fp m_Beta0MX_ij_LL
Derivative of Beta0_ij[i][j] wrt TT. Vector index is counterIJ.
vector_fp m_gfunc_IJ
Various temporary arrays used in the calculation of the Pitzer activity coefficients.
void s_update_dlnMolalityActCoeff_dP() const
This function calculates the pressure derivative of the natural logarithm of the molality activity co...
double m_TempPitzerRef
Reference Temperature for the Pitzer formulations.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
vector_fp m_Beta1MX_ij_L
Derivative of Beta1_ij[i][j] wrt T. Vector index is counterIJ.
void readXMLBinarySalt(XML_Node &BinSalt)
Process an XML node called "binarySaltParameters".
virtual doublereal satPressure(doublereal T)
Get the saturation pressure for a given temperature.
double elambda[17]
This is elambda, MEC.
std::unique_ptr< WaterProps > m_waterProps
Pointer to the water property calculator.
vector_fp m_BprimeMX_IJ
Intermediate variable called BprimeMX in Pitzer's paper.
void s_updateIMS_lnMolalityActCoeff() const
This function will be called to update the internally stored natural logarithm of the molality activi...
void calcMolalitiesCropped() const
Calculate the cropped molalities.
virtual void getActivities(doublereal *ac) const
Get the array of non-dimensional activities at the current solution temperature, pressure,...
vector_fp m_CphiMX_ij_P
Derivative of Cphi_ij[i][j] wrt P. Vector index is counterIJ.
vector_fp m_tmpV
vector of size m_kk, used as a temporary holding area.
double ADebye_J(double temperature=-1.0, double pressure=-1.0) const
Return Pitzer's definition of A_J.
void s_updateScaling_pHScaling_dT2() const
Apply the current phScale to a set of 2nd derivatives of the activity Coefficients wrt temperature.
Array2D m_Beta1MX_ij_coeff
Array of coefficients for Beta1, a variable in Pitzer's papers.
doublereal s_NBS_CLM_lnMolalityActCoeff() const
Calculate the Chlorine activity coefficient on the NBS scale.
void s_updateScaling_pHScaling() const
Apply the current phScale to a set of activity Coefficients.
Array2D m_CphiMX_ij_coeff
Array of coefficients for CphiMX, a parameter in the activity coefficient formulation.
vector_fp m_g2func_IJ
This is the value of g2(x2) in Pitzer's papers. Vector index is counterIJ.
virtual double A_Debye_TP(double temperature=-1.0, double pressure=-1.0) const
Value of the Debye Huckel constant as a function of temperature and pressure.
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...
void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input.
vector_fp m_dlnActCoeffMolaldP_Scaled
Derivative of the Logarithm of the activity coefficients on the molality scale wrt P.
vector_int m_CounterIJ
a counter variable for keeping track of symmetric binary interactions amongst the solute species.
vector_fp m_lnActCoeffMolal_Scaled
Logarithm of the activity coefficients on the molality scale.
bool m_molalitiesAreCropped
Boolean indicating whether the molalities are cropped or are modified.
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
size_t m_indexCLM
Index of the phScale species.
void setMoleFSolventMin(doublereal xmolSolventMIN)
Sets the minimum mole fraction in the molality formulation.
virtual void initThermo()
doublereal m_xmolSolventMIN
int m_pHScalingType
Scaling to be used for output of single-ion species activity coefficients.
doublereal m_Mnaught
This is the multiplication factor that goes inside log expressions involving the molalities of specie...
void calcMolalities() const
Calculates the molality of all species and stores the result internally.
vector_fp m_molalities
Current value of the molalities of the species in the phase.
doublereal m_weightSolvent
Molecular weight of the Solvent.
Class for the liquid water pressure dependent standard state.
virtual void setState_TP(doublereal temp, doublereal pres)
Set the internal temperature and pressure.
virtual doublereal satPressure(doublereal T)
saturation pressure
void assignDensity(const double density_)
Set the internally stored constant density (kg/m^3) of the phase.
virtual void setMoleFractions(const double *const x)
Set the mole fractions to the specified values.
doublereal mean_X(const doublereal *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
ValueCache m_cache
Cached for saved calculations within each ThermoPhase.
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
size_t m_kk
Number of species in the phase.
std::string speciesName(size_t k) const
Name of the species with index k.
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
int stateMFNumber() const
Return the State Mole Fraction Number.
doublereal temperature() const
Temperature (K).
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
double molarVolume() const
Molar volume (m^3/kmol).
shared_ptr< Species > species(const std::string &name) const
Return the Species object for the named species.
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
virtual doublereal isothermalCompressibility() const
Returns the isothermal compressibility. Units: 1/Pa.
void initThermoFile(const std::string &inputFile, const std::string &id)
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
virtual doublereal thermalExpansionCoeff() const
Return the volumetric thermal expansion coefficient. Units: 1/K.
AnyMap m_input
Data supplied via setParameters.
virtual void getParameters(int &n, doublereal *const c) const
Get the equation of state parameters in a vector.
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of the species standard states at the current T and P of the solution.
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the species standard states at the cu...
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Entropy functions for the standard state species at the current T and...
virtual doublereal pressure() const
Returns the current pressure of the phase.
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity for the species at their standard states at the...
virtual void updateStandardStateThermo() const
Updates the standard state thermodynamic functions at the current T and P of the solution.
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
CachedScalar getScalar(int id)
Get a reference to a CachedValue object representing a scalar (doublereal) with the given id.
int getId()
Get a unique id for a cached value.
The WaterProps class is used to house several approximation routines for properties of water.
Class XML_Node is a tree-based representation of the contents of an XML file.
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
std::string name() const
Returns the name of the XML node.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
std::string id() const
Return the id attribute, if present.
const std::vector< XML_Node * > & children() const
Return an unchangeable reference to the vector of children of the current node.
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
Header file for a common definitions used in electrolytes thermodynamics.
#define AssertTrace(expr)
Assertion must be true or an error is thrown.
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
void writelog(const std::string &fmt, const Args &... args)
Write a formatted message to the screen.
void writelogf(const char *fmt, const Args &... args)
Write a formatted message to the screen.
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type="")
Get a floating-point value from a child element.
bool getOptionalFloat(const XML_Node &parent, const std::string &name, doublereal &fltRtn, const std::string &type="")
Get an optional floating-point value from a child element.
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
const int PHSCALE_PITZER
Scale to be used for the output of single-ion activity coefficients is that used by Pitzer.
const double SmallNumber
smallest number to compare to zero.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
const double GasConstant
Universal Gas Constant [J/kmol/K].
size_t getFloatArray(const XML_Node &node, vector_fp &v, const bool convert=true, const std::string &unitsString="", const std::string &nodeName="floatArray")
This function reads the current node or a child node of the current node with the default name,...
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
const int PHSCALE_NBS
Scale to be used for evaluation of single-ion activity coefficients is that used by the NBS standard ...
int sign(T x)
Sign of a number. Returns -1 if x < 0, 1 if x > 0 and 0 if x == 0.
Contains declarations for string manipulation functions within Cantera.
T value
The value of the cached property.
bool validate(double state1New)
Check whether the currently cached value is valid based on a single state variable.