Cantera  4.0.0a1
Loading...
Searching...
No Matches
RedlichKisterVPSSTP.cpp
Go to the documentation of this file.
1/**
2 * @file RedlichKisterVPSSTP.cpp
3 * Definitions for ThermoPhase object for phases which
4 * employ excess Gibbs free energy formulations related to RedlichKister
5 * expansions (see @ref thermoprops
6 * and class @link Cantera::RedlichKisterVPSSTP RedlichKisterVPSSTP@endlink).
7 */
8
9// This file is part of Cantera. See License.txt in the top-level directory or
10// at https://cantera.org/license.txt for license and copyright information.
11
15
16using namespace std;
17
18namespace Cantera
19{
20RedlichKisterVPSSTP::RedlichKisterVPSSTP(const string& inputFile, const string& id_)
21{
22 initThermoFile(inputFile, id_);
23}
24
25// - Activities, Standard States, Activity Concentrations -----------
26
28{
29 checkArraySize("RedlichKisterVPSSTP::getLnActivityCoefficients", lnac.size(), m_kk);
30 // Update the activity coefficients
32
33 for (size_t k = 0; k < m_kk; k++) {
34 lnac[k] = lnActCoeff_Scaled_[k];
35 }
36}
37
38// ------------ Partial Molar Properties of the Solution ------------
39
40void RedlichKisterVPSSTP::getChemPotentials(span<double> mu) const
41{
42 // First get the standard chemical potentials in molar form. This requires
43 // updates of standard state as a function of T and P
45 // Update the activity coefficients
47
48 for (size_t k = 0; k < m_kk; k++) {
49 double xx = std::max(moleFractions_[k], SmallNumber);
50 mu[k] += RT() * (log(xx) + lnActCoeff_Scaled_[k]);
51 }
52}
53
55{
56 return cp_mole();
57}
58
60{
61 // Get the nondimensional standard state enthalpies
62 getEnthalpy_RT(hbar);
63 // dimensionalize it.
64 double T = temperature();
65 for (size_t k = 0; k < m_kk; k++) {
66 hbar[k] *= GasConstant * T;
67 }
68
69 // Update the activity coefficients, This also update the internally stored
70 // molalities.
73 for (size_t k = 0; k < m_kk; k++) {
74 hbar[k] -= GasConstant * T * T * dlnActCoeffdT_Scaled_[k];
75 }
76}
77
78void RedlichKisterVPSSTP::getPartialMolarCp(span<double> cpbar) const
79{
80 getCp_R(cpbar);
81 // dimensionalize it.
82 for (size_t k = 0; k < m_kk; k++) {
83 cpbar[k] *= GasConstant;
84 }
85}
86
88{
89 // Get the nondimensional standard state entropies
90 getEntropy_R(sbar);
91 double T = temperature();
92
93 // Update the activity coefficients, This also update the internally stored
94 // molalities.
97
98 for (size_t k = 0; k < m_kk; k++) {
99 double xx = std::max(moleFractions_[k], SmallNumber);
100 sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
101 }
102 // dimensionalize it.
103 for (size_t k = 0; k < m_kk; k++) {
104 sbar[k] *= GasConstant;
105 }
106}
107
109{
110 // Get the standard state values in m^3 kmol-1
111 getStandardVolumes(vbar);
112 for (size_t iK = 0; iK < m_kk; iK++) {
113 vbar[iK] += 0.0;
114 }
115}
116
118{
119 if (m_input.hasKey("interactions")) {
120 for (const auto& item : m_input["interactions"].asVector<AnyMap>()) {
121 auto& species = item["species"].asVector<string>(2);
122 vector<double> h_excess = item.convertVector("excess-enthalpy", "J/kmol");
123 vector<double> s_excess = item.convertVector("excess-entropy", "J/kmol/K");
124 addBinaryInteraction(species[0], species[1], h_excess, s_excess);
125 }
126 }
127 initLengths();
129}
130
132{
134 vector<AnyMap> interactions;
135 for (size_t n = 0; n < m_pSpecies_A_ij.size(); n++) {
136 AnyMap interaction;
137 interaction["species"] = vector<string>{
139 vector<double> h = m_HE_m_ij[n];
140 vector<double> s = m_SE_m_ij[n];
141 while (h.size() > 1 && h.back() == 0) {
142 h.pop_back();
143 }
144 while (s.size() > 1 && s.back() == 0) {
145 s.pop_back();
146 }
147 interaction["excess-enthalpy"].setQuantity(std::move(h), "J/kmol");
148 interaction["excess-entropy"].setQuantity(std::move(s), "J/kmol/K");
149 interactions.push_back(std::move(interaction));
150 }
151 phaseNode["interactions"] = std::move(interactions);
152}
153
155{
157}
158
160{
161 double T = temperature();
162 lnActCoeff_Scaled_.assign(m_kk, 0.0);
163
164 // Scaling: I moved the division of RT higher so that we are always dealing
165 // with G/RT dimensionless terms within the routine. There is a severe
166 // problem with roundoff error in these calculations. The dimensionless
167 // terms help.
168 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
169 size_t iA = m_pSpecies_A_ij[i];
170 size_t iB = m_pSpecies_B_ij[i];
171 double XA = moleFractions_[iA];
172 double XB = moleFractions_[iB];
173 double deltaX = XA - XB;
174 const vector<double>& he_vec = m_HE_m_ij[i];
175 const vector<double>& se_vec = m_SE_m_ij[i];
176 double poly = 1.0;
177 double polyMm1 = 1.0;
178 double sum = 0.0;
179 double sumMm1 = 0.0;
180 double sum2 = 0.0;
181 for (size_t m = 0; m < he_vec.size(); m++) {
182 double A_ge = (he_vec[m] - T * se_vec[m]) / (GasConstant * T);
183 sum += A_ge * poly;
184 sum2 += A_ge * (m + 1) * poly;
185 poly *= deltaX;
186 if (m >= 1) {
187 sumMm1 += (A_ge * polyMm1 * m);
188 polyMm1 *= deltaX;
189 }
190 }
191 double oneMXA = 1.0 - XA;
192 double oneMXB = 1.0 - XB;
193 for (size_t k = 0; k < m_kk; k++) {
194 if (iA == k) {
195 lnActCoeff_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
196 } else if (iB == k) {
197 lnActCoeff_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
198 } else {
199 lnActCoeff_Scaled_[k] += -(XA * XB * sum2);
200 }
201 }
202 // Debug against formula in literature
203 }
204}
205
207{
208 double T = temperature();
209 dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
210
211 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
212 size_t iA = m_pSpecies_A_ij[i];
213 size_t iB = m_pSpecies_B_ij[i];
214 double XA = moleFractions_[iA];
215 double XB = moleFractions_[iB];
216 double deltaX = XA - XB;
217 double poly = 1.0;
218 double sum = 0.0;
219 const vector<double>& he_vec = m_HE_m_ij[i];
220 double sumMm1 = 0.0;
221 double polyMm1 = 1.0;
222 double sum2 = 0.0;
223 for (size_t m = 0; m < he_vec.size(); m++) {
224 double h_e = - he_vec[m] / (GasConstant * T * T);
225 sum += h_e * poly;
226 sum2 += h_e * (m + 1) * poly;
227 poly *= deltaX;
228 if (m >= 1) {
229 sumMm1 += (h_e * polyMm1 * m);
230 polyMm1 *= deltaX;
231 }
232 }
233 double oneMXA = 1.0 - XA;
234 double oneMXB = 1.0 - XB;
235 for (size_t k = 0; k < m_kk; k++) {
236 if (iA == k) {
237 dlnActCoeffdT_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
238 } else if (iB == k) {
239 dlnActCoeffdT_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
240 } else {
241 dlnActCoeffdT_Scaled_[k] += -(XA * XB * sum2);
242 }
243 }
244 }
245
246 for (size_t k = 0; k < m_kk; k++) {
248 }
249}
250
251void RedlichKisterVPSSTP::getdlnActCoeffdT(span<double> dlnActCoeffdT) const
252{
253 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdT", dlnActCoeffdT.size(), m_kk);
255 for (size_t k = 0; k < m_kk; k++) {
256 dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
257 }
258}
259
260void RedlichKisterVPSSTP::getd2lnActCoeffdT2(span<double> d2lnActCoeffdT2) const
261{
262 checkArraySize("RedlichKisterVPSSTP::getd2lnActCoeffdT2",
263 d2lnActCoeffdT2.size(), m_kk);
265 for (size_t k = 0; k < m_kk; k++) {
266 d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k];
267 }
268}
269
271{
272 double T = temperature();
273 dlnActCoeffdlnX_diag_.assign(m_kk, 0.0);
274
275 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
276 size_t iA = m_pSpecies_A_ij[i];
277 size_t iB = m_pSpecies_B_ij[i];
278 double XA = moleFractions_[iA];
279 double XB = moleFractions_[iB];
280 double deltaX = XA - XB;
281 double poly = 1.0;
282 double sum = 0.0;
283 const vector<double>& he_vec = m_HE_m_ij[i];
284 const vector<double>& se_vec = m_SE_m_ij[i];
285 double sumMm1 = 0.0;
286 double polyMm1 = 1.0;
287 double polyMm2 = 1.0;
288 double sumMm2 = 0.0;
289 for (size_t m = 0; m < he_vec.size(); m++) {
290 double A_ge = (he_vec[m] - T * se_vec[m]) / (GasConstant * T);;
291 sum += A_ge * poly;
292 poly *= deltaX;
293 if (m >= 1) {
294 sumMm1 += (A_ge * polyMm1 * m);
295 polyMm1 *= deltaX;
296 }
297 if (m >= 2) {
298 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
299 polyMm2 *= deltaX;
300 }
301 }
302
303 for (size_t k = 0; k < m_kk; k++) {
304 if (iA == k) {
306 XA * (- (1-XA+XB) * sum + 2*(1.0 - XA) * XB * sumMm1
307 + sumMm1 * (XB * (1 - 2*XA + XB) - XA * (1 - XA + 2*XB))
308 + 2 * XA * XB * sumMm2 * (1.0 - XA + XB));
309 } else if (iB == k) {
311 XB * (- (1-XB+XA) * sum - 2*(1.0 - XB) * XA * sumMm1
312 + sumMm1 * (XA * (2*XB - XA - 1) - XB * (-2*XA + XB - 1))
313 - 2 * XA * XB * sumMm2 * (-XA - 1 + XB));
314 }
315 }
316 }
317}
318
320{
321 double T = temperature();
323
324 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
325 size_t iA = m_pSpecies_A_ij[i];
326 size_t iB = m_pSpecies_B_ij[i];
327 double XA = moleFractions_[iA];
328 double XB = moleFractions_[iB];
329 double deltaX = XA - XB;
330 double poly = 1.0;
331 double sum = 0.0;
332 const vector<double>& he_vec = m_HE_m_ij[i];
333 const vector<double>& se_vec = m_SE_m_ij[i];
334 double sumMm1 = 0.0;
335 double polyMm1 = 1.0;
336 double polyMm2 = 1.0;
337 double sum2 = 0.0;
338 double sum2Mm1 = 0.0;
339 double sumMm2 = 0.0;
340 for (size_t m = 0; m < he_vec.size(); m++) {
341 double A_ge = he_vec[m] - T * se_vec[m];
342 sum += A_ge * poly;
343 sum2 += A_ge * (m + 1) * poly;
344 poly *= deltaX;
345 if (m >= 1) {
346 sumMm1 += (A_ge * polyMm1 * m);
347 sum2Mm1 += (A_ge * polyMm1 * m * (1.0 + m));
348 polyMm1 *= deltaX;
349 }
350 if (m >= 2) {
351 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
352 polyMm2 *= deltaX;
353 }
354 }
355
356 for (size_t k = 0; k < m_kk; k++) {
357 if (iA == k) {
358 dlnActCoeff_dX_(k, iA) += (- XB * sum + (1.0 - XA) * XB * sumMm1
359 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
360 + XA * XB * sumMm2 * (1.0 - XA + XB));
361
362 dlnActCoeff_dX_(k, iB) += ((1.0 - XA) * sum - (1.0 - XA) * XB * sumMm1
363 + XA * sumMm1 * (1.0 + 2.0 * XB - XA)
364 - XA * XB * sumMm2 * (1.0 - XA + XB));
365 } else if (iB == k) {
366 dlnActCoeff_dX_(k, iA) += ((1.0 - XB) * sum + (1.0 - XA) * XB * sumMm1
367 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
368 + XA * XB * sumMm2 * (1.0 - XA + XB));
369
370 dlnActCoeff_dX_(k, iB) += (- XA * sum - (1.0 - XB) * XA * sumMm1
371 + XA * sumMm1 * (XB - XA - (1.0 - XB))
372 - XA * XB * sumMm2 * (-XA - (1.0 - XB)));
373 } else {
374 dlnActCoeff_dX_(k, iA) += (- XB * sum2 - XA * XB * sum2Mm1);
375 dlnActCoeff_dX_(k, iB) += (- XA * sum2 + XA * XB * sum2Mm1);
376 }
377 }
378 }
379}
380
381void RedlichKisterVPSSTP::getdlnActCoeffds(const double dTds, span<const double> const dXds,
382 span<double> dlnActCoeffds) const
383{
384 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffds", dXds.size(), m_kk);
385 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffds", dlnActCoeffds.size(), m_kk);
388 for (size_t k = 0; k < m_kk; k++) {
389 dlnActCoeffds[k] = dlnActCoeffdT_Scaled_[k] * dTds;
390 for (size_t j = 0; j < m_kk; j++) {
391 dlnActCoeffds[k] += dlnActCoeff_dX_(k, j) * dXds[j];
392 }
393 }
394}
395
396void RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag(span<double> dlnActCoeffdlnN_diag) const
397{
398 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag",
399 dlnActCoeffdlnN_diag.size(), m_kk);
401 for (size_t j = 0; j < m_kk; j++) {
402 dlnActCoeffdlnN_diag[j] = dlnActCoeff_dX_(j, j);
403 for (size_t k = 0; k < m_kk; k++) {
404 dlnActCoeffdlnN_diag[k] -= dlnActCoeff_dX_(j, k) * moleFractions_[k];
405 }
406 }
407}
408
409void RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag(span<double> dlnActCoeffdlnX_diag) const
410{
411 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag",
412 dlnActCoeffdlnX_diag.size(), m_kk);
414 for (size_t k = 0; k < m_kk; k++) {
415 dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
416 }
417}
418
419void RedlichKisterVPSSTP::getdlnActCoeffdlnN(const size_t ld, span<double> dlnActCoeffdlnN)
420{
421 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnN",
422 dlnActCoeffdlnN.size(), ld * m_kk);
424 double* data = & dlnActCoeffdlnN_(0,0);
425 for (size_t k = 0; k < m_kk; k++) {
426 for (size_t m = 0; m < m_kk; m++) {
427 dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
428 }
429 }
430}
431
433 const string& speciesA, const string& speciesB,
434 span<const double> excess_enthalpy, span<const double> excess_entropy)
435{
436 size_t kA = speciesIndex(speciesA, true);
437 size_t kB = speciesIndex(speciesB, true);
438 if (charge(kA) != 0) {
439 throw CanteraError("RedlichKisterVPSSTP::addBinaryInteraction",
440 "Species '{}' should be neutral", speciesA);
441 } else if (charge(kB) != 0) {
442 throw CanteraError("RedlichKisterVPSSTP::addBinaryInteraction",
443 "Species '{}' should be neutral", speciesB);
444 }
445
446 m_pSpecies_A_ij.push_back(kA);
447 m_pSpecies_B_ij.push_back(kB);
448 m_HE_m_ij.emplace_back(excess_enthalpy.begin(), excess_enthalpy.end());
449 m_SE_m_ij.emplace_back(excess_entropy.begin(), excess_entropy.end());
450 size_t N = max(excess_enthalpy.size(), excess_entropy.size());
451 m_HE_m_ij.back().resize(N, 0.0);
452 m_SE_m_ij.back().resize(N, 0.0);
453 dlnActCoeff_dX_.resize(N, N, 0.0);
454}
455
456}
(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.
Definition AnyMap.h:431
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
void zero()
Set all of the entries to zero.
Definition Array.h:118
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.
vector< double > d2lnActCoeffdT2_Scaled_
Storage for the current derivative values of the gradients with respect to temperature of the log of ...
Array2D dlnActCoeffdlnN_
Storage for the current derivative values of the gradients with respect to logarithm of the species m...
vector< double > lnActCoeff_Scaled_
Storage for the current values of the activity coefficients of the species.
vector< double > dlnActCoeffdlnX_diag_
Storage for the current derivative values of the gradients with respect to logarithm of the mole frac...
vector< double > moleFractions_
Storage for the current values of the mole fractions of the species.
vector< double > dlnActCoeffdT_Scaled_
Storage for the current derivative values of the gradients with respect to temperature of the log of ...
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
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
void getLnActivityCoefficients(span< double > lnac) const override
Get the array of non-dimensional molar-based ln activity coefficients at the current solution tempera...
void s_update_dlnActCoeff_dX_() const
Internal routine that calculates the derivative of the activity coefficients wrt the mole fractions.
Array2D dlnActCoeff_dX_
Two dimensional array of derivatives of activity coefficients wrt mole fractions.
vector< vector< double > > m_SE_m_ij
Entropy term for the binary mole fraction interaction of the excess Gibbs free energy expression.
void getPartialMolarEnthalpies(span< double > hbar) const override
Returns an array of partial molar enthalpies for the species in the mixture.
void getdlnActCoeffdlnN_diag(span< double > dlnActCoeffdlnN_diag) const override
Get the array of log species mole number derivatives of the log activity coefficients.
void getPartialMolarCp(span< double > cpbar) const override
Returns an array of partial molar heat capacities for the species in the mixture.
void getd2lnActCoeffdT2(span< double > d2lnActCoeffdT2) const
Get the array of temperature second derivatives of the log activity coefficients.
void getParameters(AnyMap &phaseNode) const override
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
void getdlnActCoeffdlnX_diag(span< double > dlnActCoeffdlnX_diag) const override
Get the array of ln mole fraction derivatives of the log activity coefficients - diagonal component o...
void getdlnActCoeffdlnN(const size_t ld, span< double > const dlnActCoeffdlnN) override
Get the array of derivatives of the log activity coefficients with respect to the log of the species ...
vector< size_t > m_pSpecies_A_ij
vector of species indices representing species A in the interaction
double cv_mole() const override
Molar heat capacity at constant volume and composition [J/kmol/K].
void s_update_dlnActCoeff_dT() const
Update the derivative of the log of the activity coefficients wrt T.
vector< size_t > m_pSpecies_B_ij
vector of species indices representing species B in the interaction
vector< vector< double > > m_HE_m_ij
Enthalpy term for the binary mole fraction interaction of the excess Gibbs free energy expression.
void addBinaryInteraction(const string &speciesA, const string &speciesB, span< const double > excess_enthalpy, span< const double > excess_entropy)
Add a binary species interaction with the specified parameters.
void getdlnActCoeffds(const double dTds, span< const double > dXds, span< double > dlnActCoeffds) const override
Get the change in activity coefficients wrt changes in state (temp, mole fraction,...
void getPartialMolarVolumes(span< double > vbar) const override
Return an array of partial molar volumes for the species in the mixture.
void initLengths()
Initialize lengths of local variables after all species have been identified.
void getPartialMolarEntropies(span< double > sbar) const override
Returns an array of partial molar entropies for the species in the mixture.
void s_update_dlnActCoeff_dlnX_diag() const
Internal routine that calculates the total derivative of the activity coefficients with respect to th...
void s_update_lnActCoeff() const
Update the activity coefficients.
void getdlnActCoeffdT(span< double > dlnActCoeffdT) const override
Get the array of temperature derivatives of the log activity coefficients.
RedlichKisterVPSSTP(const string &inputFile="", const string &id="")
Construct a RedlichKisterVPSSTP object from an input file.
void getChemPotentials(span< double > mu) const override
Get the species chemical potentials. Units: J/kmol.
virtual double cp_mole() const
Molar heat capacity at constant pressure and composition [J/kmol/K].
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.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
void initThermoFile(const string &inputFile, const string &id)
Initialize a ThermoPhase object using an input file.
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...
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.
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:123
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const double SmallNumber
smallest number to compare to zero.
Definition ct_defs.h:161
void checkArraySize(const char *procedure, size_t available, size_t required)
Wrapper for throwing ArraySizeError.
Contains declarations for string manipulation functions within Cantera.