Skip to content

Commit 432eb0a

Browse files
committed
address degenerate case of a=0 and b=0 for cubic EoS and added ideal gas fallback methods when degenerate case happens
1 parent dfa7d20 commit 432eb0a

File tree

5 files changed

+209
-24
lines changed

5 files changed

+209
-24
lines changed

include/cantera/thermo/MixtureFugacityTP.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,42 @@ class MixtureFugacityTP : public ThermoPhase
311311
*/
312312
double z() const;
313313

314+
//! @name Ideal-Limit Utilities for Cubic EoS
315+
//!
316+
//! These helpers provide shared ideal-gas-limit expressions used by
317+
//! cubic-EoS implementations when mixture non-ideal terms vanish.
318+
//! @{
319+
320+
//! Molar heat capacity at constant pressure in the ideal-gas limit.
321+
//! Units: J/kmol/K.
322+
double cp_mole_ideal() const;
323+
324+
//! Molar heat capacity at constant volume in the ideal-gas limit.
325+
//! Units: J/kmol/K.
326+
double cv_mole_ideal() const;
327+
328+
//! Standard concentration in the ideal-gas limit for species @p k.
329+
//! Units: kmol/m^3.
330+
double standardConcentration_ideal(size_t k) const;
331+
332+
//! Ideal-gas-limit activity coefficients for all species.
333+
//! Sets all entries of @p ac to 1.
334+
void getActivityCoefficients_ideal(double* ac) const;
335+
336+
//! Ideal-gas-limit chemical potentials for all species.
337+
//! @param mu Output vector of chemical potentials [J/kmol].
338+
void getChemPotentials_ideal(double* mu) const;
339+
340+
//! Ideal-gas-limit partial molar enthalpies for all species.
341+
//! @param hbar Output vector of partial molar enthalpies [J/kmol].
342+
void getPartialMolarEnthalpies_ideal(double* hbar) const;
343+
344+
//! Ideal-gas-limit partial molar entropies for all species.
345+
//! @param sbar Output vector of partial molar entropies [J/kmol/K].
346+
void getPartialMolarEntropies_ideal(double* sbar) const;
347+
348+
//! @}
349+
314350
//! Calculate the deviation terms for the total entropy of the mixture from
315351
//! the ideal gas mixture
316352
/**

src/thermo/MixtureFugacityTP.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "cantera/base/utilities.h"
1414
#include "cantera/base/global.h"
1515

16+
#include <algorithm>
17+
1618
using namespace std;
1719

1820
namespace Cantera
@@ -260,6 +262,56 @@ double MixtureFugacityTP::z() const
260262
return pressure() * meanMolecularWeight() / (density() * RT());
261263
}
262264

265+
double MixtureFugacityTP::cp_mole_ideal() const
266+
{
267+
return GasConstant * mean_X(m_cp0_R);
268+
}
269+
270+
double MixtureFugacityTP::cv_mole_ideal() const
271+
{
272+
return GasConstant * (mean_X(m_cp0_R) - 1.0);
273+
}
274+
275+
double MixtureFugacityTP::standardConcentration_ideal(size_t k) const
276+
{
277+
getStandardVolumes(m_workS.data());
278+
return 1.0 / m_workS[k];
279+
}
280+
281+
void MixtureFugacityTP::getActivityCoefficients_ideal(double* ac) const
282+
{
283+
for (size_t k = 0; k < m_kk; k++) {
284+
ac[k] = 1.0;
285+
}
286+
}
287+
288+
void MixtureFugacityTP::getChemPotentials_ideal(double* mu) const
289+
{
290+
double RT_ = RT();
291+
getStandardChemPotentials(mu);
292+
for (size_t k = 0; k < m_kk; k++) {
293+
double xx = std::max(SmallNumber, moleFraction(k));
294+
mu[k] += RT_ * log(xx);
295+
}
296+
}
297+
298+
void MixtureFugacityTP::getPartialMolarEnthalpies_ideal(double* hbar) const
299+
{
300+
getEnthalpy_RT_ref(hbar);
301+
scale(hbar, hbar + m_kk, hbar, RT());
302+
}
303+
304+
void MixtureFugacityTP::getPartialMolarEntropies_ideal(double* sbar) const
305+
{
306+
getEntropy_R_ref(sbar);
307+
scale(sbar, sbar + m_kk, sbar, GasConstant);
308+
double logPres = log(pressure() / refPressure());
309+
for (size_t k = 0; k < m_kk; k++) {
310+
double xx = std::max(SmallNumber, moleFraction(k));
311+
sbar[k] -= GasConstant * (log(xx) + logPres);
312+
}
313+
}
314+
263315
double MixtureFugacityTP::sresid() const
264316
{
265317
throw NotImplementedError("MixtureFugacityTP::sresid");

src/thermo/PengRobinson.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
namespace Cantera
1616
{
1717

18+
namespace
19+
{
20+
bool isIdealCubicLimit(double aMix, double bMix)
21+
{
22+
return aMix == 0.0 && bMix == 0.0;
23+
}
24+
}
25+
1826
const double PengRobinson::omega_a = 4.5723552892138218E-01;
1927
const double PengRobinson::omega_b = 7.77960739038885E-02;
2028
const double PengRobinson::omega_vc = 3.07401308698703833E-01;
@@ -84,6 +92,9 @@ void PengRobinson::setBinaryCoeffs(const string& species_i,
8492
double PengRobinson::cp_mole() const
8593
{
8694
_updateReferenceStateThermo();
95+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
96+
return cp_mole_ideal();
97+
}
8798
double T = temperature();
8899
double mv = molarVolume();
89100
double vpb = mv + (1 + Sqrt2) * m_b;
@@ -98,6 +109,9 @@ double PengRobinson::cp_mole() const
98109
double PengRobinson::cv_mole() const
99110
{
100111
_updateReferenceStateThermo();
112+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
113+
return cv_mole_ideal();
114+
}
101115
double T = temperature();
102116
calculatePressureDerivatives();
103117
return (cp_mole() + T * m_dpdT * m_dpdT / m_dpdV);
@@ -115,12 +129,15 @@ double PengRobinson::pressure() const
115129

116130
double PengRobinson::standardConcentration(size_t k) const
117131
{
118-
getStandardVolumes(m_workS.data());
119-
return 1.0 / m_workS[k];
132+
return standardConcentration_ideal(k);
120133
}
121134

122135
void PengRobinson::getActivityCoefficients(double* ac) const
123136
{
137+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
138+
getActivityCoefficients_ideal(ac);
139+
return;
140+
}
124141
double mv = molarVolume();
125142
double vpb2 = mv + (1 + Sqrt2) * m_b;
126143
double vmb2 = mv + (1 - Sqrt2) * m_b;
@@ -154,8 +171,13 @@ void PengRobinson::getActivityCoefficients(double* ac) const
154171

155172
void PengRobinson::getChemPotentials(double* mu) const
156173
{
157-
getGibbs_ref(mu);
174+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
175+
getChemPotentials_ideal(mu);
176+
return;
177+
}
158178
double RT_ = RT();
179+
180+
getGibbs_ref(mu);
159181
for (size_t k = 0; k < m_kk; k++) {
160182
double xx = std::max(SmallNumber, moleFraction(k));
161183
mu[k] += RT_ * (log(xx));
@@ -189,6 +211,10 @@ void PengRobinson::getChemPotentials(double* mu) const
189211

190212
void PengRobinson::getPartialMolarEnthalpies(double* hbar) const
191213
{
214+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
215+
getPartialMolarEnthalpies_ideal(hbar);
216+
return;
217+
}
192218
// First we get the reference state contributions
193219
getEnthalpy_RT_ref(hbar);
194220
scale(hbar, hbar+m_kk, hbar, RT());
@@ -239,6 +265,11 @@ void PengRobinson::getPartialMolarEnthalpies(double* hbar) const
239265

240266
void PengRobinson::getPartialMolarEntropies(double* sbar) const
241267
{
268+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
269+
getPartialMolarEntropies_ideal(sbar);
270+
return;
271+
}
272+
242273
// Using the identity : (hk - T*sk) = gk
243274
double T = temperature();
244275
getPartialMolarEnthalpies(sbar);
@@ -443,6 +474,9 @@ void PengRobinson::getSpeciesParameters(const string& name, AnyMap& speciesNode)
443474

444475
double PengRobinson::sresid() const
445476
{
477+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
478+
return 0.0;
479+
}
446480
double molarV = molarVolume();
447481
double hh = m_b / molarV;
448482
double zz = z();
@@ -456,6 +490,9 @@ double PengRobinson::sresid() const
456490

457491
double PengRobinson::hresid() const
458492
{
493+
if (isIdealCubicLimit(m_aAlpha_mix, m_b)) {
494+
return 0.0;
495+
}
459496
double molarV = molarVolume();
460497
double zz = z();
461498
double aAlpha_1 = daAlpha_dT();

src/thermo/RedlichKwongMFTP.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
namespace Cantera
1616
{
1717

18+
namespace
19+
{
20+
bool isIdealCubicLimit(double aMix, double bMix)
21+
{
22+
return aMix == 0.0 && bMix == 0.0;
23+
}
24+
}
25+
1826
const double RedlichKwongMFTP::omega_a = 4.27480233540E-01;
1927
const double RedlichKwongMFTP::omega_b = 8.66403499650E-02;
2028
const double RedlichKwongMFTP::omega_vc = 3.33333333333333E-01;
@@ -86,6 +94,9 @@ void RedlichKwongMFTP::setBinaryCoeffs(const string& species_i, const string& sp
8694
double RedlichKwongMFTP::cp_mole() const
8795
{
8896
_updateReferenceStateThermo();
97+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
98+
return cp_mole_ideal();
99+
}
89100
double TKelvin = temperature();
90101
double sqt = sqrt(TKelvin);
91102
double mv = molarVolume();
@@ -102,6 +113,9 @@ double RedlichKwongMFTP::cp_mole() const
102113
double RedlichKwongMFTP::cv_mole() const
103114
{
104115
_updateReferenceStateThermo();
116+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
117+
return cv_mole_ideal();
118+
}
105119
double TKelvin = temperature();
106120
double sqt = sqrt(TKelvin);
107121
double mv = molarVolume();
@@ -126,12 +140,15 @@ double RedlichKwongMFTP::pressure() const
126140

127141
double RedlichKwongMFTP::standardConcentration(size_t k) const
128142
{
129-
getStandardVolumes(m_workS.data());
130-
return 1.0 / m_workS[k];
143+
return standardConcentration_ideal(k);
131144
}
132145

133146
void RedlichKwongMFTP::getActivityCoefficients(double* ac) const
134147
{
148+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
149+
getActivityCoefficients_ideal(ac);
150+
return;
151+
}
135152
double mv = molarVolume();
136153
double sqt = sqrt(temperature());
137154
double vpb = mv + m_b_current;
@@ -164,6 +181,11 @@ void RedlichKwongMFTP::getActivityCoefficients(double* ac) const
164181

165182
void RedlichKwongMFTP::getChemPotentials(double* mu) const
166183
{
184+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
185+
getChemPotentials_ideal(mu);
186+
return;
187+
}
188+
167189
getGibbs_ref(mu);
168190
for (size_t k = 0; k < m_kk; k++) {
169191
double xx = std::max(SmallNumber, moleFraction(k));
@@ -198,6 +220,10 @@ void RedlichKwongMFTP::getChemPotentials(double* mu) const
198220

199221
void RedlichKwongMFTP::getPartialMolarEnthalpies(double* hbar) const
200222
{
223+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
224+
getPartialMolarEnthalpies_ideal(hbar);
225+
return;
226+
}
201227
// First we get the reference state contributions
202228
getEnthalpy_RT_ref(hbar);
203229
scale(hbar, hbar+m_kk, hbar, RT());
@@ -243,6 +269,11 @@ void RedlichKwongMFTP::getPartialMolarEnthalpies(double* hbar) const
243269

244270
void RedlichKwongMFTP::getPartialMolarEntropies(double* sbar) const
245271
{
272+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
273+
getPartialMolarEntropies_ideal(sbar);
274+
return;
275+
}
276+
246277
getEntropy_R_ref(sbar);
247278
scale(sbar, sbar+m_kk, sbar, GasConstant);
248279
double TKelvin = temperature();
@@ -504,6 +535,9 @@ void RedlichKwongMFTP::getSpeciesParameters(const string& name,
504535

505536
double RedlichKwongMFTP::sresid() const
506537
{
538+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
539+
return 0.0;
540+
}
507541
// note this agrees with tpx
508542
double rho = density();
509543
double mmw = meanMolecularWeight();
@@ -520,6 +554,9 @@ double RedlichKwongMFTP::sresid() const
520554

521555
double RedlichKwongMFTP::hresid() const
522556
{
557+
if (isIdealCubicLimit(m_a_current, m_b_current)) {
558+
return 0.0;
559+
}
523560
// note this agrees with tpx
524561
double rho = density();
525562
double mmw = meanMolecularWeight();

0 commit comments

Comments
 (0)