11 #include "libmesh/int_range.h" 18 {
"Y", 1e24}, {
"Z", 1e21}, {
"E", 1e18}, {
"P", 1e15}, {
"T", 1e12}, {
"G", 1e9}, {
"M", 1e6},
19 {
"k", 1e3}, {
"h", 1e2}, {
"da", 1e1}, {
"d", 1e-1}, {
"c", 1e-2}, {
"m", 1e-3}, {
"mu", 1e-6},
20 {
"n", 1e-9}, {
"p", 1e-12}, {
"f", 1e-15}, {
"a", 1e-18}, {
"z", 1e-21}, {
"y", 1e-24}};
197 {60 * 60 * 24 * 365.25,
218 for (std::size_t i = 0; i <
_base.size(); ++i)
229 mooseError(
"Cannot convert between non-conforming units '", *
this,
"' and '", from_unit,
"'.");
241 std::stack<std::vector<std::pair<MooseUnits::BaseUnit, int>>> stack;
242 std::stack<char> op_stack;
243 std::stack<MooseUnits>
out;
245 auto it = unit_string.begin();
246 const auto end = unit_string.end();
258 op_stack.push(*(it++));
260 else if (*it ==
'*' || *it ==
'/')
263 while (!op_stack.empty() && (op_stack.top() ==
'*' || op_stack.top() ==
'/'))
265 auto top = op_stack.top();
270 unit_string, it,
"Applying ", top,
" but don't have enough items on the stack.");
271 auto rhs =
out.top();
274 out.top() =
out.top() * rhs;
276 out.top() =
out.top() / rhs;
279 op_stack.push(*(it++));
286 if (op_stack.empty())
287 parseError(unit_string, it,
"Mismatching right parenthesis.");
289 auto top = op_stack.top();
295 if (top ==
'*' || top ==
'/')
299 unit_string, it,
"Applying ", top,
" but don't have enough items on the stack.");
300 auto rhs =
out.top();
303 out.top() =
out.top() * rhs;
305 out.top() =
out.top() / rhs;
316 if (it != end && *it ==
'-')
324 while (*it >=
'0' && *it <=
'9')
327 num += *(it++) -
'0';
335 parseError(unit_string, it,
"Expected a number but found end of string.");
337 parseError(unit_string, it,
"Expected a number but got '", (*it),
"'.");
342 parseError(unit_string, it,
"Applying an exponent, but found no units in front of it.");
348 while (it != end && ((*it >=
'a' && *it <=
'z') || (*it >=
'A' && *it <=
'Z') ||
349 (*it >=
'0' && *it <=
'9') || *it ==
'.' || *it ==
'-'))
354 std::stringstream ss(unit);
355 if ((ss >> si_factor).fail() || !std::isfinite(si_factor))
368 auto len = unit.length();
372 parseError(unit_string, it,
"Expected unit but found end of string.");
374 parseError(unit_string, it,
"Expected unit but found '", *it,
"'.");
381 const auto slen = s.length();
382 if (slen <= len && unit.substr(len - slen) == s)
388 parseError(unit_string, it,
"Unknown unit '", unit,
"'.");
392 const auto slen = s.length();
395 const auto prefix = unit.substr(0, len - slen);
398 si_factor = jt->second;
400 parseError(unit_string, it,
"Unknown SI prefix '", prefix,
"' on unit '", unit,
"'.");
410 while (!op_stack.empty())
412 auto top = op_stack.top();
415 if (top ==
'(' || top ==
')')
416 parseError(unit_string, it,
"Unit string contains unmatched parenthesis.");
418 if (top ==
'*' || top ==
'/')
425 " but don't have enough items on the stack.",
427 auto rhs =
out.top();
430 out.top() =
out.top() * rhs;
432 out.top() =
out.top() / rhs;
438 mooseError(
"Internal parse error. Remaining output stack size should be 1, but is ",
470 for (
auto & b : u.
_base)
492 MooseUnits::operator
Real()
const 495 mooseError(
"Unit '", *
this,
"' is not a pure number.");
502 std::map<BaseUnit, int> base_map;
503 for (
auto & b :
_base)
505 auto j = base_map.find(b.first);
506 if (j == base_map.end())
509 j->second += b.second;
514 for (
auto & u : base_map)
523 if (
_base.size() != 1)
527 if (
_base[0].second != 1)
531 return (
_base[0].first == base);
542 for (
auto & b : r.
_base)
564 static int i = std::ios_base::xalloc();
572 static const std::vector<std::string> base_unit = {
"m",
"kg",
"s",
"A",
"K",
"at",
"cd"};
577 if (!u.
_base.empty())
583 os << (i ? (latex ?
"\\cdot " :
"*") :
"");
585 const auto & unit = base_unit[
int(u.
_base[i].first)];
587 os <<
"\\text{" << unit <<
"}";
591 if (u.
_base[i].second != 1)
594 os <<
"^{" << u.
_base[i].second <<
'}';
596 os <<
'^' << u.
_base[i].second;
MooseUnits operator*(const Real f) const
Unit prefactor scaling.
static const std::vector< std::pair< std::string, MooseUnits > > _unit_table
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
bool operator==(const MooseUnits &rhs) const
void parseError(const std::string &unit_string, std::string::const_iterator it, Args... args)
helper function to generate a pretty mooseError
std::basic_ostream< charT, traits > * os
std::vector< std::pair< BaseUnit, int > > _base
base SI units and their exponents
static const std::map< std::string, Real > _si_prefix
data tables with SI prefixes and known units
bool isBase(const MooseUnits::BaseUnit) const
check if the unit has a pure base
static int geti()
iosteam manipulator helper to toggle latex / text output
MooseUnits operator/(const MooseUnits &rhs) const
std::ostream & operator<<(std::ostream &os, const MooseUnits &u)
MooseUnits(const std::string &unit_string)
Physical unit management class with runtime unit string parsing, unit checking, unit conversion...
bool conformsTo(const MooseUnits &) const
checks if the units are dimensionally conforming (i.e. the describe the same physical quanitity) ...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real _factor
conversion factor w.r.t. the base SI units
Real convert(Real from_value, const MooseUnits &from_unit) const
Converts from_value in units of from_units to value this units.
static std::ostream & text(std::ostream &os)
Real _shift
additive shift (for Celsius and Fahrenheit)
std::vector< ElemQuality > valid(const ElemType t)
MooseUnits pow(const MooseUnits &, int)
void parse(const std::string &unit_string)
parse a unit string into a MooseUnits object
void ErrorVector unsigned int
auto index_range(const T &sizable)
static std::ostream & latex(std::ostream &os)
iostream manipulators
void simplify()
simplify into the canonical form that permits comparisons