diff --git a/include/cantera/base/Units.h b/include/cantera/base/Units.h index 8c72b7ed0..482de891f 100644 --- a/include/cantera/base/Units.h +++ b/include/cantera/base/Units.h @@ -87,6 +87,10 @@ private: * * Metric prefixes are recognized for all units, e.g. nm, hPa, mg, EJ, mL, kcal. * + * Special functions for converting molar energies (e.g. activation energies) + * allow these values to be expressed as either energy per quantity or + * temperature by applying a factor of the gas constant where needed. + * * @ingroup inputfiles */ class UnitSystem @@ -104,6 +108,10 @@ public: //! * To use CGS+mol: `setDefaults({"cm", "g", "mol"});` void setDefaults(std::initializer_list units); + //! Set the default units to convert from when using the `convertMolarEnergy` + //! function. + void setDefaultMolarEnergy(const std::string& e_units); + //! Convert `value` from the units of `src` to the units of `dest`. double convert(double value, const std::string& src, const std::string& dest) const; @@ -113,6 +121,15 @@ public: double convert(double value, const std::string& dest) const; double convert(double value, const Units& dest) const; + //! Convert `value` from the units of `src` to the units of `dest`, allowing + //! for the different dimensions that can be used for molar energies + double convertMolarEnergy(double value, const std::string& src, + const std::string& dest) const; + + //! Convert `value` from the default molar energy units to the + //! specified units + double convertMolarEnergy(double value, const std::string& dest) const; + private: //! Factor to convert mass from this unit system to kg double m_mass_factor; @@ -123,12 +140,12 @@ private: //! Factor to convert time from this unit system to seconds double m_time_factor; - //! Factor to convert energy from this unit system to Joules - double m_energy_factor; - //! Factor to convert pressure from this unit system to Pa double m_pressure_factor; + //! Factor to convert molar energy from this unit system to J/kmol + double m_molar_energy_factor; + //! Factor to convert quantity from this unit system to kmol double m_quantity_factor; }; diff --git a/src/base/Units.cpp b/src/base/Units.cpp index a8ea6d66d..0630a94a9 100644 --- a/src/base/Units.cpp +++ b/src/base/Units.cpp @@ -214,8 +214,8 @@ UnitSystem::UnitSystem(std::initializer_list units) : m_mass_factor(1.0) , m_length_factor(1.0) , m_time_factor(1.0) - , m_energy_factor(1.0) , m_pressure_factor(1.0) + , m_molar_energy_factor(1.0) , m_quantity_factor(1.0) { setDefaults(units); @@ -245,6 +245,21 @@ void UnitSystem::setDefaults(std::initializer_list units) } } +void UnitSystem::setDefaultMolarEnergy(const std::string& e_units) +{ + Units u(e_units); + if (u.convertible(Units("J/kmol"))) { + m_molar_energy_factor = u.factor(); + } else if (u.convertible(knownUnits.at("K"))) { + m_molar_energy_factor = GasConstant; + } else if (u.convertible(knownUnits.at("eV"))) { + m_molar_energy_factor = u.factor() * Avogadro; + } else { + throw CanteraError("Units::setDefaultMolarEnergy", + "Unable to match unit '{}' to a unit of molar energy", e_units); + } +} + double UnitSystem::convert(double value, const std::string& src, const std::string& dest) const { @@ -276,4 +291,50 @@ double UnitSystem::convert(double value, const Units& dest) const * pow(m_pressure_factor, dest.m_pressure_dim); } +double UnitSystem::convertMolarEnergy(double value, const std::string& src, + const std::string& dest) const +{ + // Convert to J/kmol + Units usrc(src); + if (usrc.convertible(Units("J/kmol"))) { + value *= usrc.factor(); + } else if (usrc.convertible(Units("K"))) { + value *= GasConstant * usrc.factor(); + } else if (usrc.convertible(Units("eV"))) { + value *= Avogadro * usrc.factor(); + } else { + throw CanteraError("UnitSystem::convertMolarEnergy", + "Don't understand units '{}' as a molar energy", src); + } + + // Convert from J/kmol + Units udest(dest); + if (udest.convertible(Units("J/kmol"))) { + value /= udest.factor(); + } else if (udest.convertible(Units("K"))) { + value /= GasConstant * udest.factor(); + } else if (udest.convertible(Units("eV"))) { + value /= Avogadro * udest.factor(); + } else { + throw CanteraError("UnitSystem::convertMolarEnergy", + "Don't understand units '{}' as a molar energy", dest); + } + + return value; +} +double UnitSystem::convertMolarEnergy(double value, const std::string& dest) const +{ + Units udest(dest); + if (udest.convertible(Units("J/kmol"))) { + return value * m_molar_energy_factor / udest.factor(); + } else if (udest.convertible(knownUnits.at("K"))) { + return value * m_molar_energy_factor / GasConstant; + } else if (udest.convertible(knownUnits.at("eV"))) { + return value * m_molar_energy_factor / (Avogadro * udest.factor()); + } else { + throw CanteraError("UnitSystem::convertMolarEnergy", + "'{}' is not a unit of molar energy", dest); + } +} + } diff --git a/test/general/test_units.cpp b/test/general/test_units.cpp index b0c25c896..33307b846 100644 --- a/test/general/test_units.cpp +++ b/test/general/test_units.cpp @@ -49,3 +49,21 @@ TEST(Units, with_defaults) { EXPECT_DOUBLE_EQ(U.convert(1.0, "hPa"), 1013.25); EXPECT_DOUBLE_EQ(U.convert(1.0, "Pa*m^6/kmol"), 101325*1e-12*1000); } + +TEST(Units, activation_energies) { + UnitSystem U; + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(1000, "J/kmol", "J/mol"), 1.0); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(100, "K", "K"), 100); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(500, "K", "J/kmol"), 500 * GasConstant); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(3, "J/mol", "K"), 3000 / GasConstant); + + U.setDefaults({"cm", "g"}); + U.setDefaultMolarEnergy("cal/mol"); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(1000, "cal/mol"), 1000); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(1000, "J/kmol"), 4184e3); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(1000, "K"), 4184e3 / GasConstant); + + U.setDefaultMolarEnergy("K"); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(2000, "K"), 2000); + EXPECT_DOUBLE_EQ(U.convertMolarEnergy(2000, "J/kmol"), 2000 * GasConstant); +}