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
6#include "cantera/base/Units.h"
7#include "cantera/base/ctexceptions.h"
8#include "cantera/base/global.h"
9#include "cantera/base/stringUtils.h"
10#include "cantera/base/AnyMap.h"
11#include "cantera/base/utilities.h"
12#include <regex>
13
14 namespace {
15 using namespace Cantera;
16
17 const 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
83 const 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
106 namespace Cantera
107{
108
109 Units::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
133 Units::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) {
153 m_factor = fpValueCheck(factor);
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
210 bool 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
220 Units& Units::operator*=(const Units& other)
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;
229 m_pressure_dim += other.m_pressure_dim;
230 m_energy_dim += other.m_energy_dim;
231 return *this;
232}
233
234 Units 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
301 bool 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
310 && m_pressure_dim == other.m_pressure_dim
311 && m_energy_dim == other.m_energy_dim;
312}
313
314 double 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
334 Units UnitStack::standardUnits() const
335{
336 if (!stack.size()) {
337 return Units(0);
338 }
339 return stack[0].first;
340}
341
342 void UnitStack::setStandardUnits(Units& standardUnits)
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
355 double UnitStack::standardExponent() const
356{
357 if (!stack.size()) {
358 return NAN;
359 }
360 return stack[0].second;
361}
362
363 void 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
373 void 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
388 Units UnitStack::product() const
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
404 UnitSystem::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
447 void 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 }
486 if (!m_explicit_activation_energy) {
487 m_activation_energy_factor = m_energy_factor / m_quantity_factor;
488 }
489}
490
491 void 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) {
537 m_activation_energy_factor = m_energy_factor / m_quantity_factor;
538 }
539}
540
541 void 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"))) {
546 m_activation_energy_factor = u.factor();
547 } else if (u.convertible(knownUnits.at("K"))) {
548 m_activation_energy_factor = GasConstant;
549 } else if (u.convertible(knownUnits.at("eV"))) {
550 m_activation_energy_factor = u.factor() * Avogadro;
551 } else {
552 throw CanteraError("Units::setDefaultActivationEnergy",
553 "Unable to match unit '{}' to a unit of activation energy", e_units);
554 }
555 m_explicit_activation_energy = true;
556}
557
558 double 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
564 double 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
575 double UnitSystem::convertTo(double value, const std::string& dest) const
576{
577 return convertTo(value, Units(dest));
578}
579
580 double 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)
587 * pow(m_pressure_factor, dest.m_pressure_dim)
588 * pow(m_energy_factor, dest.m_energy_dim);
589}
590
591 double UnitSystem::convertFrom(double value, const std::string& dest) const
592{
593 return convertFrom(value, Units(dest));
594}
595
596 double 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)
603 * pow(m_pressure_factor, -src.m_pressure_dim)
604 * pow(m_energy_factor, -src.m_energy_dim);
605}
606
607 static 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
625 double UnitSystem::convert(const AnyValue& v, const std::string& dest) const
626{
627 return convert(v, Units(dest));
628}
629
630 double 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
642 vector_fp UnitSystem::convert(const std::vector<AnyValue>& vals,
643 const std::string& dest) const
644{
645 return convert(vals, Units(dest));
646}
647
648 vector_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
658 double 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
690 double UnitSystem::convertActivationEnergyTo(double value,
691 const std::string& dest) const
692{
693 return convertActivationEnergyTo(value, Units(dest));
694}
695
696 double 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"))) {
702 return value * m_activation_energy_factor / GasConstant;
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
711 double UnitSystem::convertActivationEnergyFrom(double value,
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"))) {
718 return value * GasConstant / m_activation_energy_factor;
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
727 double UnitSystem::convertActivationEnergy(const AnyValue& v,
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
740 AnyMap UnitSystem::getDelta(const UnitSystem& other) const
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 }
755 if (m_pressure_factor != other.m_pressure_factor) {
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 }
761 if (m_quantity_factor != other.m_quantity_factor) {
762 delta["quantity"] = get(m_defaults, "quantity", "kmol");
763 }
764 if (m_explicit_activation_energy
765 || (other.m_explicit_activation_energy
766 && m_activation_energy_factor != m_energy_factor / m_quantity_factor))
767 {
768 delta["activation-energy"] = get(m_defaults, "activation-energy", "J/kmol");
769 }
770 return delta;
771}
772
773}
AnyMap.h
Units.h
Header for unit conversion utilities, which are used to translate user input from input files (See In...
Cantera::AnyMap
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
Cantera::AnyValue
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:84
Cantera::AnyValue::asString
const std::string & asString() const
Return the held value, if it is a string.
Definition: AnyMap.cpp:716
Cantera::AnyValue::asDouble
double & asDouble()
Return the held value as a double, if it is a double or a long int.
Definition: AnyMap.cpp:801
Cantera::AnyValue::is
bool is() const
Returns true if the held value is of the specified type.
Definition: AnyMap.inl.h:58
Cantera::CanteraError
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Cantera::UnitSystem
Unit conversion utility.
Definition: Units.h:161
Cantera::UnitSystem::m_activation_energy_factor
double m_activation_energy_factor
Factor to convert activation energy from this unit system to J/kmol.
Definition: Units.h:272
Cantera::UnitSystem::m_explicit_activation_energy
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
Cantera::UnitSystem::m_time_factor
double m_time_factor
Factor to convert time from this unit system to seconds.
Definition: Units.h:263
Cantera::UnitSystem::m_pressure_factor
double m_pressure_factor
Factor to convert pressure from this unit system to Pa.
Definition: Units.h:266
Cantera::UnitSystem::UnitSystem
UnitSystem()
Default constructor for unit system (needed as VS2019 does not recognize an optional argument with a ...
Definition: Units.h:168
Cantera::UnitSystem::m_energy_factor
double m_energy_factor
Factor to convert energy from this unit system to J.
Definition: Units.h:269
Cantera::UnitSystem::m_length_factor
double m_length_factor
Factor to convert length from this unit system to meters.
Definition: Units.h:260
Cantera::UnitSystem::convert
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
Cantera::UnitSystem::setDefaultActivationEnergy
void setDefaultActivationEnergy(const std::string &e_units)
Set the default units to convert from when using the convertActivationEnergy function.
Definition: Units.cpp:541
Cantera::UnitSystem::convertFrom
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
Cantera::UnitSystem::convertActivationEnergy
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
Cantera::UnitSystem::defaults
std::map< std::string, std::string > defaults() const
Return default units used by the unit system.
Definition: Units.cpp:417
Cantera::UnitSystem::m_mass_factor
double m_mass_factor
Factor to convert mass from this unit system to kg.
Definition: Units.h:257
Cantera::UnitSystem::convertTo
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
Cantera::UnitSystem::m_quantity_factor
double m_quantity_factor
Factor to convert quantity from this unit system to kmol.
Definition: Units.h:275
Cantera::UnitSystem::convertActivationEnergyTo
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
Cantera::UnitSystem::setDefaults
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
Cantera::UnitSystem::convertActivationEnergyFrom
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
Cantera::UnitSystem::getDelta
AnyMap getDelta(const UnitSystem &other) const
Get the changes to the defaults from other to this UnitSystem.
Definition: Units.cpp:740
Cantera::UnitSystem::m_defaults
std::map< std::string, std::string > m_defaults
Map of dimensions (mass, length, etc.) to names of specified default units.
Definition: Units.h:283
Cantera::Units
A representation of the units associated with a dimensional quantity.
Definition: Units.h:30
Cantera::Units::m_energy_dim
double m_energy_dim
pseudo-dimension to track explicit energy units
Definition: Units.h:80
Cantera::Units::str
std::string str(bool skip_unity=true) const
Provide a string representation of these Units.
Definition: Units.cpp:245
Cantera::Units::m_pressure_dim
double m_pressure_dim
pseudo-dimension to track explicit pressure units
Definition: Units.h:79
Cantera::Units::scale
void scale(double k)
Scale the unit by the factor k
Definition: Units.h:70
Cantera::Units::m_factor
double m_factor
conversion factor to Cantera base units
Definition: Units.h:72
Cantera::Units::pow
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
Cantera::Units::operator*=
Units & operator*=(const Units &other)
Multiply two Units objects, combining their conversion factors and dimensions.
Definition: Units.cpp:220
Cantera::Units::convertible
bool convertible(const Units &other) const
Returns true if the specified Units are dimensionally consistent.
Definition: Units.cpp:210
Cantera::Units::dimension
double dimension(const std::string &primary) const
Return dimension of primary unit component ("mass", "length", "time", "temperature",...
Definition: Units.cpp:314
Cantera::Units::factor
double factor() const
Return the factor for converting from this unit to Cantera's base units.
Definition: Units.h:48
Cantera::Units::Units
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
ctexceptions.h
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
global.h
This file contains definitions for utility functions and text for modules, inputfiles,...
Cantera
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:557
Cantera::npos
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
Cantera::Avogadro
const double Avogadro
Avogadro's Number [number/kmol].
Definition: ct_defs.h:66
Cantera::OneAtm
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:81
Cantera::SmallNumber
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:153
Cantera::trimCopy
std::string trimCopy(const std::string &input)
Trim.
Definition: stringUtils.cpp:258
Cantera::vector_fp
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
Cantera::GasConstant
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:113
Cantera::ElectronCharge
const double ElectronCharge
Elementary charge [C].
Definition: ct_defs.h:75
Cantera::fpValueCheck
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
Definition: stringUtils.cpp:137
stringUtils.h
Contains declarations for string manipulation functions within Cantera.
Cantera::UnitStack::standardExponent
double standardExponent() const
Effective exponent of standard unit.
Definition: Units.cpp:355
Cantera::UnitStack::update
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
Cantera::UnitStack::standardUnits
Units standardUnits() const
Get standard unit used by UnitStack.
Definition: Units.cpp:334
Cantera::UnitStack::product
Units product() const
Calculate product of units-exponent stack.
Definition: Units.cpp:388
Cantera::UnitStack::join
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
Cantera::UnitStack::stack
std::vector< std::pair< Units, double > > stack
Stack uses vector of pairs.
Definition: Units.h:132
Cantera::UnitStack::setStandardUnits
void setStandardUnits(Units &standardUnits)
Set standard units.
Definition: Units.cpp:342
utilities.h
Various templated functions that carry out common vector operations (see Templated Utility Functions)...