Skip to content

Commit 3dafa16

Browse files
committed
thermo: reject degenerate nonphysical single cubic roots
1 parent b3a9be7 commit 3dafa16

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

src/thermo/MixtureFugacityTP.cpp

Lines changed: 17 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
@@ -841,6 +843,11 @@ int MixtureFugacityTP::solveCubic(double T, double pres, double a, double b,
841843
}
842844

843845
double tmp;
846+
auto physicalRoot = [b](double v) {
847+
// For cubic EoS, physically admissible roots satisfy V > b and V > 0.
848+
double vmin = std::max(0.0, b * (1.0 + 1e-12));
849+
return std::isfinite(v) && v > vmin;
850+
};
844851
// One real root -> have to determine whether gas or liquid is the root
845852
if (disc > 0.0) {
846853
double tmpD = sqrt(disc);
@@ -921,6 +928,11 @@ int MixtureFugacityTP::solveCubic(double T, double pres, double a, double b,
921928
// Find an accurate root, since there might be a heavy amount of roundoff error due to bad conditioning in this solver.
922929
double res, dresdV = 0.0;
923930
for (int i = 0; i < nSolnValues; i++) {
931+
if (!physicalRoot(Vroot[i])) {
932+
// Non-physical roots (for example, negative molar volume) are not
933+
// used for state selection and should not trigger convergence errors.
934+
continue;
935+
}
924936
for (int n = 0; n < 20; n++) {
925937
res = an * Vroot[i] * Vroot[i] * Vroot[i] + bn * Vroot[i] * Vroot[i] + cn * Vroot[i] + dn;
926938
if (fabs(res) < 1.0E-14) { // accurate root is obtained
@@ -946,6 +958,11 @@ int MixtureFugacityTP::solveCubic(double T, double pres, double a, double b,
946958
"V = {}", T, pres, Vroot[i]);
947959
}
948960
}
961+
if (nSolnValues == 1 && !physicalRoot(Vroot[0])) {
962+
throw CanteraError("MixtureFugacityTP::solveCubic",
963+
"single real root is non-physical for T = {}, p = {} "
964+
"(V = {}, b = {})", T, pres, Vroot[0], b);
965+
}
949966

950967
if (nSolnValues == 1) {
951968
// Determine the phase of the single root.

test/python/test_thermo.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,28 @@ def test_partial_lookup_pr_state_setting(self, temperature, pressure, compositio
10711071
assert gas.density > 0.0
10721072
assert gas.P == approx(pressure)
10731073

1074+
@pytest.mark.parametrize("p", [2.0e7, 4.0e7, 6.0e7])
1075+
def test_partial_lookup_pr_high_pressure_equilibrate(self, p):
1076+
gas = self._partial_lookup_peng_robinson_phase()
1077+
1078+
fuel_temp = 255.0
1079+
oxidizer_temp = 142.0
1080+
1081+
gas.TPY = fuel_temp, p, "CH4:1.0"
1082+
yin_f = gas.Y
1083+
gas.TPY = oxidizer_temp, p, "O2:1.0"
1084+
yin_o = gas.Y
1085+
zst = 1.0 / (1.0 + gas.stoich_air_fuel_ratio(yin_f, yin_o, "mass"))
1086+
yst = zst * yin_f + (1.0 - zst) * yin_o
1087+
1088+
tbar = 0.5 * (fuel_temp + oxidizer_temp)
1089+
gas.TPY = tbar, p, yst
1090+
gas.equilibrate("HP")
1091+
1092+
assert np.isfinite(gas.T)
1093+
assert gas.T > tbar
1094+
assert gas.P == approx(p)
1095+
10741096
def test_partial_lookup_pr_zero_ab_properties_finite(self):
10751097
gas = self._partial_lookup_peng_robinson_phase()
10761098
gas.TPX = 500.0, 1.0e6, "CO2:0.333, H2O:0.666"

test/thermo/cubicSolver_Test.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,16 @@ TEST_F(cubicSolver_Test, solve_cubic)
115115
p = peng_robinson_phase->pressure();
116116
EXPECT_NEAR(p, pCrit, 1);
117117
}
118+
119+
TEST_F(cubicSolver_Test, solve_cubic_nonphysical_single_root_when_b_zero)
120+
{
121+
auto* peng_robinson_phase = dynamic_cast<PengRobinson*>(test_phase.get());
122+
ASSERT_TRUE(peng_robinson_phase != nullptr);
123+
124+
double Vroot[3];
125+
EXPECT_THROW(
126+
peng_robinson_phase->solveCubic(300.0, 1.0e5, 2.0e7, 0.0, 2.0e7, Vroot),
127+
CanteraError);
128+
}
118129
#endif
119130
};

0 commit comments

Comments
 (0)