From 3d7904161ba09515359e9b5be54c1ab5bbf1dc50 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Thu, 9 Jul 2020 17:23:01 -0400 Subject: [PATCH 1/3] Fix documentation of ThermoPhase::setToEquilState The values passed into this function are the nondimensional (species) chemical potentials, not the element potentials. The method ChemEquil::setToEquilState already handles calculation of the chemical potentials from the element potentials. --- include/cantera/thermo/ThermoPhase.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/cantera/thermo/ThermoPhase.h b/include/cantera/thermo/ThermoPhase.h index e0b0965f3e..d49ded492b 100644 --- a/include/cantera/thermo/ThermoPhase.h +++ b/include/cantera/thermo/ThermoPhase.h @@ -1457,10 +1457,10 @@ class ThermoPhase : public Phase * temperature is unchanged. Any phase (ideal or not) that * implements this method can be equilibrated by ChemEquil. * - * @param lambda_RT Input vector of dimensionless element potentials - * The length is equal to nElements(). + * @param mu_RT Input vector of dimensionless chemical potentials + * The length is equal to nSpecies(). */ - virtual void setToEquilState(const doublereal* lambda_RT) { + virtual void setToEquilState(const doublereal* mu_RT) { throw NotImplementedError("ThermoPhase::setToEquilState"); } From c7a7a31b75a48ef4eb88f1ea89c9f2ddc7960c9a Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Thu, 9 Jul 2020 18:00:33 -0400 Subject: [PATCH 2/3] [Equil] Fix use of element potential method with IdealSolidSolnPhase The implementation of IdealSolidSolnPhase::setToEquilState incorrectly used the input array as the element potentials rather than the species chemical potentials. The modified implementation corresponds to that of the IdealGasPhase class. The previous implementation seems to generally have resulted in an exception being raised, which normally results in falling back to the Gibbs solver, so this shouldn't have been producing incorrect results. --- include/cantera/thermo/IdealSolidSolnPhase.h | 2 +- .../cython/cantera/test/test_equilibrium.py | 10 +++++++++ src/thermo/IdealSolidSolnPhase.cpp | 21 ++++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/cantera/thermo/IdealSolidSolnPhase.h b/include/cantera/thermo/IdealSolidSolnPhase.h index 62afeed86a..ef42b5aa47 100644 --- a/include/cantera/thermo/IdealSolidSolnPhase.h +++ b/include/cantera/thermo/IdealSolidSolnPhase.h @@ -596,7 +596,7 @@ class IdealSolidSolnPhase : public ThermoPhase virtual bool addSpecies(shared_ptr spec); virtual void initThermo(); virtual void initThermoXML(XML_Node& phaseNode, const std::string& id); - virtual void setToEquilState(const doublereal* lambda_RT); + virtual void setToEquilState(const doublereal* mu_RT); //! Set the form for the standard and generalized concentrations /*! diff --git a/interfaces/cython/cantera/test/test_equilibrium.py b/interfaces/cython/cantera/test/test_equilibrium.py index 0ff4a0dc34..b33ef5f4ad 100644 --- a/interfaces/cython/cantera/test/test_equilibrium.py +++ b/interfaces/cython/cantera/test/test_equilibrium.py @@ -216,3 +216,13 @@ def test_vcs(self): def test_vcs_est(self): self.solve('vcs', estimate_equil=-1) + + +class Test_IdealSolidSolnPhase_Equil(utilities.CanteraTest): + def test_equil(self): + gas = ct.ThermoPhase('IdealSolidSolnPhaseExample.xml') + gas.TPX = 500, ct.one_atm, 'C2H2-graph: 1.0' + + gas.equilibrate('TP', solver='element_potential') + self.assertNear(gas['C-graph'].X[0], 2.0 / 3.0) + self.assertNear(gas['H2-solute'].X[0], 1.0 / 3.0) diff --git a/src/thermo/IdealSolidSolnPhase.cpp b/src/thermo/IdealSolidSolnPhase.cpp index befac7571a..054607a2a9 100644 --- a/src/thermo/IdealSolidSolnPhase.cpp +++ b/src/thermo/IdealSolidSolnPhase.cpp @@ -447,21 +447,28 @@ void IdealSolidSolnPhase::initThermoXML(XML_Node& phaseNode, const std::string& ThermoPhase::initThermoXML(phaseNode, id_); } -void IdealSolidSolnPhase::setToEquilState(const doublereal* lambda_RT) +void IdealSolidSolnPhase::setToEquilState(const doublereal* mu_RT) { const vector_fp& grt = gibbs_RT_ref(); - // set the pressure and composition to be consistent with the temperature doublereal pres = 0.0; + double m_p0 = refPressure(); for (size_t k = 0; k < m_kk; k++) { - m_pp[k] = -grt[k]; - for (size_t m = 0; m < nElements(); m++) { - m_pp[k] += nAtoms(k,m)*lambda_RT[m]; + double tmp = -grt[k] + mu_RT[k]; + if (tmp < -600.) { + m_pp[k] = 0.0; + } else if (tmp > 500.0) { + // Protect against inf results if the exponent is too high + double tmp2 = tmp / 500.; + tmp2 *= tmp2; + m_pp[k] = m_p0 * exp(500.) * tmp2; + } else { + m_pp[k] = m_p0 * exp(tmp); } - m_pp[k] = m_Pref * exp(m_pp[k]); pres += m_pp[k]; } - setState_PX(pres, &m_pp[0]); + // set state + setState_PX(pres, m_pp.data()); } void IdealSolidSolnPhase::setStandardConcentrationModel(const std::string& model) From a9578082ca94fc7b5e48c76d5c8be7318f3aff6d Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Thu, 9 Jul 2020 18:22:37 -0400 Subject: [PATCH 3/3] [Equil] Remove incorrect RedlichKwongMFTP::setToEquilState The inversion of setting the mole fractions based on the chemical potentials is not obvious for non-ideal phases, and the implementation here based on an ideal phase leads to incorrect equilibrium solutions. --- include/cantera/thermo/RedlichKwongMFTP.h | 1 - src/thermo/RedlichKwongMFTP.cpp | 30 ----------------------- 2 files changed, 31 deletions(-) diff --git a/include/cantera/thermo/RedlichKwongMFTP.h b/include/cantera/thermo/RedlichKwongMFTP.h index 803c6d76f2..fa5e4f0eb5 100644 --- a/include/cantera/thermo/RedlichKwongMFTP.h +++ b/include/cantera/thermo/RedlichKwongMFTP.h @@ -176,7 +176,6 @@ class RedlichKwongMFTP : public MixtureFugacityTP virtual bool addSpecies(shared_ptr spec); virtual void setParametersFromXML(const XML_Node& thermoNode); - virtual void setToEquilState(const doublereal* lambda_RT); virtual void initThermoXML(XML_Node& phaseNode, const std::string& id); virtual void initThermo(); diff --git a/src/thermo/RedlichKwongMFTP.cpp b/src/thermo/RedlichKwongMFTP.cpp index 58ad30f6fe..7ce8021fb7 100644 --- a/src/thermo/RedlichKwongMFTP.cpp +++ b/src/thermo/RedlichKwongMFTP.cpp @@ -518,36 +518,6 @@ doublereal RedlichKwongMFTP::critDensity() const return mmw / vc; } -void RedlichKwongMFTP::setToEquilState(const doublereal* mu_RT) -{ - double tmp, tmp2; - _updateReferenceStateThermo(); - getGibbs_RT_ref(m_tmpV.data()); - - // Within the method, we protect against inf results if the exponent is too - // high. - // - // If it is too low, we set the partial pressure to zero. This capability is - // needed by the elemental potential method. - doublereal pres = 0.0; - double m_p0 = refPressure(); - for (size_t k = 0; k < m_kk; k++) { - tmp = -m_tmpV[k] + mu_RT[k]; - if (tmp < -600.) { - m_pp[k] = 0.0; - } else if (tmp > 500.0) { - tmp2 = tmp / 500.; - tmp2 *= tmp2; - m_pp[k] = m_p0 * exp(500.) * tmp2; - } else { - m_pp[k] = m_p0 * exp(tmp); - } - pres += m_pp[k]; - } - // set state - setState_PX(pres, &m_pp[0]); -} - bool RedlichKwongMFTP::addSpecies(shared_ptr spec) { bool added = MixtureFugacityTP::addSpecies(spec);