From 6e3053dd1cf6815cc0ea968edbf71f76738b4af6 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Tue, 18 Dec 2018 14:17:14 -0500 Subject: [PATCH] Add function for setting default units from a std::map This is the form that will be used when reading units from a YAML input file. --- include/cantera/base/Units.h | 14 ++++++++++++++ src/base/Units.cpp | 32 ++++++++++++++++++++++++++++++++ test/general/test_units.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/include/cantera/base/Units.h b/include/cantera/base/Units.h index 03504fb66..2bf9d6fc5 100644 --- a/include/cantera/base/Units.h +++ b/include/cantera/base/Units.h @@ -111,6 +111,20 @@ public: //! * To use CGS+mol: `setDefaults({"cm", "g", "mol"});` void setDefaults(std::initializer_list units); + //! Set the default units using a map of dimension to unit pairs. + //! + //! Defaults for dimensions not specified will be left unchanged. To use + //! Cantera's default units: + //! ``` + //! UnitSystem system; + //! std::map defaults{ + //! {"length", "m"}, {"mass", "kg"}, {"time", "s"}, + //! {"quantity", "kmol"}, {"pressure", "Pa"}, {"molar-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); diff --git a/src/base/Units.cpp b/src/base/Units.cpp index 5ab9303f5..19bae0487 100644 --- a/src/base/Units.cpp +++ b/src/base/Units.cpp @@ -68,6 +68,9 @@ const std::map knownUnits{ {"ohm", Units(1.0, 1, 2, -3, 0, -2)}, // kg*m^2/s^3/A^2 {"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] + {"J/kmol", Units(1.0, 1, 2, -2, 0, 0, -1)}, }; const std::map prefixes{ @@ -245,6 +248,35 @@ void UnitSystem::setDefaults(std::initializer_list units) } } +void UnitSystem::setDefaults(const std::map& units) +{ + for (const auto& item : units) { + auto& name = item.first; + Units unit(item.second); + if (name == "mass" && unit.convertible(knownUnits.at("kg"))) { + m_mass_factor = unit.factor(); + } else if (name == "length" && unit.convertible(knownUnits.at("m"))) { + m_length_factor = unit.factor(); + } else if (name == "time" && unit.convertible(knownUnits.at("s"))) { + m_time_factor = unit.factor(); + } else if (name == "temperature" && item.second == "K") { + // do nothing - no other temperature scales are supported + } else if (name == "current" && item.second == "A") { + // do nothing - no other current scales are supported + } else if (name == "quantity" && unit.convertible(knownUnits.at("kmol"))) { + 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 { + throw CanteraError("UnitSystem::setDefaults", + "Unable to set default unit for '{}' to '{}' ({}).", + name, item.second, unit.str()); + } + } +} + void UnitSystem::setDefaultMolarEnergy(const std::string& e_units) { Units u(e_units); diff --git a/test/general/test_units.cpp b/test/general/test_units.cpp index 330edb0b3..26e5dcdfd 100644 --- a/test/general/test_units.cpp +++ b/test/general/test_units.cpp @@ -51,6 +51,32 @@ TEST(Units, with_defaults) { EXPECT_DOUBLE_EQ(U.convert(1.0, "Pa*m^6/kmol"), 101325*1e-12*1000); } +TEST(Units, with_defaults_map) { + std::map defaults{ + {"length", "cm"}, {"mass", "g"}, {"quantity", "mol"}, + {"pressure", "atm"} + }; + UnitSystem U; + U.setDefaults(defaults); + 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); + EXPECT_DOUBLE_EQ(U.convert(1.0, "cm^2"), 1.0); + 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); + +} + +TEST(Units, bad_defaults) { + UnitSystem U; + std::map bad_key{{"length", "m"}, {"joy", "MJ"}}; + EXPECT_THROW(U.setDefaults(bad_key), CanteraError); + std::map bad_value{{"length", "m"}, {"time", "J"}}; + EXPECT_THROW(U.setDefaults(bad_value), CanteraError); +} + + TEST(Units, activation_energies) { UnitSystem U; EXPECT_DOUBLE_EQ(U.convertMolarEnergy(1000, "J/kmol", "J/mol"), 1.0);