[Thermo] Add method for setting the state using an AnyMap

Analogous to ThermoPhase::setStateFromXML, but more flexible
This commit is contained in:
Ray Speth 2018-12-31 14:41:19 -05:00
parent 3251a3533e
commit c8b737035d
7 changed files with 195 additions and 0 deletions

View file

@ -500,6 +500,12 @@ public:
*/
void setState_TPM(doublereal t, doublereal p, const std::string& m);
//! @copydoc ThermoPhase::setState
/*!
* Additionally uses the keys `molalities` or `M` to set the molalities.
*/
virtual void setState(const AnyMap& state);
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN) {
getdlnActCoeffdlnN_numderiv(ld, dlnActCoeffdlnN);
}

View file

@ -394,6 +394,12 @@ public:
*/
void getCoverages(doublereal* theta) const;
//! @copydoc ThermoPhase::setState
/*!
* Additionally uses the key `coverages` to set the fractional coverages.
*/
virtual void setState(const AnyMap& state);
protected:
//! Surface site density (kmol m-2)
doublereal m_n0;

View file

@ -1140,6 +1140,31 @@ public:
*/
virtual void setState_RPY(doublereal rho, doublereal p, const std::string& y);
//! Set the state using an AnyMap containing any combination of properties
//! supported by the thermodynamic model
/*!
* Accepted keys are:
* * `X` (mole fractions)
* * `Y` (mass fractions)
* * `T` or `temperature`
* * `P` or `pressure` [Pa]
* * `H` or `enthalpy` [J/kg]
* * `U` or `internal-energy` [J/kg]
* * `S` or `entropy` [J/kg/K]
* * `V` or `specific-volume` [m^3/kg]
* * `D` or `density` [kg/m^3]
*
* Composition can be specified as either an AnyMap of species names to
* values or as a composition string. All other values can be given as
* floating point values in Cantera's default units, or as strings with the
* units specified, which will be converted using the Units class.
*
* If no thermodynamic property pair is given, or only one of temperature or
* pressure is given, then 298.15 K and 101325 Pa will be used as necessary
* to fully set the state.
*/
virtual void setState(const AnyMap& state);
//@}
private:

View file

