15 const std::map<std::string, Units> knownUnits{
20 {
"kg",
Units(1.0, 1, 0, 0)},
21 {
"g",
Units(1e-3, 1, 0, 0)},
24 {
"m",
Units(1.0, 0, 1, 0)},
25 {
"micron",
Units(1e-6, 0, 1, 0)},
26 {
"angstrom",
Units(1e-10, 0, 1, 0)},
27 {
"Å",
Units(1e-10, 0, 1, 0)},
30 {
"s",
Units(1.0, 0, 0, 1)},
31 {
"min",
Units(60, 0, 0, 1)},
32 {
"hr",
Units(3600, 0, 0, 1)},
35 {
"K",
Units(1.0, 0, 0, 0, 1)},
36 {
"C",
Units(1.0, 0, 0, 0, 1)},
39 {
"A",
Units(1.0, 0, 0, 0, 0, 1)},
42 {
"mol",
Units(1e-3, 0, 0, 0, 0, 0, 1)},
43 {
"gmol",
Units(1e-3, 0, 0, 0, 0, 0, 1)},
44 {
"mole",
Units(1e-3, 0, 0, 0, 0, 0, 1)},
45 {
"kmol",
Units(1.0, 0, 0, 0, 0, 0, 1)},
46 {
"kgmol",
Units(1.0, 0, 0, 0, 0, 0, 1)},
50 {
"J",
Units(1.0, 1, 2, -2)},
51 {
"cal",
Units(4.184, 1, 2, -2)},
52 {
"erg",
Units(1e-7, 1, 2, -2)},
56 {
"N",
Units(1.0, 1, 1, -2)},
57 {
"dyn",
Units(1e-5, 1, 1, -2)},
60 {
"Pa",
Units(1.0, 1, -1, -2)},
62 {
"bar",
Units(1.0e5, 1, -1, -2)},
63 {
"dyn/cm^2",
Units(0.1, 1, -1, -2)},
66 {
"m^3",
Units(1.0, 0, 3, 0)},
67 {
"liter",
Units(0.001, 0, 3, 0)},
68 {
"L",
Units(0.001, 0, 3, 0)},
69 {
"l",
Units(0.001, 0, 3, 0)},
70 {
"cc",
Units(1.0e-6, 0, 3, 0)},
73 {
"ohm",
Units(1.0, 1, 2, -3, 0, -2)},
74 {
"V",
Units(1.0, 1, 2, -3, 0, -1)},
75 {
"coulomb",
Units(1.0, 0, 0, 1, 0, 1)},
78 {
"J/kmol",
Units(1.0, 1, 2, -2, 0, 0, -1)},
81 const std::map<std::string, double> prefixes{
108 double temperature,
double current,
double quantity)
111 , m_length_dim(length)
113 , m_temperature_dim(temperature)
114 , m_current_dim(current)
115 , m_quantity_dim(quantity)
119 if (mass != 0 && length == -mass && time == -2 * mass
120 && temperature == 0 && current == 0 && quantity == 0) {
123 }
else if (mass != 0 && length == 2 * mass && time == -2 * mass
124 && temperature == 0 && current == 0 && quantity == 0)
136 , m_temperature_dim(0)
145 size_t stop = name.find_first_of(
"*/", start);
146 size_t carat = name.find(
'^', start);
152 name.substr(start, std::min(carat, stop) - start));
154 double exponent = 1.0;
156 exponent =
fpValueCheck(name.substr(carat+1, stop-carat-1));
158 if (start != 0 && name[start-1] ==
'/') {
160 exponent = -exponent;
163 if (knownUnits.find(unit) != knownUnits.end()) {
165 *
this *= knownUnits.at(unit).pow(exponent);
168 std::string prefix = unit.substr(0, 1);
169 std::string suffix = unit.substr(1);
170 if (prefixes.find(prefix) != prefixes.end() &&
171 knownUnits.find(suffix) != knownUnits.end()) {
172 Units u = knownUnits.at(suffix);
173 u.
scale(prefixes.at(prefix));
174 *
this *= u.
pow(exponent);
177 "Unknown unit '{}' in unit string '{}'", unit, name);
190 return (m_mass_dim == other.m_mass_dim &&
191 m_length_dim == other.m_length_dim &&
192 m_time_dim == other.m_time_dim &&
193 m_temperature_dim == other.m_temperature_dim &&
194 m_current_dim == other.m_current_dim &&
195 m_quantity_dim == other.m_quantity_dim);
201 m_mass_dim += other.m_mass_dim;
202 m_length_dim += other.m_length_dim;
203 m_time_dim += other.m_time_dim;
204 m_temperature_dim += other.m_temperature_dim;
205 m_current_dim += other.m_current_dim;
206 m_quantity_dim += other.m_quantity_dim;
214 m_mass_dim * exponent,
215 m_length_dim * exponent,
216 m_time_dim * exponent,
217 m_temperature_dim * exponent,
218 m_current_dim * exponent,
219 m_quantity_dim * exponent);
223 return fmt::format(
"Units({} kg^{} * m^{} * s^{} * K^{} * A^{} * kmol^{})",
224 m_factor, m_mass_dim, m_length_dim, m_time_dim,
225 m_temperature_dim, m_current_dim, m_quantity_dim);
230 , m_length_factor(1.0)
232 , m_pressure_factor(1.0)
233 , m_energy_factor(1.0)
234 , m_activation_energy_factor(1.0)
235 , m_quantity_factor(1.0)
236 , m_explicit_activation_energy(false)
243 for (
const auto& name : units) {
244 auto unit =
Units(name);
245 if (unit.convertible(knownUnits.at(
"kg"))) {
247 }
else if (unit.convertible(knownUnits.at(
"m"))) {
249 }
else if (unit.convertible(knownUnits.at(
"s"))) {
251 }
else if (unit.convertible(knownUnits.at(
"kmol"))) {
253 }
else if (unit.convertible(knownUnits.at(
"Pa"))) {
255 }
else if (unit.convertible(knownUnits.at(
"J"))) {
257 }
else if (unit.convertible(knownUnits.at(
"K"))
258 || unit.convertible(knownUnits.at(
"A"))) {
262 "Unable to match unit '{}' to a basic dimension", name);
272 for (
const auto& item : units) {
273 auto& name = item.first;
274 Units unit(item.second);
275 if (name ==
"mass" && unit.
convertible(knownUnits.at(
"kg"))) {
277 }
else if (name ==
"length" && unit.
convertible(knownUnits.at(
"m"))) {
279 }
else if (name ==
"time" && unit.
convertible(knownUnits.at(
"s"))) {
281 }
else if (name ==
"temperature" && item.second ==
"K") {
283 }
else if (name ==
"current" && item.second ==
"A") {
285 }
else if (name ==
"quantity" && unit.
convertible(knownUnits.at(
"kmol"))) {
287 }
else if (name ==
"pressure" && unit.
convertible(knownUnits.at(
"Pa"))) {
289 }
else if (name ==
"energy" && unit.
convertible(knownUnits.at(
"J"))) {
291 }
else if (name ==
"activation-energy") {
295 "Unable to set default unit for '{}' to '{}' ({}).",
296 name, item.second, unit.
str());
299 if (units.find(
"activation-energy") != units.end()) {
317 "Unable to match unit '{}' to a unit of activation energy", e_units);
323 const std::string& dest)
const
329 const Units& dest)
const
333 "Incompatible units:\n {} and\n {}", src.
str(), dest.
str());
345 return value / dest.
factor()
354 static std::pair<double, std::string> split_unit(
const AnyValue& v) {
355 if (v.
is<std::string>()) {
357 std::string val_units = v.
asString();
358 size_t space = val_units.find(
" ");
361 "Couldn't parse '{}' as a space-separated value/unit pair\n",
365 val_units.substr(space+1)};
379 auto val_units = split_unit(v);
380 if (val_units.second.empty()) {
382 return convert(val_units.first, dest);
385 return convert(val_units.first,
Units(val_units.second), dest);
390 const std::string& dest)
const
396 const Units& dest)
const
399 for (
const auto& val : vals) {
400 out.emplace_back(
convert(val, dest));
406 const std::string& dest)
const
417 throw CanteraError(
"UnitSystem::convertActivationEnergy",
418 "Don't understand units '{}' as an activation energy", src);
430 throw CanteraError(
"UnitSystem::convertActivationEnergy",
431 "Don't understand units '{}' as an activation energy", dest);
438 const std::string& dest)
const
443 }
else if (udest.
convertible(knownUnits.at(
"K"))) {
445 }
else if (udest.
convertible(knownUnits.at(
"eV"))) {
448 throw CanteraError(
"UnitSystem::convertActivationEnergy",
449 "'{}' is not a unit of activation energy", dest);
454 const std::string& dest)
const
456 auto val_units = split_unit(v);
457 if (val_units.second.empty()) {