Cantera  4.0.0a2
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.
72 for (size_t k = 0; k < m_kk; k++) {
73 hbar[k] -= GasConstant * T * T * dlnActCoeffdT_Scaled_[k];
74 }
75}
76
77void RedlichKisterVPSSTP::getPartialMolarCp(span<double> cpbar) const
78{
79 // The Redlich-Kister excess Gibbs energy is linear in T, so the first and
80 // second temperature derivative terms of the activity coefficients cancel.
81 getCp_R(cpbar);
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.
96
97 for (size_t k = 0; k < m_kk; k++) {
98 double xx = std::max(moleFractions_[k], SmallNumber);
99 sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
100 }
101 // dimensionalize it.
102 for (size_t k = 0; k < m_kk; k++) {
103 sbar[k] *= GasConstant;
104 }
105}
106
108{
109 // Get the standard state values in m^3 kmol-1
110 getStandardVolumes(vbar);
111 for (size_t iK = 0; iK < m_kk; iK++) {
112 vbar[iK] += 0.0;
113 }
114}
115
117{
118 if (m_input.hasKey("interactions")) {
119 for (const auto& item : m_input["interactions"].asVector<AnyMap>()) {
120 auto& species = item["species"].asVector<string>(2);
121 vector<double> h_excess = item.convertVector("excess-enthalpy", "J/kmol");
122 vector<double> s_excess = item.convertVector("excess-entropy", "J/kmol/K");
123 addBinaryInteraction(species[0], species[1], h_excess, s_excess);
124 }
125 }
126 initLengths();
128}
129
131{
133 vector<AnyMap> interactions;
134 for (size_t n = 0; n < m_pSpecies_A_ij.size(); n++) {
135 AnyMap interaction;
136 interaction["species"] = vector<string>{
138 vector<double> h = m_HE_m_ij[n];
139 vector<double> s = m_SE_m_ij[n];
140 while (h.size() > 1 && h.back() == 0) {
141 h.pop_back();
142 }
143 while (s.size() > 1 && s.back() == 0) {
144 s.pop_back();
145 }
146 interaction["excess-enthalpy"].setQuantity(std::move(h), "J/kmol");
147 interaction["excess-entropy"].setQuantity(std::move(s), "J/kmol/K");
148 interactions.push_back(std::move(interaction));
149 }
150 phaseNode["interactions"] = std::move(interactions);
151}
152
154{
156}
157
159{
160 double T = temperature();
161 lnActCoeff_Scaled_.assign(m_kk, 0.0);
162
163 // Scaling: I moved the division of RT higher so that we are always dealing
164 // with G/RT dimensionless terms within the routine. There is a severe
165 // problem with roundoff error in these calculations. The dimensionless
166 // terms help.
167 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
168 size_t iA = m_pSpecies_A_ij[i];
169 size_t iB = m_pSpecies_B_ij[i];
170 double XA = moleFractions_[iA];
171 double XB = moleFractions_[iB];
172 double deltaX = XA - XB;
173 const vector<double>& he_vec = m_HE_m_ij[i];
174 const vector<double>& se_vec = m_SE_m_ij[i];
175 double poly = 1.0;
176 double polyMm1 = 1.0;
177 double sum = 0.0;
178 double sumMm1 = 0.0;
179 double sum2 = 0.0;
180 for (size_t m = 0; m < he_vec.size(); m++) {
181 double A_ge = (he_vec[m] - T * se_vec[m]) / (GasConstant * T);
182 sum += A_ge * poly;
183 sum2 += A_ge * (m + 1) * poly;
184 poly *= deltaX;
185 if (m >= 1) {
186 sumMm1 += (A_ge * polyMm1 * m);
187 polyMm1 *= deltaX;
188 }
189 }
190 double oneMXA = 1.0 - XA;
191 double oneMXB = 1.0 - XB;
192 for (size_t k = 0; k < m_kk; k++) {
193 if (iA == k) {
194 lnActCoeff_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
195 } else if (iB == k) {
196 lnActCoeff_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
197 } else {
198 lnActCoeff_Scaled_[k] += -(XA * XB * sum2);
199 }
200 }
201 // Debug against formula in literature
202 }
203}
204
206{
207 double T = temperature();
208 dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
209
210 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
211 size_t iA = m_pSpecies_A_ij[i];
212 size_t iB = m_pSpecies_B_ij[i];
213 double XA = moleFractions_[iA];
214 double XB = moleFractions_[iB];
215 double deltaX = XA - XB;
216 double poly = 1.0;
217 double sum = 0.0;
218 const vector<double>& he_vec = m_HE_m_ij[i];
219 double sumMm1 = 0.0;
220 double polyMm1 = 1.0;
221 double sum2 = 0.0;
222 for (size_t m = 0; m < he_vec.size(); m++) {
223 double h_e = - he_vec[m] / (GasConstant * T * T);
224 sum += h_e * poly;
225 sum2 += h_e * (m + 1) * poly;
226 poly *= deltaX;
227 if (m >= 1) {
228 sumMm1 += (h_e * polyMm1 * m);
229 polyMm1 *= deltaX;
230 }
231 }
232 double oneMXA = 1.0 - XA;
233 double oneMXB = 1.0 - XB;
234 for (size_t k = 0; k < m_kk; k++) {
235 if (iA == k) {
236 dlnActCoeffdT_Scaled_[k] += (oneMXA * XB * sum) + (XA * XB * sumMm1 * (oneMXA + XB));
237 } else if (iB == k) {
238 dlnActCoeffdT_Scaled_[k] += (oneMXB * XA * sum) + (XA * XB * sumMm1 * (-oneMXB - XA));
239 } else {
240 dlnActCoeffdT_Scaled_[k] += -(XA * XB * sum2);
241 }
242 }
243 }
244}
245
246void RedlichKisterVPSSTP::getdlnActCoeffdT(span<double> dlnActCoeffdT) const
247{
248 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdT", dlnActCoeffdT.size(), m_kk);
250 for (size_t k = 0; k < m_kk; k++) {
251 dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
252 }
253}
254
256{
257 double T = temperature();
258 dlnActCoeffdlnX_diag_.assign(m_kk, 0.0);
259
260 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
261 size_t iA = m_pSpecies_A_ij[i];
262 size_t iB = m_pSpecies_B_ij[i];
263 double XA = moleFractions_[iA];
264 double XB = moleFractions_[iB];
265 double deltaX = XA - XB;
266 double poly = 1.0;
267 double sum = 0.0;
268 const vector<double>& he_vec = m_HE_m_ij[i];
269 const vector<double>& se_vec = m_SE_m_ij[i];
270 double sumMm1 = 0.0;
271 double polyMm1 = 1.0;
272 double polyMm2 = 1.0;
273 double sumMm2 = 0.0;
274 for (size_t m = 0; m < he_vec.size(); m++) {
275 double A_ge = (he_vec[m] - T * se_vec[m]) / (GasConstant * T);;
276 sum += A_ge * poly;
277 poly *= deltaX;
278 if (m >= 1) {
279 sumMm1 += (A_ge * polyMm1 * m);
280 polyMm1 *= deltaX;
281 }
282 if (m >= 2) {
283 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
284 polyMm2 *= deltaX;
285 }
286 }
287
288 for (size_t k = 0; k < m_kk; k++) {
289 if (iA == k) {
291 XA * (- (1-XA+XB) * sum + 2*(1.0 - XA) * XB * sumMm1
292 + sumMm1 * (XB * (1 - 2*XA + XB) - XA * (1 - XA + 2*XB))
293 + 2 * XA * XB * sumMm2 * (1.0 - XA + XB));
294 } else if (iB == k) {
296 XB * (- (1-XB+XA) * sum - 2*(1.0 - XB) * XA * sumMm1
297 + sumMm1 * (XA * (2*XB - XA - 1) - XB * (-2*XA + XB - 1))
298 - 2 * XA * XB * sumMm2 * (-XA - 1 + XB));
299 }
300 }
301 }
302}
303
305{
306 double T = temperature();
308
309 for (size_t i = 0; i < m_HE_m_ij.size(); i++) {
310 size_t iA = m_pSpecies_A_ij[i];
311 size_t iB = m_pSpecies_B_ij[i];
312 double XA = moleFractions_[iA];
313 double XB = moleFractions_[iB];
314 double deltaX = XA - XB;
315 double poly = 1.0;
316 double sum = 0.0;
317 const vector<double>& he_vec = m_HE_m_ij[i];
318 const vector<double>& se_vec = m_SE_m_ij[i];
319 double sumMm1 = 0.0;
320 double polyMm1 = 1.0;
321 double polyMm2 = 1.0;
322 double sum2 = 0.0;
323 double sum2Mm1 = 0.0;
324 double sumMm2 = 0.0;
325 for (size_t m = 0; m < he_vec.size(); m++) {
326 double A_ge = he_vec[m] - T * se_vec[m];
327 sum += A_ge * poly;
328 sum2 += A_ge * (m + 1) * poly;
329 poly *= deltaX;
330 if (m >= 1) {
331 sumMm1 += (A_ge * polyMm1 * m);
332 sum2Mm1 += (A_ge * polyMm1 * m * (1.0 + m));
333 polyMm1 *= deltaX;
334 }
335 if (m >= 2) {
336 sumMm2 += (A_ge * polyMm2 * m * (m - 1.0));
337 polyMm2 *= deltaX;
338 }
339 }
340
341 for (size_t k = 0; k < m_kk; k++) {
342 if (iA == k) {
343 dlnActCoeff_dX_(k, iA) += (- XB * sum + (1.0 - XA) * XB * sumMm1
344 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
345 + XA * XB * sumMm2 * (1.0 - XA + XB));
346
347 dlnActCoeff_dX_(k, iB) += ((1.0 - XA) * sum - (1.0 - XA) * XB * sumMm1
348 + XA * sumMm1 * (1.0 + 2.0 * XB - XA)
349 - XA * XB * sumMm2 * (1.0 - XA + XB));
350 } else if (iB == k) {
351 dlnActCoeff_dX_(k, iA) += ((1.0 - XB) * sum + (1.0 - XA) * XB * sumMm1
352 + XB * sumMm1 * (1.0 - 2.0 * XA + XB)
353 + XA * XB * sumMm2 * (1.0 - XA + XB));
354
355 dlnActCoeff_dX_(k, iB) += (- XA * sum - (1.0 - XB) * XA * sumMm1
356 + XA * sumMm1 * (XB - XA - (1.0 - XB))
357 - XA * XB * sumMm2 * (-XA - (1.0 - XB)));
358 } else {
359 dlnActCoeff_dX_(k, iA) += (- XB * sum2 - XA * XB * sum2Mm1);
360 dlnActCoeff_dX_(k, iB) += (- XA * sum2 + XA * XB * sum2Mm1);
361 }
362 }
363 }
364}
365
366void RedlichKisterVPSSTP::getdlnActCoeffds(const double dTds, span<const double> const dXds,
367 span<double> dlnActCoeffds) const
368{
369 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffds", dXds.size(), m_kk);
370 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffds", dlnActCoeffds.size(), m_kk);
373 for (size_t k = 0; k < m_kk; k++) {
374 dlnActCoeffds[k] = dlnActCoeffdT_Scaled_[k] * dTds;
375 for (size_t j = 0; j < m_kk; j++) {
376 dlnActCoeffds[k] += dlnActCoeff_dX_(k, j) * dXds[j];
377 }
378 }
379}
380
381void RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag(span<double> dlnActCoeffdlnN_diag) const
382{
383 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnN_diag",
384 dlnActCoeffdlnN_diag.size(), m_kk);
386 for (size_t j = 0; j < m_kk; j++) {
387 dlnActCoeffdlnN_diag[j] = dlnActCoeff_dX_(j, j);
388 for (size_t k = 0; k < m_kk; k++) {
389 dlnActCoeffdlnN_diag[k] -= dlnActCoeff_dX_(j, k) * moleFractions_[k];
390 }
391 }
392}
393
394void RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag(span<double> dlnActCoeffdlnX_diag) const
395{
396 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnX_diag",
397 dlnActCoeffdlnX_diag.size(), m_kk);
399 for (size_t k = 0; k < m_kk; k++) {
400 dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
401 }
402}
403
404void RedlichKisterVPSSTP::getdlnActCoeffdlnN(const size_t ld, span<double> dlnActCoeffdlnN)
405{
406 checkArraySize("RedlichKisterVPSSTP::getdlnActCoeffdlnN",
407 dlnActCoeffdlnN.size(), ld * m_kk);
409 double* data = & dlnActCoeffdlnN_(0,0);
410 for (size_t k = 0; k < m_kk; k++) {
411 for (size_t m = 0; m < m_kk; m++) {
412 dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
413 }
414 }
415}
416
418 const string& speciesA, const string& speciesB,
419 span<const double> excess_enthalpy, span<const double> excess_entropy)
420{
421 size_t kA = speciesIndex(speciesA, true);
422 size_t kB = speciesIndex(speciesB, true);
423 if (charge(kA) != 0) {
424 throw CanteraError("RedlichKisterVPSSTP::addBinaryInteraction",
425 "Species '{}' should be neutral", speciesA);
426 } else if (charge(kB) != 0) {
427 throw CanteraError("RedlichKisterVPSSTP::addBinaryInteraction",
428 "Species '{}' should be neutral", speciesB);
429 }
430
431 m_pSpecies_A_ij.push_back(kA);
432 m_pSpecies_B_ij.push_back(kB);
433 m_HE_m_ij.emplace_back(excess_enthalpy.begin(), excess_enthalpy.end());
434 m_SE_m_ij.emplace_back(excess_entropy.begin(), excess_entropy.end());
435 size_t N = max(excess_enthalpy.size(), excess_entropy.size());
436 m_HE_m_ij.back().resize(N, 0.0);
437 m_SE_m_ij.back().resize(N, 0.0);
438 dlnActCoeff_dX_.resize(N, N, 0.0);
439}
440
441}
(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.
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:882
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:586
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:943
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:562
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 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.