@ -271,6 +271,23 @@ void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, const std::string&
setState_TP(t, p);
}
void MolalityVPSSTP::setState(const AnyMap& state) {
AnyValue molalities;
if (state.hasKey("molalities")) {
molalities = state["molalities"];
} else if (state.hasKey("M")) {
molalities = state["M"];
}
if (molalities.is<string>()) {
setMolalitiesByName(molalities.asString());
} else if (molalities.is<AnyMap>()) {
setMolalitiesByName(molalities.asMap<double>());
}
VPStandardStateTP::setState(state);
}
void MolalityVPSSTP::initThermo()
{
VPStandardStateTP::initThermo();

View file

@ -289,6 +289,17 @@ void SurfPhase::setCoveragesByName(const compositionMap& cov)
setCoverages(cv.data());
}
void SurfPhase::setState(const AnyMap& state) {
if (state.hasKey("coverages")) {
if (state["coverages"].is<string>()) {
setCoveragesByName(state["coverages"].asString());
} else {
setCoveragesByName(state["coverages"].asMap<double>());
}
}
ThermoPhase::setState(state);
}
void SurfPhase::_updateThermo(bool force) const
{
doublereal tnow = temperature();

View file

@ -191,6 +191,102 @@ void ThermoPhase::setState_UV(double u, double v, double rtol)
setState_HPorUV(u, v, rtol, true);
}
void ThermoPhase::setState(const AnyMap& input_state)
{
AnyMap state = input_state;
// Remap allowable synonyms
if (state.hasKey("mass-fractions")) {
state["Y"] = state["mass-fractions"];
state.erase("mass-fractions");
}
if (state.hasKey("mole-fractions")) {
state["X"] = state["mole-fractions"];
state.erase("mole-fractions");
}
if (state.hasKey("temperature")) {
state["T"] = state["temperature"];
}
if (state.hasKey("pressure")) {
state["P"] = state["pressure"];
}
if (state.hasKey("enthalpy")) {
state["H"] = state["enthalpy"];
}
if (state.hasKey("int-energy")) {
state["U"] = state["int-energy"];
}
if (state.hasKey("internal-energy")) {
state["U"] = state["internal-energy"];
}
if (state.hasKey("specific-volume")) {
state["V"] = state["specific-volume"];
}
if (state.hasKey("entropy")) {
state["S"] = state["entropy"];
}
if (state.hasKey("density")) {
state["D"] = state["density"];
}
// Set composition
if (state.hasKey("X")) {
if (state["X"].is<string>()) {
setMoleFractionsByName(state["X"].asString());
} else {
setMoleFractionsByName(state["X"].asMap<double>());
}
state.erase("X");
} else if (state.hasKey("Y")) {
if (state["Y"].is<string>()) {
setMassFractionsByName(state["Y"].asString());
} else {
setMassFractionsByName(state["Y"].asMap<double>());
}
state.erase("Y");
}
// set thermodynamic state using whichever property pair is found
if (state.size() == 0) {
setState_TP(298.15, OneAtm);
} else if (state.hasKey("T") && state.hasKey("P")) {
setState_TP(state.convert("T", "K"), state.convert("P", "Pa"));
} else if (state.hasKey("T") && state.hasKey("D")) {
setState_TR(state.convert("T", "K"), state.convert("D", "kg/m^3"));
} else if (state.hasKey("T") && state.hasKey("V")) {
setState_TV(state.convert("T", "K"), state.convert("V", "m^3/kg"));
} else if (state.hasKey("H") && state.hasKey("P")) {
setState_HP(state.convert("H", "J/kg"), state.convert("P", "Pa"));
} else if (state.hasKey("U") && state.hasKey("V")) {
setState_UV(state.convert("U", "J/kg"), state.convert("V", "m^3/kg"));
} else if (state.hasKey("S") && state.hasKey("P")) {
setState_SP(state.convert("S", "J/kg/K"), state.convert("P", "Pa"));
} else if (state.hasKey("S") && state.hasKey("V")) {
setState_SV(state.convert("S", "J/kg/K"), state.convert("V", "m^3/kg"));
} else if (state.hasKey("S") && state.hasKey("T")) {
setState_ST(state.convert("S", "J/kg/K"), state.convert("T", "K"));
} else if (state.hasKey("P") && state.hasKey("V")) {
setState_PV(state.convert("P", "Pa"), state.convert("V", "m^3/kg"));
} else if (state.hasKey("U") && state.hasKey("P")) {
setState_UP(state.convert("U", "J/kg"), state.convert("P", "Pa"));
} else if (state.hasKey("V") && state.hasKey("H")) {
setState_VH(state.convert("V", "m^3/kg"), state.convert("H", "J/kg"));
} else if (state.hasKey("T") && state.hasKey("H")) {
setState_TH(state.convert("T", "K"), state.convert("H", "J/kg"));
} else if (state.hasKey("S") && state.hasKey("H")) {
setState_SH(state.convert("S", "J/kg/K"), state.convert("H", "J/kg"));
} else if (state.hasKey("D") && state.hasKey("P")) {
setState_RP(state.convert("D", "kg/m^3"), state.convert("P", "Pa"));
} else if (state.hasKey("T")) {
setState_TP(state.convert("T", "K"), OneAtm);
} else if (state.hasKey("P")) {
setState_TP(298.15, state.convert("P", "Pa"));
} else {
throw CanteraError("ThermoPhase::setState",
"'state' did not specify a recognized set of properties.\n"
"Keys provided were: {}", input_state.keys_str());
}
}
void ThermoPhase::setState_conditional_TP(doublereal t, doublereal p, bool set_p)
{
setTemperature(t);

View file

@ -75,4 +75,38 @@ TEST_F(TestThermoMethods, setState_nan)
EXPECT_THROW(thermo->setState_TR(555, nan), CanteraError);
}
TEST_F(TestThermoMethods, setState_AnyMap)
{
AnyMap state;
state["temperature"] = 321;
state["Y"] = "AR: 4, O2: 1.0";
state["P"] = "5 bar";
thermo->setState(state);
EXPECT_DOUBLE_EQ(thermo->temperature(), 321);
EXPECT_DOUBLE_EQ(thermo->pressure(), 5e5);
EXPECT_DOUBLE_EQ(thermo->massFraction("O2"), 0.2);
AnyMap state2;
state2["P"] = OneAtm;
state2["enthalpy"] = 0;
state2["X"]["O2"] = 0.9;
state2["X"]["AR"] = 0.1;
thermo->setState(state2);
EXPECT_DOUBLE_EQ(thermo->pressure(), OneAtm);
EXPECT_NEAR(thermo->temperature(), 298.15, 1e-6);
EXPECT_DOUBLE_EQ(thermo->moleFraction("AR"), 0.1);
AnyMap state3;
state3["density"] = 10;
state3["V"] = 0.1;
state3["mole-fractions"] = "O2: 1.0";
EXPECT_THROW(thermo->setState(state3), CanteraError);
AnyMap state4;
state4["mole-fractions"] = "O2: 1.0";
thermo->setState(state4);
EXPECT_DOUBLE_EQ(thermo->pressure(), OneAtm);
EXPECT_NEAR(thermo->temperature(), 298.15, 1e-6);
}
}