20 RedlichKisterVPSSTP::RedlichKisterVPSSTP(
const string& inputFile,
const string& id_)
22 initThermoFile(inputFile, id_);
27 void RedlichKisterVPSSTP::getLnActivityCoefficients(
double* lnac)
const
30 s_update_lnActCoeff();
32 for (
size_t k = 0; k < m_kk; k++) {
33 lnac[k] = lnActCoeff_Scaled_[k];
39 void RedlichKisterVPSSTP::getChemPotentials(
double* mu)
const
43 getStandardChemPotentials(mu);
45 s_update_lnActCoeff();
47 for (
size_t k = 0; k < m_kk; k++) {
48 double xx = std::max(moleFractions_[k],
SmallNumber);
49 mu[k] += RT() * (log(xx) + lnActCoeff_Scaled_[k]);
53 double RedlichKisterVPSSTP::enthalpy_mole()
const
56 vector<double> hbar(m_kk);
57 getPartialMolarEnthalpies(&hbar[0]);
58 for (
size_t i = 0; i < m_kk; i++) {
59 h += moleFractions_[i]*hbar[i];
64 double RedlichKisterVPSSTP::entropy_mole()
const
67 vector<double> sbar(m_kk);
68 getPartialMolarEntropies(&sbar[0]);
69 for (
size_t i = 0; i < m_kk; i++) {
70 s += moleFractions_[i]*sbar[i];
75 double RedlichKisterVPSSTP::cp_mole()
const
78 vector<double> cpbar(m_kk);
79 getPartialMolarCp(&cpbar[0]);
80 for (
size_t i = 0; i < m_kk; i++) {
81 cp += moleFractions_[i]*cpbar[i];
86 double RedlichKisterVPSSTP::cv_mole()
const
91 void RedlichKisterVPSSTP::getPartialMolarEnthalpies(
double* hbar)
const
96 double T = temperature();
97 for (
size_t k = 0; k < m_kk; k++) {
103 s_update_lnActCoeff();
104 s_update_dlnActCoeff_dT();
105 for (
size_t k = 0; k < m_kk; k++) {
106 hbar[k] -=
GasConstant * T * T * dlnActCoeffdT_Scaled_[k];
110 void RedlichKisterVPSSTP::getPartialMolarCp(
double* cpbar)
const
114 for (
size_t k = 0; k < m_kk; k++) {
119 void RedlichKisterVPSSTP::getPartialMolarEntropies(
double* sbar)
const
123 double T = temperature();
127 s_update_lnActCoeff();
128 s_update_dlnActCoeff_dT();
130 for (
size_t k = 0; k < m_kk; k++) {
131 double xx = std::max(moleFractions_[k],
SmallNumber);
132 sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
135 for (
size_t k = 0; k < m_kk; k++) {
140 void RedlichKisterVPSSTP::getPartialMolarVolumes(
double* vbar)
const
143 getStandardVolumes(vbar);
144 for (
size_t iK = 0; iK < m_kk; iK++) {
149 void RedlichKisterVPSSTP::initThermo()
151 if (m_input.hasKey(
"interactions")) {
152 for (
const auto& item : m_input[
"interactions"].asVector<AnyMap>()) {
153 auto& species = item[
"species"].asVector<
string>(2);
154 vector<double> h_excess = item.convertVector(
"excess-enthalpy",
"J/kmol");
155 vector<double> s_excess = item.convertVector(
"excess-entropy",
"J/kmol/K");
156 addBinaryInteraction(species[0], species[1],
157 h_excess.data(), h_excess.size(),
158 s_excess.data(), s_excess.size());
162 GibbsExcessVPSSTP::initThermo();
165 void RedlichKisterVPSSTP::getParameters(
AnyMap& phaseNode)
const
167 GibbsExcessVPSSTP::getParameters(phaseNode);
168 vector<AnyMap> interactions;
169 for (
size_t n = 0; n < m_pSpecies_A_ij.size(); n++) {
171 interaction[
"species"] = vector<string>{
172 speciesName(m_pSpecies_A_ij[n]), speciesName(m_pSpecies_B_ij[n])};
173 vector<double> h = m_HE_m_ij[n];
174 vector<double> s = m_SE_m_ij[n];
175 while (h.size() > 1 && h.back() == 0) {
178 while (s.size() > 1 && s.back() == 0) {
181 interaction[
"excess-enthalpy"].setQuantity(std::move(h),
"J/kmol");
182 interaction[
"excess-entropy"].setQuantity(std::move(s),
"J/kmol/K");
183 interactions.push_back(std::move(interaction));
185 phaseNode[
"interactions"] = std::move(interactions);
188 void RedlichKisterVPSSTP::initLengths()
190 dlnActCoeffdlnN_.resize(m_kk, m_kk);
193 void RedlichKisterVPSSTP::s_update_lnActCoeff()
const
195 double T = temperature();
196 lnActCoeff_Scaled_.assign(m_kk, 0.0);
202 for (
size_t i = 0; i < m_HE_m_ij.size(); i++) {
203 size_t iA = m_pSpecies_A_ij[i];
204 size_t iB = m_pSpecies_B_ij[i];
205 double XA = moleFractions_[iA];
206 double XB = moleFractions_[iB];
207 double deltaX = XA - XB;
208 const vector<double>& he_vec = m_HE_m_ij[i];
209 const vector<double>& se_vec = m_SE_m_ij[i];
211 double polyMm1 = 1.0;
215 for (
size_t m = 0; m < he_vec.size(); m++) {
216 double A_ge = (he_vec[m] - T * se_vec[m]) / (
GasConstant * T);
218 sum2 += A_ge * (m + 1) * poly;
221 sumMm1 += (A_ge * polyMm1 * m);
225 double oneMXA = 1.0 - XA;
226 double oneMXB = 1.0 - XB;
227 for (
size_t k = 0; k < m_kk; k++) {
229 lnActCoeff_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
230 }
else if (iB == k) {
231 lnActCoeff_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
233 lnActCoeff_Scaled_[k] += -(XA * XB * sum2);
240 void RedlichKisterVPSSTP::s_update_dlnActCoeff_dT()
const
242 double T = temperature();
243 dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
245 for (
size_t i = 0; i < m_HE_m_ij.size(); i++) {
246 size_t iA = m_pSpecies_A_ij[i];
247 size_t iB = m_pSpecies_B_ij[i];
248 double XA = moleFractions_[iA];
249 double XB = moleFractions_[iB];
250 double deltaX = XA - XB;
253 const vector<double>& he_vec = m_HE_m_ij[i];
255 double polyMm1 = 1.0;
257 for (
size_t m = 0; m < he_vec.size(); m++) {
260 sum2 += h_e * (m + 1) * poly;
263 sumMm1 += (h_e * polyMm1 * m);
267 double oneMXA = 1.0 - XA;
268 double oneMXB = 1.0 - XB;
269 for (
size_t k = 0; k < m_kk; k++) {
271 dlnActCoeffdT_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
272 }
else if (iB == k) {
273 dlnActCoeffdT_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
275 dlnActCoeffdT_Scaled_[k] += -(XA * XB * sum2);
280 for (
size_t k = 0; k < m_kk; k++) {
281 d2lnActCoeffdT2_Scaled_[k] = -2 / T * dlnActCoeffdT_Scaled_[k];
285 void RedlichKisterVPSSTP::getdlnActCoeffdT(
double* dlnActCoeffdT)
const
287 s_update_dlnActCoeff_dT();
288 for (
size_t k = 0; k < m_kk; k++) {
289 dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
293 void RedlichKisterVPSSTP::getd2lnActCoeffdT2(
double* d2lnActCoeffdT2)
const
295 s_update_dlnActCoeff_dT();
296 for (
size_t k = 0; k < m_kk; k++) {
297 d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k];
301 void RedlichKisterVPSSTP::s_update_dlnActCoeff_dlnX_diag()
const
303 double T = temperature();
304 dlnActCoeffdlnX_diag_.assign(m_kk, 0.0);
306 for (
size_t i = 0; i < m_HE_m_ij.size(); i++) {
307 size_t iA = m_pSpecies_A_ij[i];
308 size_t iB = m_pSpecies_B_ij[i];
309 double XA = moleFractions_[iA];
310 double XB = moleFractions_[iB];
311 double deltaX = XA - XB;
314 const vector<double>& he_vec = m_HE_m_ij[i];
315 const vector<double>& se_vec = m_SE_m_ij[i];
317 double polyMm1 = 1.0;
318 double polyMm2 = 1.0;
320 for (
size_t m = 0; m < he_vec.size(); m++) {
321 double A_ge = (he_vec[m] - T * se_vec[m]) / (
GasConstant * T);;
325 sumMm1 += (A_ge * polyMm1 * m);
329 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
334 for (
size_t k = 0; k < m_kk; k++) {
336 dlnActCoeffdlnX_diag_[k] +=
337 XA * (- (1-XA+XB) * sum + 2*(1.0 - XA) * XB * sumMm1
338 + sumMm1 * (XB * (1 - 2*XA + XB) - XA * (1 - XA + 2*XB))
339 + 2 * XA * XB * sumMm2 * (1.0 - XA + XB));
340 }
else if (iB == k) {
341 dlnActCoeffdlnX_diag_[k] +=
342 XB * (- (1-XB+XA) * sum - 2*(1.0 - XB) * XA * sumMm1
343 + sumMm1 * (XA * (2*XB - XA - 1) - XB * (-2*XA + XB - 1))
344 - 2 * XA * XB * sumMm2 * (-XA - 1 + XB));
350 void RedlichKisterVPSSTP::s_update_dlnActCoeff_dX_()
const
352 double T = temperature();
353 dlnActCoeff_dX_.zero();
355 for (
size_t i = 0; i < m_HE_m_ij.size(); i++) {
356 size_t iA = m_pSpecies_A_ij[i];
357 size_t iB = m_pSpecies_B_ij[i];
358 double XA = moleFractions_[iA];
359 double XB = moleFractions_[iB];
360 double deltaX = XA - XB;
363 const vector<double>& he_vec = m_HE_m_ij[i];
364 const vector<double>& se_vec = m_SE_m_ij[i];
366 double polyMm1 = 1.0;
367 double polyMm2 = 1.0;
369 double sum2Mm1 = 0.0;
371 for (
size_t m = 0; m < he_vec.size(); m++) {
372 double A_ge = he_vec[m] - T * se_vec[m];
374 sum2 += A_ge * (m + 1) * poly;
377 sumMm1 += (A_ge * polyMm1 * m);
378 sum2Mm1 += (A_ge * polyMm1 * m * (1.0 + m));
382 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
387 for (
size_t k = 0; k < m_kk; k++) {
389 dlnActCoeff_dX_(k, iA) += (- XB * sum + (1.0 - XA) * XB * sumMm1
390 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
391 + XA * XB * sumMm2 * (1.0 - XA + XB));
393 dlnActCoeff_dX_(k, iB) += ((1.0 - XA) * sum - (1.0 - XA) * XB * sumMm1
394 + XA * sumMm1 * (1.0 + 2.0 * XB - XA)
395 - XA * XB * sumMm2 * (1.0 - XA + XB));
396 }
else if (iB == k) {
397 dlnActCoeff_dX_(k, iA) += ((1.0 - XB) * sum + (1.0 - XA) * XB * sumMm1
398 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
399 + XA * XB * sumMm2 * (1.0 - XA + XB));
401 dlnActCoeff_dX_(k, iB) += (- XA * sum - (1.0 - XB) * XA * sumMm1
402 + XA * sumMm1 * (XB - XA - (1.0 - XB))
403 - XA * XB * sumMm2 * (-XA - (1.0 - XB)));
405 dlnActCoeff_dX_(k, iA) += (- XB * sum2 - XA * XB * sum2Mm1);
406 dlnActCoeff_dX_(k, iB) += (- XA * sum2 + XA * XB * sum2Mm1);
412 void RedlichKisterVPSSTP::getdlnActCoeffds(
const double dTds,
const double*
const dXds,
413 double* dlnActCoeffds)
const
415 s_update_dlnActCoeff_dT();
416 s_update_dlnActCoeff_dX_();
417 for (
size_t k = 0; k < m_kk; k++) {
418 dlnActCoeffds[k] = dlnActCoeffdT_Scaled_[k] * dTds;
419 for (
size_t j = 0; j < m_kk; j++) {
420 dlnActCoeffds[k] += dlnActCoeff_dX_(k, j) * dXds[j];
425 void RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag(
double* dlnActCoeffdlnN_diag)
const
427 s_update_dlnActCoeff_dX_();
428 for (
size_t j = 0; j < m_kk; j++) {
429 dlnActCoeffdlnN_diag[j] = dlnActCoeff_dX_(j, j);
430 for (
size_t k = 0; k < m_kk; k++) {
431 dlnActCoeffdlnN_diag[k] -= dlnActCoeff_dX_(j, k) * moleFractions_[k];
436 void RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag(
double* dlnActCoeffdlnX_diag)
const
438 s_update_dlnActCoeff_dlnX_diag();
439 for (
size_t k = 0; k < m_kk; k++) {
440 dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
444 void RedlichKisterVPSSTP::getdlnActCoeffdlnN(
const size_t ld,
double* dlnActCoeffdlnN)
446 s_update_dlnActCoeff_dX_();
447 double* data = & dlnActCoeffdlnN_(0,0);
448 for (
size_t k = 0; k < m_kk; k++) {
449 for (
size_t m = 0; m < m_kk; m++) {
450 dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
455 void RedlichKisterVPSSTP::addBinaryInteraction(
456 const string& speciesA,
const string& speciesB,
457 const double* excess_enthalpy,
size_t n_enthalpy,
458 const double* excess_entropy,
size_t n_entropy)
460 size_t kA = speciesIndex(speciesA);
461 size_t kB = speciesIndex(speciesB);
463 throw CanteraError(
"RedlichKisterVPSSTP::addBinaryInteraction",
464 "Species '{}' not present in phase", speciesA);
465 }
else if (kB ==
npos) {
466 throw CanteraError(
"RedlichKisterVPSSTP::addBinaryInteraction",
467 "Species '{}' not present in phase", speciesB);
469 if (charge(kA) != 0) {
470 throw CanteraError(
"RedlichKisterVPSSTP::addBinaryInteraction",
471 "Species '{}' should be neutral", speciesA);
472 }
else if (charge(kB) != 0) {
473 throw CanteraError(
"RedlichKisterVPSSTP::addBinaryInteraction",
474 "Species '{}' should be neutral", speciesB);
477 m_pSpecies_A_ij.push_back(kA);
478 m_pSpecies_B_ij.push_back(kB);
479 m_HE_m_ij.emplace_back(excess_enthalpy, excess_enthalpy + n_enthalpy);
480 m_SE_m_ij.emplace_back(excess_entropy, excess_entropy + n_entropy);
481 size_t N = max(n_enthalpy, n_entropy);
482 m_HE_m_ij.back().resize(N, 0.0);
483 m_SE_m_ij.back().resize(N, 0.0);
484 dlnActCoeff_dX_.resize(N, N, 0.0);
(see Thermodynamic Properties and class RedlichKisterVPSSTP).
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.
Base class for exceptions thrown by Cantera classes.
const double GasConstant
Universal Gas Constant [J/kmol/K].
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
const double SmallNumber
smallest number to compare to zero.
Contains declarations for string manipulation functions within Cantera.