[Thermo] Fix silent failures in HP/UV/SV/SP convergence

In cases where the specified state was non-physical (i.e. corresponded to a
negative temperature), the iteration would exit when the temperature reached a
small enough value. Computing the error in temperature relative to the current
temperature avoids this problem.

Fixes #264
This commit is contained in:
Ray Speth 2016-10-18 14:54:30 -04:00
parent 89d0c5601f
commit 5b1a4a60bb
2 changed files with 20 additions and 4 deletions

View file

@ -646,6 +646,12 @@ class TestThermo(utilities.CanteraTest):
self.assertNear(self.gas.v, 3 * v1)
self.assertTrue(self.gas.T < self.gas.min_temp)
def test_setSV_low_invalid(self):
self.gas.TPX = 450, 1e5, 'H2:1.0, O2:0.4, AR:3'
self.gas.SV = 4600, None
with self.assertRaises(ct.CanteraError):
self.gas.SV = -1000, None
def test_setSV_highT(self):
"""
Set state in terms of (s,v) when the end temperature is above the
@ -675,6 +681,16 @@ class TestThermo(utilities.CanteraTest):
self.assertNear(self.gas.P, p1)
self.assertTrue(self.gas.T < self.gas.min_temp)
def test_setHP_low_invalid(self):
"""
Set state in terms of (h,p) when the enthalpy would imply a negative
temperature
"""
self.gas.TPX = 300, 101325, 'H2:1.0'
with self.assertRaises(ct.CanteraError):
self.gas.HP = -4e6, 101325
def test_setHP_highT(self):
"""
Set state in terms of (s,v) when the end temperature is above the

View file

@ -409,9 +409,9 @@ void ThermoPhase::setState_HPorUV(doublereal Htarget, doublereal p,
// Convergence in H
double Herr = Htarget - Hnew;
double acpd = std::max(fabs(cpd), 1.0E-5);
double denom = std::max(fabs(Htarget), acpd * dTtol);
double denom = std::max(fabs(Htarget), acpd * Tnew);
double HConvErr = fabs((Herr)/denom);
if (HConvErr < 0.00001 *dTtol || fabs(dt) < dTtol) {
if (HConvErr < 0.00001 * dTtol || fabs(dt/Tnew) < 0.00001 * dTtol) {
return;
}
}
@ -595,9 +595,9 @@ void ThermoPhase::setState_SPorSV(doublereal Starget, doublereal p,
// Convergence in S
double Serr = Starget - Snew;
double acpd = std::max(fabs(cpd), 1.0E-5);
double denom = std::max(fabs(Starget), acpd * dTtol);
double denom = std::max(fabs(Starget), acpd * Tnew);
double SConvErr = fabs((Serr * Tnew)/denom);
if (SConvErr < 0.00001 *dTtol || fabs(dt) < dTtol) {
if (SConvErr < 0.00001 * dTtol || fabs(dt/Tnew) < 0.00001 * dTtol) {
return;
}
}