From 3028c14a10a61dbf02e4247629bd95ce54374473 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Tue, 22 Jan 2019 23:16:35 -0500 Subject: [PATCH] Improve setting of default energy and pressure units Only treat activation energies as a special case, rather than all molar energies. Units of activation energy can be set either explicitly or by setting units for energy and quantity. Only the case where activation energies are given as temperatures needs to be specified explicitly. Allow setting of default energy units, which allows calories to be used. Also add dyn/cm^2 as an option for pressure units. --- include/cantera/base/AnyMap.h | 15 ---- include/cantera/base/Units.h | 51 +++++++----- src/base/AnyMap.cpp | 17 ---- src/base/Units.cpp | 90 +++++++++++++------- src/kinetics/Reaction.cpp | 4 +- src/thermo/SpeciesThermoFactory.cpp | 4 +- test/data/ideal-gas.yaml | 2 +- test/data/test_subdir/species-elements.yaml | 2 +- test/general/test_units.cpp | 92 +++++++++++++++++---- 9 files changed, 170 insertions(+), 107 deletions(-) diff --git a/include/cantera/base/AnyMap.h b/include/cantera/base/AnyMap.h index f1ce0756d..7cf5f84d4 100644 --- a/include/cantera/base/AnyMap.h +++ b/include/cantera/base/AnyMap.h @@ -291,21 +291,6 @@ public: vector_fp convertVector(const std::string& key, const std::string& units, size_t nMin=npos, size_t nMax=npos) const; - //! Convert the item stored by the given `key` to the units specified in - //! `units`. If the stored value is a double, convert it using the default - //! units. If the input is a string, treat this as a dimensioned value, e.g. - //! '2.7e4 J/kmol' and convert from the specified units. - double convertMolarEnergy(const std::string& key, - const std::string& units) const; - - //! Convert the item stored by the given `key` to the units specified in - //! `units`. If the stored value is a double, convert it using the default - //! units. If the stored value is a string, treat it as a dimensioned value, - //! e.g. '2.7e4 J/kmol' and convert from the specified units. If the key is - //! missing, the `default_` value is returned. - double convertMolarEnergy(const std::string& key, const std::string& units, - double default_) const; - // Define begin() and end() to allow use with range-based for loops using const_iterator = std::unordered_map::const_iterator; const_iterator begin() const { diff --git a/include/cantera/base/Units.h b/include/cantera/base/Units.h index 59875161d..499ebf8d0 100644 --- a/include/cantera/base/Units.h +++ b/include/cantera/base/Units.h @@ -67,6 +67,7 @@ private: double m_current_dim; double m_quantity_dim; double m_pressure_dim; //!< pseudo-dimension to track explicit pressure units + double m_energy_dim; //!< pseudo-dimension to track explicit energy units friend class UnitSystem; }; @@ -90,9 +91,9 @@ 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. + * Special functions for converting activation energies allow these values to be + * expressed as either energy per quantity, energy (e.g. eV), or temperature by + * applying a factor of the Avogadro number or the gas constant where needed. * * @ingroup inputfiles */ @@ -103,12 +104,12 @@ public: UnitSystem(std::initializer_list units={}); //! Set the default units to convert from when explicit units are not - //! provided. Defaults can be set for mass, length, time, quantity, and - //! pressure. Conversion using the pressure unit is done only when the - //! target units explicitly contain pressure units. + //! provided. Defaults can be set for mass, length, time, quantity, energy, + //! and pressure. Conversion using the pressure or energy units is done only + //! when the target units explicitly contain pressure or energy units. //! - //! * To use SI+kmol: `setDefaults({"kg", "m", "s", "kmol"});` - //! * To use CGS+mol: `setDefaults({"cm", "g", "mol"});` + //! * To use SI+kmol: `setDefaults({"kg", "m", "s", "Pa", "J", "kmol"});` + //! * To use CGS+mol: `setDefaults({"cm", "g", "dyn/cm^2", "erg", "mol"});` void setDefaults(std::initializer_list units); //! Set the default units using a map of dimension to unit pairs. @@ -119,15 +120,16 @@ public: //! UnitSystem system; //! std::map defaults{ //! {"length", "m"}, {"mass", "kg"}, {"time", "s"}, - //! {"quantity", "kmol"}, {"pressure", "Pa"}, {"molar-energy", "J/kmol"} + //! {"quantity", "kmol"}, {"pressure", "Pa"}, {"energy", "J"}, + //! {"activation-energy", "J/kmol"} //! }; //! setDefaults(defaults); //! ``` void setDefaults(const std::map& units); - //! Set the default units to convert from when using the `convertMolarEnergy` - //! function. - void setDefaultMolarEnergy(const std::string& e_units); + //! Set the default units to convert from when using the + //! `convertActivationEnergy` function. + void setDefaultActivationEnergy(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, @@ -155,20 +157,20 @@ public: 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; + //! for the different dimensions that can be used for activation energies + double convertActivationEnergy(double value, const std::string& src, + const std::string& dest) const; - //! Convert `value` from the default molar energy units to the + //! Convert `value` from the default activation energy units to the //! specified units - double convertMolarEnergy(double value, const std::string& dest) const; + double convertActivationEnergy(double value, const std::string& dest) const; //! Convert a generic AnyValue node to the units specified in `dest`. If the //! input is a double, convert it using the default units. If the input is a //! string, treat this as a dimensioned value, e.g. '2.7e4 J/kmol' and //! convert from the specified units. - double convertMolarEnergy(const AnyValue& val, const std::string& dest) const; - + double convertActivationEnergy(const AnyValue& val, + const std::string& dest) const; private: //! Factor to convert mass from this unit system to kg @@ -183,11 +185,18 @@ private: //! 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 energy from this unit system to J + double m_energy_factor; + + //! Factor to convert activation energy from this unit system to J/kmol + double m_activation_energy_factor; //! Factor to convert quantity from this unit system to kmol double m_quantity_factor; + + //! True if activation energy units are set explicitly, rather than as a + //! combination of energy and quantity units + bool m_explicit_activation_energy; }; } diff --git a/src/base/AnyMap.cpp b/src/base/AnyMap.cpp index 82f5545bb..859ca4953 100644 --- a/src/base/AnyMap.cpp +++ b/src/base/AnyMap.cpp @@ -674,23 +674,6 @@ vector_fp AnyMap::convertVector(const std::string& key, const std::string& dest, return units().convert(at(key).asVector(nMin, nMax), dest); } -double AnyMap::convertMolarEnergy(const std::string& key, - const std::string& dest) const -{ - return units().convertMolarEnergy(at(key), dest); -} - -double AnyMap::convertMolarEnergy(const std::string& key, - const std::string& dest, - double default_) const -{ - if (hasKey(key)) { - return units().convertMolarEnergy(at(key), dest); - } else { - return default_; - } -} - void AnyMap::applyUnits(const UnitSystem& units) { m_units = units; diff --git a/src/base/Units.cpp b/src/base/Units.cpp index 5fbcf6c5c..e22168fd9 100644 --- a/src/base/Units.cpp +++ b/src/base/Units.cpp @@ -52,10 +52,15 @@ const std::map knownUnits{ {"erg", Units(1e-7, 1, 2, -2)}, {"eV", Units(ElectronCharge, 1, 2, -2)}, + // Force [M*L/T^2] + {"N", Units(1.0, 1, 1, -2)}, + {"dyn", Units(1e-5, 1, 1, -2)}, + // Pressure [M/L/T^2] {"Pa", Units(1.0, 1, -1, -2)}, {"atm", Units(OneAtm, 1, -1, -2)}, {"bar", Units(1.0e5, 1, -1, -2)}, + {"dyn/cm^2", Units(0.1, 1, -1, -2)}, // Volume [L^3] {"m^3", Units(1.0, 0, 3, 0)}, @@ -69,7 +74,7 @@ const std::map knownUnits{ {"V", Units(1.0, 1, 2, -3, 0, -1)}, // kg*m^2/s^3/A {"coulomb", Units(1.0, 0, 0, 1, 0, 1)}, // A*s - //! Molar energy units [M*L^2/T^2/Q] + //! Activation energy units [M*L^2/T^2/Q] {"J/kmol", Units(1.0, 1, 2, -2, 0, 0, -1)}, }; @@ -109,11 +114,17 @@ Units::Units(double factor, double mass, double length, double time, , m_current_dim(current) , m_quantity_dim(quantity) , m_pressure_dim(0) + , m_energy_dim(0) { if (mass != 0 && length == -mass && time == -2 * mass && temperature == 0 && current == 0 && quantity == 0) { // Dimension looks like Pa^n m_pressure_dim = mass; + } else if (mass != 0 && length == 2 * mass && time == -2 * mass + && temperature == 0 && current == 0 && quantity == 0) + { + // Dimesion looks like J^n + m_energy_dim = mass; } } @@ -126,6 +137,7 @@ Units::Units(const std::string& name) , m_current_dim(0) , m_quantity_dim(0) , m_pressure_dim(0) + , m_energy_dim(0) { size_t start = 0; while (true) { @@ -193,6 +205,7 @@ Units& Units::operator*=(const Units& other) m_current_dim += other.m_current_dim; m_quantity_dim += other.m_quantity_dim; m_pressure_dim += other.m_pressure_dim; + m_energy_dim += other.m_energy_dim; return *this; } @@ -217,8 +230,10 @@ UnitSystem::UnitSystem(std::initializer_list units) , m_length_factor(1.0) , m_time_factor(1.0) , m_pressure_factor(1.0) - , m_molar_energy_factor(1.0) + , m_energy_factor(1.0) + , m_activation_energy_factor(1.0) , m_quantity_factor(1.0) + , m_explicit_activation_energy(false) { setDefaults(units); } @@ -237,6 +252,8 @@ void UnitSystem::setDefaults(std::initializer_list units) m_quantity_factor = unit.factor(); } else if (unit.convertible(knownUnits.at("Pa"))) { m_pressure_factor = unit.factor(); + } else if (unit.convertible(knownUnits.at("J"))) { + m_energy_factor = unit.factor(); } else if (unit.convertible(knownUnits.at("K")) || unit.convertible(knownUnits.at("A"))) { // Do nothing -- no other scales are supported for temperature and current @@ -245,6 +262,9 @@ void UnitSystem::setDefaults(std::initializer_list units) "Unable to match unit '{}' to a basic dimension", name); } } + if (!m_explicit_activation_energy) { + m_activation_energy_factor = m_energy_factor / m_quantity_factor; + } } void UnitSystem::setDefaults(const std::map& units) @@ -266,29 +286,37 @@ void UnitSystem::setDefaults(const std::map& units) m_quantity_factor = unit.factor(); } else if (name == "pressure" && unit.convertible(knownUnits.at("Pa"))) { m_pressure_factor = unit.factor(); - } else if (name == "molar-energy" && unit.convertible(knownUnits.at("J/kmol"))) { - m_molar_energy_factor = unit.factor(); + } else if (name == "energy" && unit.convertible(knownUnits.at("J"))) { + m_energy_factor = unit.factor(); + } else if (name == "activation-energy") { + // handled separately to allow override } else { throw CanteraError("UnitSystem::setDefaults", "Unable to set default unit for '{}' to '{}' ({}).", name, item.second, unit.str()); } } + if (units.find("activation-energy") != units.end()) { + setDefaultActivationEnergy(units.at("activation-energy")); + } else if (!m_explicit_activation_energy) { + m_activation_energy_factor = m_energy_factor / m_quantity_factor; + } } -void UnitSystem::setDefaultMolarEnergy(const std::string& e_units) +void UnitSystem::setDefaultActivationEnergy(const std::string& e_units) { Units u(e_units); if (u.convertible(Units("J/kmol"))) { - m_molar_energy_factor = u.factor(); + m_activation_energy_factor = u.factor(); } else if (u.convertible(knownUnits.at("K"))) { - m_molar_energy_factor = GasConstant; + m_activation_energy_factor = GasConstant; } else if (u.convertible(knownUnits.at("eV"))) { - m_molar_energy_factor = u.factor() * Avogadro; + m_activation_energy_factor = u.factor() * Avogadro; } else { - throw CanteraError("Units::setDefaultMolarEnergy", - "Unable to match unit '{}' to a unit of molar energy", e_units); + throw CanteraError("Units::setDefaultActivationEnergy", + "Unable to match unit '{}' to a unit of activation energy", e_units); } + m_explicit_activation_energy = true; } double UnitSystem::convert(double value, const std::string& src, @@ -315,11 +343,12 @@ double UnitSystem::convert(double value, const std::string& dest) const double UnitSystem::convert(double value, const Units& dest) const { return value / dest.factor() - * pow(m_mass_factor, dest.m_mass_dim - dest.m_pressure_dim) - * pow(m_length_factor, dest.m_length_dim + dest.m_pressure_dim) - * pow(m_time_factor, dest.m_time_dim + 2*dest.m_pressure_dim) + * pow(m_mass_factor, dest.m_mass_dim - dest.m_pressure_dim - dest.m_energy_dim) + * pow(m_length_factor, dest.m_length_dim + dest.m_pressure_dim - 2*dest.m_energy_dim) + * pow(m_time_factor, dest.m_time_dim + 2*dest.m_pressure_dim + 2*dest.m_energy_dim) * pow(m_quantity_factor, dest.m_quantity_dim) - * pow(m_pressure_factor, dest.m_pressure_dim); + * pow(m_pressure_factor, dest.m_pressure_dim) + * pow(m_energy_factor, dest.m_energy_dim); } static std::pair split_unit(const AnyValue& v) { @@ -373,8 +402,8 @@ vector_fp UnitSystem::convert(const std::vector& vals, return out; } -double UnitSystem::convertMolarEnergy(double value, const std::string& src, - const std::string& dest) const +double UnitSystem::convertActivationEnergy(double value, const std::string& src, + const std::string& dest) const { // Convert to J/kmol Units usrc(src); @@ -385,8 +414,8 @@ double UnitSystem::convertMolarEnergy(double value, const std::string& src, } else if (usrc.convertible(Units("eV"))) { value *= Avogadro * usrc.factor(); } else { - throw CanteraError("UnitSystem::convertMolarEnergy", - "Don't understand units '{}' as a molar energy", src); + throw CanteraError("UnitSystem::convertActivationEnergy", + "Don't understand units '{}' as an activation energy", src); } // Convert from J/kmol @@ -398,38 +427,39 @@ double UnitSystem::convertMolarEnergy(double value, const std::string& src, } else if (udest.convertible(Units("eV"))) { value /= Avogadro * udest.factor(); } else { - throw CanteraError("UnitSystem::convertMolarEnergy", - "Don't understand units '{}' as a molar energy", dest); + throw CanteraError("UnitSystem::convertActivationEnergy", + "Don't understand units '{}' as an activation energy", dest); } return value; } -double UnitSystem::convertMolarEnergy(double value, const std::string& dest) const +double UnitSystem::convertActivationEnergy(double value, + const std::string& dest) const { Units udest(dest); if (udest.convertible(Units("J/kmol"))) { - return value * m_molar_energy_factor / udest.factor(); + return value * m_activation_energy_factor / udest.factor(); } else if (udest.convertible(knownUnits.at("K"))) { - return value * m_molar_energy_factor / GasConstant; + return value * m_activation_energy_factor / GasConstant; } else if (udest.convertible(knownUnits.at("eV"))) { - return value * m_molar_energy_factor / (Avogadro * udest.factor()); + return value * m_activation_energy_factor / (Avogadro * udest.factor()); } else { - throw CanteraError("UnitSystem::convertMolarEnergy", - "'{}' is not a unit of molar energy", dest); + throw CanteraError("UnitSystem::convertActivationEnergy", + "'{}' is not a unit of activation energy", dest); } } -double UnitSystem::convertMolarEnergy(const AnyValue& v, - const std::string& dest) const +double UnitSystem::convertActivationEnergy(const AnyValue& v, + const std::string& dest) const { auto val_units = split_unit(v); if (val_units.second.empty()) { // Just a value, so convert using default units - return convertMolarEnergy(val_units.first, dest); + return convertActivationEnergy(val_units.first, dest); } else { // Both source and destination units are explicit - return convertMolarEnergy(val_units.first, val_units.second, dest); + return convertActivationEnergy(val_units.first, val_units.second, dest); } } diff --git a/src/kinetics/Reaction.cpp b/src/kinetics/Reaction.cpp index b602aa4ce..8f294ce0b 100644 --- a/src/kinetics/Reaction.cpp +++ b/src/kinetics/Reaction.cpp @@ -324,12 +324,12 @@ Arrhenius readArrhenius(const Reaction& R, const AnyValue& rate, auto& rate_map = rate.as(); A = units.convert(rate_map["A"], rc_units); b = rate_map["b"].asDouble(); - Ta = rate_map.convertMolarEnergy("Ea", "K"); + Ta = units.convertActivationEnergy(rate_map["Ea"], "K"); } else { auto& rate_vec = rate.asVector(3); A = units.convert(rate_vec[0], rc_units); b = rate_vec[1].asDouble(); - Ta = units.convertMolarEnergy(rate_vec[2], "K"); + Ta = units.convertActivationEnergy(rate_vec[2], "K"); } return Arrhenius(A, b, Ta); } diff --git a/src/thermo/SpeciesThermoFactory.cpp b/src/thermo/SpeciesThermoFactory.cpp index 87e30c66d..c9a050fe8 100644 --- a/src/thermo/SpeciesThermoFactory.cpp +++ b/src/thermo/SpeciesThermoFactory.cpp @@ -369,14 +369,14 @@ void setupMu0(Mu0Poly& thermo, const AnyMap& node) { setupSpeciesThermo(thermo, node); bool dimensionless = node.getBool("dimensionless", false); - double h0 = node.convertMolarEnergy("h0", "J/kmol", 0.0); + double h0 = node.convert("h0", "J/kmol", 0.0); map T_mu; for (const auto& item : node["data"]) { double T = node.units().convert(fpValueCheck(item.first), "K"); if (dimensionless) { T_mu[T] = item.second.asDouble() * GasConstant * T; } else { - T_mu[T] = node.units().convertMolarEnergy(item.second, "J/kmol"); + T_mu[T] = node.units().convert(item.second, "J/kmol"); } } thermo.setParameters(h0, T_mu); diff --git a/test/data/ideal-gas.yaml b/test/data/ideal-gas.yaml index 2e6e7985f..ff8145f3a 100644 --- a/test/data/ideal-gas.yaml +++ b/test/data/ideal-gas.yaml @@ -1,4 +1,4 @@ -units: {length: cm, time: s, quantity: mol, molar-energy: cal/mol} +units: {length: cm, time: s, quantity: mol, energy: cal} phases: - name: simple diff --git a/test/data/test_subdir/species-elements.yaml b/test/data/test_subdir/species-elements.yaml index 0888e1415..78fbf23ec 100644 --- a/test/data/test_subdir/species-elements.yaml +++ b/test/data/test_subdir/species-elements.yaml @@ -1,4 +1,4 @@ -units: {length: cm, time: s, quantity: mol, molar-energy: cal/mol} +units: {length: cm, time: s, quantity: mol, energy: cal} isotopes: - symbol: Ar diff --git a/test/general/test_units.cpp b/test/general/test_units.cpp index f21dee317..951b060c2 100644 --- a/test/general/test_units.cpp +++ b/test/general/test_units.cpp @@ -40,8 +40,8 @@ TEST(Units, prefixes) { EXPECT_DOUBLE_EQ(U.convert(1.0, "m/s", "km/hr"), 3.6); } -TEST(Units, with_defaults) { - UnitSystem U({"cm", "g", "mol", "atm"}); +TEST(Units, with_defaults1) { + UnitSystem U({"cm", "g", "mol", "atm", "kcal"}); EXPECT_DOUBLE_EQ(U.convert(1.0, "m"), 0.01); EXPECT_DOUBLE_EQ(U.convert(1.0, "kmol/m^3"), 1000); EXPECT_DOUBLE_EQ(U.convert(1.0, "kg/kmol"), 1.0); @@ -49,12 +49,19 @@ TEST(Units, with_defaults) { EXPECT_DOUBLE_EQ(U.convert(1.0, "Pa"), 101325); 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); + EXPECT_DOUBLE_EQ(U.convert(1.0, "J"), 4184); +} + +TEST(Units, with_defaults2) { + UnitSystem U({"dyn/cm^2"}); + EXPECT_DOUBLE_EQ(U.convert(1.0, "Pa"), 0.1); + EXPECT_DOUBLE_EQ(U.convert(1.0, "N/m^2"), 1.0); } TEST(Units, with_defaults_map) { std::map defaults{ {"length", "cm"}, {"mass", "g"}, {"quantity", "mol"}, - {"pressure", "atm"} + {"pressure", "atm"}, {"energy", "J"} }; UnitSystem U; U.setDefaults(defaults); @@ -65,7 +72,7 @@ TEST(Units, with_defaults_map) { EXPECT_DOUBLE_EQ(U.convert(1.0, "Pa"), 101325); 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); - + EXPECT_DOUBLE_EQ(U.convert(1.0, "J/cm^3"), 1.0); } TEST(Units, bad_defaults) { @@ -77,22 +84,55 @@ TEST(Units, bad_defaults) { } -TEST(Units, activation_energies) { +TEST(Units, activation_energies1) { 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); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "J/kmol", "J/mol"), 1.0); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(100, "K", "K"), 100); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(500, "K", "J/kmol"), 500 * GasConstant); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(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); +TEST(Units, activation_energies2) { + UnitSystem U; + U.setDefaultActivationEnergy("cal/mol"); + U.setDefaults({"cm", "g", "J"}); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "cal/mol"), 1000); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "J/kmol"), 4184e3); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(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); +TEST(Units, activation_energies3) { + UnitSystem U({"cal", "mol"}); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "cal/mol"), 1000); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "J/kmol"), 4184e3); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1000, "K"), 4184e3 / GasConstant); +} + +TEST(Units, activation_energies4) { + UnitSystem U; + U.setDefaultActivationEnergy("K"); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(2000, "K"), 2000); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(2000, "J/kmol"), 2000 * GasConstant); +} + +TEST(Units, activation_energies5) { + UnitSystem U; + std::map defaults{ + {"quantity", "mol"}, {"energy", "cal"}, {"activation-energy", "K"} + }; + U.setDefaults(defaults); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(2000, "K"), 2000); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(2000, "J/kmol"), 2000 * GasConstant); +} + +TEST(Units, activation_energies6) { + UnitSystem U; + std::map defaults{ + {"activation-energy", "eV"} + }; + U.setDefaults(defaults); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1, "J/kmol"), ElectronCharge * Avogadro); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(1, "eV"), 1.0); } TEST(Units, from_anymap) { @@ -107,7 +147,7 @@ TEST(Units, from_anymap) { EXPECT_DOUBLE_EQ(m.convert("V", "m^3"), 1e-9); auto k1 = m["k1"].asVector(); EXPECT_DOUBLE_EQ(U.convert(k1[0], "m^3/kmol"), 1e-9*5e2); - EXPECT_DOUBLE_EQ(U.convertMolarEnergy(k1[2], "J/kmol"), 29000); + EXPECT_DOUBLE_EQ(U.convertActivationEnergy(k1[2], "J/kmol"), 29000); } TEST(Units, from_anymap_default) { @@ -141,3 +181,19 @@ TEST(Units, from_yaml) { EXPECT_DOUBLE_EQ(spam[0].convert("eggs", "m"), 3000); EXPECT_DOUBLE_EQ(spam[1].convertVector("ham", "m")[2], 500); } + +TEST(Units, act_energy_from_yaml) { + AnyMap m = AnyMap::fromYamlString( + "units: {energy: J, quantity: mol, activation-energy: K}\n" + "foo:\n" + "- units: {quantity: kmol}\n" // applies to items in foo + "- bar: 0.6\n" + "- baz: 0.2\n" + " units: {energy: kJ}\n" // applies to just this entry (with "baz") + ); + auto& foo = m["foo"].asVector(); + EXPECT_DOUBLE_EQ(foo[0].units().convertActivationEnergy(foo[0]["bar"], "K"), 0.6); + EXPECT_DOUBLE_EQ(foo[1].units().convertActivationEnergy(foo[1]["baz"], "K"), 0.2); + EXPECT_DOUBLE_EQ(foo[0].convert("bar", "J/mol"), 0.0006); + EXPECT_DOUBLE_EQ(foo[1].convert("baz", "J/mol"), 0.2); +}