Cantera 2.6.0
Units.cpp
Go to the documentation of this file.
1//! @file Units.cpp
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
10#include "cantera/base/AnyMap.h"
12#include <regex>
13
14namespace {
15using namespace Cantera;
16
17const std::map<std::string, Units> knownUnits{
18 {"", Units(1.0)},
19 {"1", Units(1.0)},
20
21 // Mass [M]
22 {"kg", Units(1.0, 1, 0, 0)},
23 {"g", Units(1e-3, 1, 0, 0)},
24
25 // Length [L]
26 {"m", Units(1.0, 0, 1, 0)},
27 {"micron", Units(1e-6, 0, 1, 0)},
28 {"angstrom", Units(1e-10, 0, 1, 0)},
29 {"Å", Units(1e-10, 0, 1, 0)},
30
31 // Time [T]
32 {"s", Units(1.0, 0, 0, 1)},
33 {"min", Units(60, 0, 0, 1)},
34 {"hr", Units(3600, 0, 0, 1)},
35
36 // Temperature [K]
37 {"K", Units(1.0, 0, 0, 0, 1)},
38 {"C", Units(1.0, 0, 0, 0, 1)},
39
40 // Current [A]
41 {"A", Units(1.0, 0, 0, 0, 0, 1)},
42
43 // Quantity [Q]
44 {"mol", Units(1e-3, 0, 0, 0, 0, 0, 1)},
45 {"gmol", Units(1e-3, 0, 0, 0, 0, 0, 1)},
46 {"mole", Units(1e-3, 0, 0, 0, 0, 0, 1)},
47 {"kmol", Units(1.0, 0, 0, 0, 0, 0, 1)},
48 {"kgmol", Units(1.0, 0, 0, 0, 0, 0, 1)},
49 {"molec", Units(1.0/Avogadro, 0, 0, 0, 0, 0, 1)},
50
51 // Energy [M*L^2/T^2]
52 {"J", Units(1.0, 1, 2, -2)},
53 {"cal", Units(4.184, 1, 2, -2)},
54 {"erg", Units(1e-7, 1, 2, -2)},
55 {"eV", Units(ElectronCharge, 1, 2, -2)},
56
57 // Force [M*L/T^2]
58 {"N", Units(1.0, 1, 1, -2)},
59 {"dyn", Units(1e-5, 1, 1, -2)},
60
61 // Pressure [M/L/T^2]
62 {"Pa", Units(1.0, 1, -1, -2)},
63 {"atm", Units(OneAtm, 1, -1, -2)},
64 {"bar", Units(1.0e5, 1, -1, -2)},
65 {"dyn/cm^2", Units(0.1, 1, -1, -2)},
66
67 // Volume [L^3]
68 {"m^3", Units(1.0, 0, 3, 0)},
69 {"liter", Units(0.001, 0, 3, 0)},
70 {"L", Units(0.001, 0, 3, 0)},
71 {"l", Units(0.001, 0, 3, 0)},
72 {"cc", Units(1.0e-6, 0, 3, 0)},
73
74 // Other electrical units
75 {"ohm", Units(1.0, 1, 2, -3, 0, -2)}, // kg*m^2/s^3/A^2
76 {"V", Units(1.0, 1, 2, -3, 0, -1)}, // kg*m^2/s^3/A
77 {"coulomb", Units(1.0, 0, 0, 1, 0, 1)}, // A*s
78
79 //! Activation energy units [M*L^2/T^2/Q]
80 {"J/kmol", Units(1.0, 1, 2, -2, 0, 0, -1)},
81};
82
83const std::map<std::string, double> prefixes{
84 {"Y", 1e24},
85 {"Z", 1e21},
86 {"E", 1e18},
87 {"P", 1e15},
88 {"T", 1e12},
89 {"G", 1e9},
90 {"M", 1e6},
91 {"k", 1e3},
92 {"h", 1e2},
93 {"d", 1e-1},
94 {"c", 1e-2},
95 {"m", 1e-3},
96 {"u", 1e-6},
97 {"n", 1e-9},
98 {"p", 1e-12},
99 {"f", 1e-15},
100 {"a", 1e-18},
101 {"z", 1e-21},
102 {"y", 1e-24}
103};
104}
105
106namespace Cantera
107{
108
109Units::Units(double factor, double mass, double length, double time,
110 double temperature, double current, double quantity)
111 : m_factor(factor)
112 , m_mass_dim(mass)
113 , m_length_dim(length)
114 , m_time_dim(time)
115 , m_temperature_dim(temperature)
116 , m_current_dim(current)
117 , m_quantity_dim(quantity)
118 , m_pressure_dim(0)
119 , m_energy_dim(0)
120{
121 if (mass != 0 && length == -mass && time == -2 * mass
122 && temperature == 0 && current == 0 && quantity == 0) {
123 // Dimension looks like Pa^n
124 m_pressure_dim = mass;
125 } else if (mass != 0 && length == 2 * mass && time == -2 * mass
126 && temperature == 0 && current == 0 && quantity == 0)
127 {
128 // Dimension looks like J^n
129 m_energy_dim = mass;
130 }
131}
132
133Units::Units(const std::string& name, bool force_unity)
134 : m_factor(1.0)
135 , m_mass_dim(0)
136 , m_length_dim(0)
137 , m_time_dim(0)
138 , m_temperature_dim(0)
139 , m_current_dim(0)
140 , m_quantity_dim(0)
141 , m_pressure_dim(0)
142 , m_energy_dim(0)
143{
144 size_t start = 0;
145
146 // Determine factor
147 static std::regex regexp("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)");
148 std::smatch matched;
149 std::regex_search(name, matched, regexp);
150 if (matched.size()) {
151 std::string factor = *matched.begin();
152 if (name.find(factor) == 0) {
154 start = factor.size();
155 }
156 }
157
158 while (true) {
159 // Split into groups of the form 'unit^exponent'
160 size_t stop = name.find_first_of("*/", start);
161 size_t caret = name.find('^', start);
162 if (caret > stop) {
163 // No caret in this group
164 caret = npos;
165 }
166 std::string unit = trimCopy(
167 name.substr(start, std::min(caret, stop) - start));
168
169 double exponent = 1.0;
170 if (caret != npos) {
171 exponent = fpValueCheck(name.substr(caret+1, stop-caret-1));
172 }
173 if (start != 0 && name[start-1] == '/') {
174 // This unit is in the denominator
175 exponent = -exponent;
176 }
177
178 if (knownUnits.find(unit) != knownUnits.end()) {
179 // Incorporate the unit defined by the current group
180 *this *= knownUnits.at(unit).pow(exponent);
181 } else {
182 // See if the unit looks like a prefix + base unit
183 std::string prefix = unit.substr(0, 1);
184 std::string suffix = unit.substr(1);
185 if (prefixes.find(prefix) != prefixes.end() &&
186 knownUnits.find(suffix) != knownUnits.end()) {
187 Units u = knownUnits.at(suffix);
188 u.scale(prefixes.at(prefix));
189 *this *= u.pow(exponent);
190 } else {
191 throw CanteraError("Units::Units(string)",
192 "Unknown unit '{}' in unit string '{}'", unit, name);
193 }
194 }
195
196 start = stop+1;
197 if (stop == npos) {
198 break;
199 }
200 }
201
202 if (force_unity && (std::abs(m_factor - 1.) > SmallNumber)) {
203 throw CanteraError("Units::Units(string)",
204 "Detected non-unity conversion factor:\n"
205 "input '{}' is equivalent to '{}' where the conversion factor is '{}'",
206 name, str(), m_factor);
207 }
208}
209
210bool Units::convertible(const Units& other) const
211{
212 return (m_mass_dim == other.m_mass_dim &&
213 m_length_dim == other.m_length_dim &&
214 m_time_dim == other.m_time_dim &&
215 m_temperature_dim == other.m_temperature_dim &&
216 m_current_dim == other.m_current_dim &&
217 m_quantity_dim == other.m_quantity_dim);
218}
219
221{
222 m_factor *= other.m_factor;
223 m_mass_dim += other.m_mass_dim;
224 m_length_dim += other.m_length_dim;
225 m_time_dim += other.m_time_dim;
226 m_temperature_dim += other.m_temperature_dim;
227 m_current_dim += other.m_current_dim;
228 m_quantity_dim += other.m_quantity_dim;
230 m_energy_dim += other.m_energy_dim;
231 return *this;
232}
233
234Units Units::pow(double exponent) const
235{
236 return Units(std::pow(m_factor, exponent),
237 m_mass_dim * exponent,
238 m_length_dim * exponent,
239 m_time_dim * exponent,
240 m_temperature_dim * exponent,
241 m_current_dim * exponent,
242 m_quantity_dim * exponent);
243}
244
245std::string Units::str(bool skip_unity) const
246{
247 std::map<std::string, double> dims{
248 {"kg", m_mass_dim},
249 {"m", m_length_dim},
250 {"s", m_time_dim},
251 {"K", m_temperature_dim},
252 {"A", m_current_dim},
253 {"kmol", m_quantity_dim},
254 };
255
256 std::string num = "";
257 std::string den = "";
258 for (auto const& dim : dims) {
259 int rounded = (int)round(dim.second);
260 if (dim.second == 0.) {
261 // skip
262 } else if (dim.second == 1.) {
263 num.append(fmt::format(" * {}", dim.first));
264 } else if (dim.second == -1.) {
265 den.append(fmt::format(" / {}", dim.first));
266 } else if (dim.second == rounded && rounded > 0) {
267 num.append(fmt::format(" * {}^{}", dim.first, rounded));
268 } else if (dim.second == rounded) {
269 den.append(fmt::format(" / {}^{}", dim.first, -rounded));
270 } else if (dim.second > 0) {
271 num.append(fmt::format(" * {}^{}", dim.first, dim.second));
272 } else {
273 den.append(fmt::format(" / {}^{}", dim.first, -dim.second));
274 }
275 }
276
277 if (skip_unity && (std::abs(m_factor - 1.) < SmallNumber)) {
278 if (num.size()) {
279 return fmt::format("{}{}", num.substr(3), den);
280 }
281 // print '1' as the numerator is empty
282 return fmt::format("1{}", den);
283 }
284
285 std::string factor;
286 if (m_factor == round(m_factor)) {
287 // ensure that fmt::format does not round to integer
288 factor = fmt::format("{:.1f}", m_factor);
289 } else {
290 factor = fmt::format("{}", m_factor);
291 }
292
293 if (num.size()) {
294 // concatenate factor, numerator and denominator (skipping leading '*')
295 return fmt::format("{} {}{}", factor, num.substr(3), den);
296 }
297
298 return fmt::format("{}{}", factor, den);
299}
300
301bool Units::operator==(const Units& other) const
302{
303 return m_factor == other.m_factor
304 && m_mass_dim == other.m_mass_dim
305 && m_length_dim == other.m_length_dim
306 && m_time_dim == other.m_time_dim
307 && m_temperature_dim == other.m_temperature_dim
308 && m_current_dim == other.m_current_dim
309 && m_quantity_dim == other.m_quantity_dim
311 && m_energy_dim == other.m_energy_dim;
312}
313
314double Units::dimension(const std::string& primary) const
315{
316 if (primary == "mass") {
317 return m_mass_dim;
318 } else if (primary == "length") {
319 return m_length_dim;
320 } else if (primary == "time") {
321 return m_time_dim;
322 } else if (primary == "temperature") {
323 return m_temperature_dim;
324 } else if (primary == "current") {
325 return m_current_dim;
326 } else if (primary == "quantity") {
327 return m_quantity_dim;
328 } else {
329 throw CanteraError("Units::dimension",
330 "Unknown primary unit '{}'.", primary);
331 }
332}
333
335{
336 if (!stack.size()) {
337 return Units(0);
338 }
339 return stack[0].first;
340}
341
343{
344 if (!stack.size()) {
345 stack.emplace_back(standardUnits, 0.);
346 return;
347 }
348 if (stack[0].second != 0.) {
349 throw CanteraError("UnitStack::setStandardUnit",
350 "Standard unit is already defined.");
351 }
352 stack[0].first = standardUnits;
353}
354
356{
357 if (!stack.size()) {
358 return NAN;
359 }
360 return stack[0].second;
361}
362
363void UnitStack::join(double exponent)
364{
365 if (!stack.size()) {
366 throw CanteraError("UnitStack::join",
367 "Standard unit is not defined.");
368 }
369 stack[0].second += exponent;
370
371}
372
373void UnitStack::update(const Units& units, double exponent)
374{
375 bool found = false;
376 for (auto& item : stack) {
377 if (item.first == units) {
378 item.second += exponent;
379 found = true;
380 break;
381 }
382 }
383 if (!found) {
384 stack.emplace_back(units, exponent);
385 }
386}
387
389{
390 if (!stack.size()) {
391 return Units(0.);
392 }
393 Units out = Units(1.);
394 for (auto& item : stack) {
395 if (item.second == 1) {
396 out *= item.first;
397 } else {
398 out *= item.first.pow(item.second);
399 }
400 }
401 return out;
402}
403
404UnitSystem::UnitSystem(std::initializer_list<std::string> units)
405 : m_mass_factor(1.0)
406 , m_length_factor(1.0)
407 , m_time_factor(1.0)
408 , m_pressure_factor(1.0)
409 , m_energy_factor(1.0)
410 , m_activation_energy_factor(1.0)
411 , m_quantity_factor(1.0)
412 , m_explicit_activation_energy(false)
413{
414 setDefaults(units);
415}
416
417std::map<std::string, std::string> UnitSystem::defaults() const
418{
419 // Unit system defaults
420 std::map<std::string, std::string> units{
421 {"mass", "kg"},
422 {"length", "m"},
423 {"time", "s"},
424 {"quantity", "kmol"},
425 {"pressure", "Pa"},
426 {"energy", "J"},
427 {"temperature", "K"},
428 {"current", "A"},
429 {"activation-energy", "J / kmol"},
430 };
431
432 // Overwrite entries that have conversion factors
433 for (const auto& defaults : m_defaults) {
434 units[defaults.first] = defaults.second;
435 }
436
437 // Activation energy follows specified energy and quantity units
438 // unless given explicitly
439 if (!m_defaults.count("activation-energy")) {
440 units["activation-energy"] = fmt::format(
441 "{} / {}", units["energy"], units["quantity"]);
442 }
443
444 return units;
445}
446
447void UnitSystem::setDefaults(std::initializer_list<std::string> units)
448{
449 for (const auto& name : units) {
450 auto unit = Units(name);
451 if (unit.convertible(knownUnits.at("kg"))) {
452 m_mass_factor = unit.factor();
453 m_defaults["mass"] = name;
454 } else if (unit.convertible(knownUnits.at("m"))) {
455 m_length_factor = unit.factor();
456 m_defaults["length"] = name;
457 } else if (unit.convertible(knownUnits.at("s"))) {
458 m_time_factor = unit.factor();
459 m_defaults["time"] = name;
460 } else if (unit.convertible(knownUnits.at("kmol"))) {
461 m_quantity_factor = unit.factor();
462 m_defaults["quantity"] = name;
463 } else if (unit.convertible(knownUnits.at("Pa"))) {
464 m_pressure_factor = unit.factor();
465 m_defaults["pressure"] = name;
466 } else if (unit.convertible(knownUnits.at("J"))) {
467 m_energy_factor = unit.factor();
468 m_defaults["energy"] = name;
469 } else if (unit.convertible(knownUnits.at("K"))) {
470 // Do nothing -- no other scales are supported for temperature
471 if (unit.factor() != 1.) {
472 throw CanteraError("UnitSystem::setDefaults", "Temperature scales "
473 "with non-unity conversion factor from Kelvin are not supported.");
474 }
475 } else if (unit.convertible(knownUnits.at("A"))) {
476 // Do nothing -- no other scales are supported for current
477 if (unit.factor() != 1.) {
478 throw CanteraError("UnitSystem::setDefaults", "Current scales "
479 "with non-unity conversion factor from Ampere are not supported.");
480 }
481 } else {
482 throw CanteraError("UnitSystem::setDefaults",
483 "Unable to match unit '{}' to a basic dimension", name);
484 }
485 }
488 }
489}
490
491void UnitSystem::setDefaults(const std::map<std::string, std::string>& units)
492{
493 for (const auto& item : units) {
494 auto& name = item.first;
495 Units unit(item.second);
496 if (name == "mass" && unit.convertible(knownUnits.at("kg"))) {
497 m_mass_factor = unit.factor();
498 m_defaults["mass"] = item.second;
499 } else if (name == "length" && unit.convertible(knownUnits.at("m"))) {
500 m_length_factor = unit.factor();
501 m_defaults["length"] = item.second;
502 } else if (name == "time" && unit.convertible(knownUnits.at("s"))) {
503 m_time_factor = unit.factor();
504 m_defaults["time"] = item.second;
505 } else if (name == "temperature" && unit.convertible(knownUnits.at("K"))) {
506 // do nothing - no other temperature scales are supported
507 if (unit.factor() != 1.) {
508 throw CanteraError("UnitSystem::setDefaults", "Temperature scales "
509 "with non-unity conversion factor from Kelvin are not supported.");
510 }
511 } else if (name == "current" && unit.convertible(knownUnits.at("A"))) {
512 // do nothing - no other current scales are supported
513 if (unit.factor() != 1.) {
514 throw CanteraError("UnitSystem::setDefaults", "Current scales "
515 "with non-unity conversion factor from Ampere are not supported.");
516 }
517 } else if (name == "quantity" && unit.convertible(knownUnits.at("kmol"))) {
518 m_quantity_factor = unit.factor();
519 m_defaults["quantity"] = item.second;
520 } else if (name == "pressure" && unit.convertible(knownUnits.at("Pa"))) {
521 m_pressure_factor = unit.factor();
522 m_defaults["pressure"] = item.second;
523 } else if (name == "energy" && unit.convertible(knownUnits.at("J"))) {
524 m_energy_factor = unit.factor();
525 m_defaults["energy"] = item.second;
526 } else if (name == "activation-energy") {
527 // handled separately to allow override
528 } else {
529 throw CanteraError("UnitSystem::setDefaults",
530 "Unable to set default unit for '{}' to '{}' ({}).",
531 name, item.second, unit.str());
532 }
533 }
534 if (units.find("activation-energy") != units.end()) {
535 setDefaultActivationEnergy(units.at("activation-energy"));
536 } else if (!m_explicit_activation_energy) {
538 }
539}
540
541void UnitSystem::setDefaultActivationEnergy(const std::string& e_units)
542{
543 Units u(e_units);
544 m_defaults["activation-energy"] = e_units;
545 if (u.convertible(Units("J/kmol"))) {
547 } else if (u.convertible(knownUnits.at("K"))) {
549 } else if (u.convertible(knownUnits.at("eV"))) {
551 } else {
552 throw CanteraError("Units::setDefaultActivationEnergy",
553 "Unable to match unit '{}' to a unit of activation energy", e_units);
554 }
556}
557
558double UnitSystem::convert(double value, const std::string& src,
559 const std::string& dest) const
560{
561 return convert(value, Units(src), Units(dest));
562}
563
564double UnitSystem::convert(double value, const Units& src,
565 const Units& dest) const
566{
567 if (!src.convertible(dest)) {
568 throw CanteraError("UnitSystem::convert",
569 "Incompatible units:\n Units({}) and\n Units({})",
570 src.str(), dest.str());
571 }
572 return value * src.factor() / dest.factor();
573}
574
575double UnitSystem::convertTo(double value, const std::string& dest) const
576{
577 return convertTo(value, Units(dest));
578}
579
580double UnitSystem::convertTo(double value, const Units& dest) const
581{
582 return value / dest.factor()
583 * pow(m_mass_factor, dest.m_mass_dim - dest.m_pressure_dim - dest.m_energy_dim)
584 * pow(m_length_factor, dest.m_length_dim + dest.m_pressure_dim - 2*dest.m_energy_dim)
585 * pow(m_time_factor, dest.m_time_dim + 2*dest.m_pressure_dim + 2*dest.m_energy_dim)
586 * pow(m_quantity_factor, dest.m_quantity_dim)
588 * pow(m_energy_factor, dest.m_energy_dim);
589}
590
591double UnitSystem::convertFrom(double value, const std::string& dest) const
592{
593 return convertFrom(value, Units(dest));
594}
595
596double UnitSystem::convertFrom(double value, const Units& src) const
597{
598 return value * src.factor()
599 * pow(m_mass_factor, -src.m_mass_dim + src.m_pressure_dim + src.m_energy_dim)
600 * pow(m_length_factor, -src.m_length_dim - src.m_pressure_dim + 2*src.m_energy_dim)
601 * pow(m_time_factor, -src.m_time_dim - 2*src.m_pressure_dim - 2*src.m_energy_dim)
602 * pow(m_quantity_factor, -src.m_quantity_dim)
604 * pow(m_energy_factor, -src.m_energy_dim);
605}
606
607static std::pair<double, std::string> split_unit(const AnyValue& v) {
608 if (v.is<std::string>()) {
609 // Should be a value and units, separated by a space, for example '2e4 J/kmol'
610 std::string val_units = v.asString();
611 size_t space = val_units.find(" ");
612 if (space == npos) {
613 throw CanteraError("split_unit (UnitSystem)",
614 "Couldn't parse '{}' as a space-separated value/unit pair\n",
615 val_units);
616 }
617 return {fpValueCheck(val_units.substr(0, space)),
618 val_units.substr(space+1)};
619 } else {
620 // Just a value
621 return {v.asDouble(), ""};
622 }
623}
624
625double UnitSystem::convert(const AnyValue& v, const std::string& dest) const
626{
627 return convert(v, Units(dest));
628}
629
630double UnitSystem::convert(const AnyValue& v, const Units& dest) const
631{
632 auto val_units = split_unit(v);
633 if (val_units.second.empty()) {
634 // Just a value, so convert using default units
635 return convertTo(val_units.first, dest);
636 } else {
637 // Both source and destination units are explicit
638 return convert(val_units.first, Units(val_units.second), dest);
639 }
640}
641
642vector_fp UnitSystem::convert(const std::vector<AnyValue>& vals,
643 const std::string& dest) const
644{
645 return convert(vals, Units(dest));
646}
647
648vector_fp UnitSystem::convert(const std::vector<AnyValue>& vals,
649 const Units& dest) const
650{
651 vector_fp out;
652 for (const auto& val : vals) {
653 out.emplace_back(convert(val, dest));
654 }
655 return out;
656}
657
658double UnitSystem::convertActivationEnergy(double value, const std::string& src,
659 const std::string& dest) const
660{
661 // Convert to J/kmol
662 Units usrc(src);
663 if (usrc.convertible(Units("J/kmol"))) {
664 value *= usrc.factor();
665 } else if (usrc.convertible(Units("K"))) {
666 value *= GasConstant * usrc.factor();
667 } else if (usrc.convertible(Units("eV"))) {
668 value *= Avogadro * usrc.factor();
669 } else {
670 throw CanteraError("UnitSystem::convertActivationEnergy",
671 "Don't understand units '{}' as an activation energy", src);
672 }
673
674 // Convert from J/kmol
675 Units udest(dest);
676 if (udest.convertible(Units("J/kmol"))) {
677 value /= udest.factor();
678 } else if (udest.convertible(Units("K"))) {
679 value /= GasConstant * udest.factor();
680 } else if (udest.convertible(Units("eV"))) {
681 value /= Avogadro * udest.factor();
682 } else {
683 throw CanteraError("UnitSystem::convertActivationEnergy",
684 "Don't understand units '{}' as an activation energy", dest);
685 }
686
687 return value;
688}
689
691 const std::string& dest) const
692{
693 return convertActivationEnergyTo(value, Units(dest));
694}
695
696double UnitSystem::convertActivationEnergyTo(double value,
697 const Units& dest) const
698{
699 if (dest.convertible(Units("J/kmol"))) {
700 return value * m_activation_energy_factor / dest.factor();
701 } else if (dest.convertible(knownUnits.at("K"))) {
703 } else if (dest.convertible(knownUnits.at("eV"))) {
704 return value * m_activation_energy_factor / (Avogadro * dest.factor());
705 } else {
706 throw CanteraError("UnitSystem::convertActivationEnergyTo",
707 "'{}' is not a unit of activation energy", dest.str());
708 }
709}
710
712 const std::string& src) const
713{
714 Units usrc(src);
715 if (usrc.convertible(Units("J/kmol"))) {
716 return value * usrc.factor() / m_activation_energy_factor;
717 } else if (usrc.convertible(knownUnits.at("K"))) {
719 } else if (usrc.convertible(knownUnits.at("eV"))) {
720 return value * Avogadro * usrc.factor() / m_activation_energy_factor;
721 } else {
722 throw CanteraError("UnitSystem::convertActivationEnergyFrom",
723 "'{}' is not a unit of activation energy", src);
724 }
725}
726
728 const std::string& dest) const
729{
730 auto val_units = split_unit(v);
731 if (val_units.second.empty()) {
732 // Just a value, so convert using default units
733 return convertActivationEnergyTo(val_units.first, dest);
734 } else {
735 // Both source and destination units are explicit
736 return convertActivationEnergy(val_units.first, val_units.second, dest);
737 }
738}
739
741{
742 AnyMap delta;
743 // Create a local alias because the template specialization can't be deduced
744 // automatically
745 const auto& get = getValue<std::string, std::string>;
746 if (m_mass_factor != other.m_mass_factor) {
747 delta["mass"] = get(m_defaults, "mass", "kg");
748 }
749 if (m_length_factor != other.m_length_factor) {
750 delta["length"] = get(m_defaults, "length", "m");
751 }
752 if (m_time_factor != other.m_time_factor) {
753 delta["time"] = get(m_defaults, "time", "s");
754 }
756 delta["pressure"] = get(m_defaults, "pressure", "Pa");
757 }
758 if (m_energy_factor != other.m_energy_factor) {
759 delta["energy"] = get(m_defaults, "energy", "J");
760 }
762 delta["quantity"] = get(m_defaults, "quantity", "kmol");
763 }
767 {
768 delta["activation-energy"] = get(m_defaults, "activation-energy", "J/kmol");
769 }
770 return delta;
771}
772
773}
Header for unit conversion utilities, which are used to translate user input from input files (See In...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:84
const std::string & asString() const
Return the held value, if it is a string.
Definition: AnyMap.cpp:716
double & asDouble()
Return the held value as a double, if it is a double or a long int.
Definition: AnyMap.cpp:801
bool is() const
Returns true if the held value is of the specified type.
Definition: AnyMap.inl.h:58
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Unit conversion utility.
Definition: Units.h:161
double m_activation_energy_factor
Factor to convert activation energy from this unit system to J/kmol.
Definition: Units.h:272
bool m_explicit_activation_energy
True if activation energy units are set explicitly, rather than as a combination of energy and quanti...
Definition: Units.h:279
double m_time_factor
Factor to convert time from this unit system to seconds.
Definition: Units.h:263
double m_pressure_factor
Factor to convert pressure from this unit system to Pa.
Definition: Units.h:266
UnitSystem()
Default constructor for unit system (needed as VS2019 does not recognize an optional argument with a ...
Definition: Units.h:168
double m_energy_factor
Factor to convert energy from this unit system to J.
Definition: Units.h:269
double m_length_factor
Factor to convert length from this unit system to meters.
Definition: Units.h:260
double convert(double value, const std::string &src, const std::string &dest) const
Convert value from the units of src to the units of dest.
Definition: Units.cpp:558
void setDefaultActivationEnergy(const std::string &e_units)
Set the default units to convert from when using the convertActivationEnergy function.
Definition: Units.cpp:541
double convertFrom(double value, const std::string &src) const
Convert value from the specified src units to units appropriate for this unit system (defined by setD...
Definition: Units.cpp:591
double convertActivationEnergy(double value, const std::string &src, const std::string &dest) const
Convert value from the units of src to the units of dest, allowing for the different dimensions that ...
Definition: Units.cpp:658
std::map< std::string, std::string > defaults() const
Return default units used by the unit system.
Definition: Units.cpp:417
double m_mass_factor
Factor to convert mass from this unit system to kg.
Definition: Units.h:257
double convertTo(double value, const std::string &dest) const
Convert value to the specified dest units from the appropriate units for this unit system (defined by...
Definition: Units.cpp:575
double m_quantity_factor
Factor to convert quantity from this unit system to kmol.
Definition: Units.h:275
double convertActivationEnergyTo(double value, const std::string &dest) const
Convert value to the units specified by dest from the default activation energy units.
Definition: Units.cpp:690
void setDefaults(std::initializer_list< std::string > units)
Set the default units to convert from when explicit units are not provided.
Definition: Units.cpp:447
double convertActivationEnergyFrom(double value, const std::string &src) const
Convert value from the units specified by src to the default activation energy units.
Definition: Units.cpp:711
AnyMap getDelta(const UnitSystem &other) const
Get the changes to the defaults from other to this UnitSystem.
Definition: Units.cpp:740
std::map< std::string, std::string > m_defaults
Map of dimensions (mass, length, etc.) to names of specified default units.
Definition: Units.h:283
A representation of the units associated with a dimensional quantity.
Definition: Units.h:30
double m_energy_dim
pseudo-dimension to track explicit energy units
Definition: Units.h:80
std::string str(bool skip_unity=true) const
Provide a string representation of these Units.
Definition: Units.cpp:245
double m_pressure_dim
pseudo-dimension to track explicit pressure units
Definition: Units.h:79
void scale(double k)
Scale the unit by the factor k
Definition: Units.h:70
double m_factor
conversion factor to Cantera base units
Definition: Units.h:72
Units pow(double exponent) const
Raise these Units to a power, changing both the conversion factor and the dimensions of these Units.
Definition: Units.cpp:234
Units & operator*=(const Units &other)
Multiply two Units objects, combining their conversion factors and dimensions.
Definition: Units.cpp:220
bool convertible(const Units &other) const
Returns true if the specified Units are dimensionally consistent.
Definition: Units.cpp:210
double dimension(const std::string &primary) const
Return dimension of primary unit component ("mass", "length", "time", "temperature",...
Definition: Units.cpp:314
double factor() const
Return the factor for converting from this unit to Cantera's base units.
Definition: Units.h:48
Units(double factor=1.0, double mass=0, double length=0, double time=0, double temperature=0, double current=0, double quantity=0)
Create a Units object with the specified dimensions.
Definition: Units.cpp:109
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
This file contains definitions for utility functions and text for modules, inputfiles,...
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
const double Avogadro
Avogadro's Number [number/kmol].
Definition: ct_defs.h:66
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:81
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:153
std::string trimCopy(const std::string &input)
Trim.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:184
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:113
const double ElectronCharge
Elementary charge [C].
Definition: ct_defs.h:75
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
Contains declarations for string manipulation functions within Cantera.
double standardExponent() const
Effective exponent of standard unit.
Definition: Units.cpp:355
void update(const Units &units, double exponent)
Update exponent of item with matching units; if it does not exist, add unit-exponent pair at end of s...
Definition: Units.cpp:373
Units standardUnits() const
Get standard unit used by UnitStack.
Definition: Units.cpp:334
Units product() const
Calculate product of units-exponent stack.
Definition: Units.cpp:388
void join(double exponent)
Join (update) exponent of standard units, where the updated exponent is the sum of the pre-existing e...
Definition: Units.cpp:363
std::vector< std::pair< Units, double > > stack
Stack uses vector of pairs.
Definition: Units.h:132
void setStandardUnits(Units &standardUnits)
Set standard units.
Definition: Units.cpp:342
Various templated functions that carry out common vector operations (see Templated Utility Functions)...