[Thermo] Revert to previous state after error setting thermo state

This prevents ThermoPhase objects from ending up in broken states
where they can't be set to a new state because of a partially-applied
invalid state, for example caused by an out-of-range temperature.
This commit is contained in:
Ray Speth
2025-09-19 06:50:02 -04:00
committed by Bryan Weber
parent e6c2c102bf
commit c6ca2ca8d2
3 changed files with 102 additions and 10 deletions
+9 -2
View File
@@ -397,8 +397,15 @@ void Phase::setMassFractionsByName(const string& y)
void Phase::setState_TD(double t, double rho)
{
setTemperature(t);
setDensity(rho);
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setTemperature(t);
setDensity(rho);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
double Phase::molecularWeight(size_t k) const
+36 -8
View File
@@ -120,26 +120,40 @@ void ThermoPhase::setState_TPY(double t, double p, const string& y)
void ThermoPhase::setState_TP(double t, double p)
{
double tsave = temperature();
double dsave = density();
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setTemperature(t);
setPressure(p);
} catch (CanteraError&) {
setState_TD(tsave, dsave);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
void ThermoPhase::setState_HP(double Htarget, double p, double rtol)
{
setState_HPorUV(Htarget, p, rtol, false);
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setState_HPorUV(Htarget, p, rtol, false);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
void ThermoPhase::setState_UV(double u, double v, double rtol)
{
assertCompressible("setState_UV");
setState_HPorUV(u, v, rtol, true);
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setState_HPorUV(u, v, rtol, true);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
void ThermoPhase::setState(const AnyMap& input_state)
@@ -452,13 +466,27 @@ void ThermoPhase::setState_HPorUV(double Htarget, double p,
void ThermoPhase::setState_SP(double Starget, double p, double rtol)
{
setState_SPorSV(Starget, p, rtol, false);
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setState_SPorSV(Starget, p, rtol, false);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
void ThermoPhase::setState_SV(double Starget, double v, double rtol)
{
assertCompressible("setState_SV");
setState_SPorSV(Starget, v, rtol, true);
vector<double> state(partialStateSize());
savePartialState(state.size(), state.data());
try {
setState_SPorSV(Starget, v, rtol, true);
} catch (std::exception&) {
restorePartialState(state.size(), state.data());
throw;
}
}
void ThermoPhase::setState_SPorSV(double Starget, double p,
+57
View File
@@ -302,4 +302,61 @@ TEST_F(EquilRatio_MixFrac_Test, EquilRatio_MixFrac_StoichMix_Mass)
test_stoich_mixture(ThermoBasis::mass, 0.050011556441079318, 18.995378491732041);
}
struct SetStateRecovery : public testing::Test
{
SetStateRecovery() {
auto soln = newSolution("debye-huckel-all.yaml", "debye-huckel-B-dot-ak-IAPWS");
thermo = soln->thermo();
T1 = thermo->temperature();
P1 = thermo->pressure();
h1 = thermo->enthalpy_mass();
cp1 = thermo->cp_mass();
s1 = thermo->entropy_mass();
}
shared_ptr<ThermoPhase> thermo;
double T1, P1, h1, cp1, s1;
};
TEST_F(SetStateRecovery, HP)
{
double h2 = h1 + cp1 * (600 - T1); // Water state is invalid at 600 K
EXPECT_THROW(thermo->setState_HP(h2, P1), CanteraError);
EXPECT_DOUBLE_EQ(thermo->temperature(), T1);
EXPECT_DOUBLE_EQ(thermo->pressure(), P1);
double h3 = h1 + cp1 * (350 - T1);
thermo->setState_HP(h3, P1);
EXPECT_NEAR(thermo->temperature(), 350, 1.0);
}
TEST_F(SetStateRecovery, SP)
{
double T3 = T1 + 0.5 * (600 - T1);
thermo->setState_TP(T3, P1);
double s3 = thermo->entropy_mass();
double s2 = s1 + 2.0 * (s3 - s1);
thermo->setState_TP(T1, P1);
EXPECT_THROW(thermo->setState_SP(s2, P1), CanteraError);
EXPECT_DOUBLE_EQ(thermo->temperature(), T1);
EXPECT_DOUBLE_EQ(thermo->pressure(), P1);
thermo->setState_SP(s3, P1);
EXPECT_NEAR(thermo->temperature(), T3, 1e-2);
}
TEST_F(SetStateRecovery, TD)
{
EXPECT_THROW(thermo->setState_TD(400, -1), CanteraError);
EXPECT_DOUBLE_EQ(thermo->temperature(), T1);
EXPECT_DOUBLE_EQ(thermo->pressure(), P1);
thermo->setState_TP(500, 2 * P1);
}
TEST_F(SetStateRecovery, TP)
{
EXPECT_THROW(thermo->setState_TP(400, -1), CanteraError);
EXPECT_DOUBLE_EQ(thermo->temperature(), T1);
EXPECT_DOUBLE_EQ(thermo->pressure(), P1);
thermo->setState_TP(500, 2 * P1);
}
}