https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Types | Friends | List of all members
MooseUnits Class Reference

Physical unit management class with runtime unit string parsing, unit checking, unit conversion, and output. More...

#include <Units.h>

Public Member Functions

 MooseUnits (const std::string &unit_string)
 
 MooseUnits (Real f)
 
 MooseUnits (Real f, Real s, std::vector< std::pair< MooseUnits::BaseUnit, int > > b)
 
bool conformsTo (const MooseUnits &) const
 checks if the units are dimensionally conforming (i.e. the describe the same physical quanitity)
 
Real convert (Real from_value, const MooseUnits &from_unit) const
 Converts from_value in units of from_units to value this units.
 
void parse (const std::string &unit_string)
 parse a unit string into a MooseUnits object
 
void simplify ()
 simplify into the canonical form that permits comparisons
 
MooseUnits operator* (const Real f) const
 Unit prefactor scaling.
 
bool operator== (const MooseUnits &rhs) const
 
bool operator== (const Real rhs) const
 
 operator Real () const
 cast of units representing pure numbers
 
bool isLength () const
 query the nature of the unit
 
bool isTime () const
 
bool isMass () const
 
bool isCurrent () const
 
bool isTemperature () const
 
MooseUnits operator* (const MooseUnits &rhs) const
 Unit combination operators for unit pairs zero out the shift.
 
MooseUnits operator/ (const MooseUnits &rhs) const
 

Static Public Member Functions

static std::ostream & latex (std::ostream &os)
 iostream manipulators
 
static std::ostream & text (std::ostream &os)
 

Static Public Attributes

static const std::map< std::string, Real > _si_prefix
 data tables with SI prefixes and known units
 
static const std::vector< std::pair< std::string, MooseUnits > > _unit_table
 

Protected Member Functions

template<typename... Args>
void parseError (const std::string &unit_string, std::string::const_iterator it, Args... args)
 helper function to generate a pretty mooseError
 
bool isBase (const MooseUnits::BaseUnit) const
 check if the unit has a pure base
 

Static Protected Member Functions

static int geti ()
 iosteam manipulator helper to toggle latex / text output
 

Protected Attributes

Real _factor
 conversion factor w.r.t. the base SI units
 
Real _shift
 additive shift (for Celsius and Fahrenheit)
 
std::vector< std::pair< BaseUnit, int > > _base
 base SI units and their exponents
 

Private Types

enum class  BaseUnit {
  METER , KILOGRAM , SECOND , AMPERE ,
  KELVIN , COUNT , CANDELA
}
 

Friends

std::ostream & operator<< (std::ostream &os, const MooseUnits &dt)
 
MooseUnits std::pow (const MooseUnits &, int)
 

Detailed Description

Physical unit management class with runtime unit string parsing, unit checking, unit conversion, and output.

Definition at line 32 of file Units.h.

Member Enumeration Documentation

◆ BaseUnit

enum class MooseUnits::BaseUnit
strongprivate
Enumerator
METER 
KILOGRAM 
SECOND 
AMPERE 
KELVIN 
COUNT 
CANDELA 

Definition at line 34 of file Units.h.

Constructor & Destructor Documentation

◆ MooseUnits() [1/3]

MooseUnits::MooseUnits ( const std::string &  unit_string)

Definition at line 207 of file Units.C.

207 : _factor(1.0), _shift(0.0), _base()
208{
209 // parse the passed in unit string
210 parse(unit_string);
211}
std::vector< std::pair< BaseUnit, int > > _base
base SI units and their exponents
Definition Units.h:118
Real _factor
conversion factor w.r.t. the base SI units
Definition Units.h:109
void parse(const std::string &unit_string)
parse a unit string into a MooseUnits object
Definition Units.C:234
Real _shift
additive shift (for Celsius and Fahrenheit)
Definition Units.h:112

◆ MooseUnits() [2/3]

MooseUnits::MooseUnits ( Real  f)
inline

Definition at line 47 of file Units.h.

47: _factor(f), _shift(), _base() {}

◆ MooseUnits() [3/3]

MooseUnits::MooseUnits ( Real  f,
Real  s,
std::vector< std::pair< MooseUnits::BaseUnit, int > >  b 
)
inline

Definition at line 48 of file Units.h.

49 : _factor(f), _shift(s), _base(b)
50 {
51 }

Member Function Documentation

◆ conformsTo()

bool MooseUnits::conformsTo ( const MooseUnits u) const

checks if the units are dimensionally conforming (i.e. the describe the same physical quanitity)

Definition at line 214 of file Units.C.

215{
216 if (_base.size() != u._base.size())
217 return false;
218 for (std::size_t i = 0; i < _base.size(); ++i)
219 if (_base[i] != u._base[i])
220 return false;
221
222 return true;
223}

Referenced by convert(), and operator==().

◆ convert()

Real MooseUnits::convert ( Real  from_value,
const MooseUnits from_unit 
) const

Converts from_value in units of from_units to value this units.

Definition at line 226 of file Units.C.

227{
228 if (!conformsTo(from_unit))
229 mooseError("Cannot convert between non-conforming units '", *this, "' and '", from_unit, "'.");
230 return ((from_value + from_unit._shift) * from_unit._factor) / _factor - _shift;
231}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
bool conformsTo(const MooseUnits &) const
checks if the units are dimensionally conforming (i.e. the describe the same physical quanitity)
Definition Units.C:214

◆ geti()

int MooseUnits::geti ( )
staticprotected

iosteam manipulator helper to toggle latex / text output

Definition at line 562 of file Units.C.

563{
564 static int i = std::ios_base::xalloc();
565 return i;
566}

Referenced by latex(), and text().

◆ isBase()

bool MooseUnits::isBase ( const MooseUnits::BaseUnit  base) const
protected

check if the unit has a pure base

Definition at line 520 of file Units.C.

521{
522 // must have only one base unit
523 if (_base.size() != 1)
524 return false;
525
526 // its exponent must be one
527 if (_base[0].second != 1)
528 return false;
529
530 // and it has to be the right base unit
531 return (_base[0].first == base);
532}

Referenced by isCurrent(), isLength(), isMass(), isTemperature(), and isTime().

◆ isCurrent()

bool MooseUnits::isCurrent ( ) const
inline

Definition at line 74 of file Units.h.

74{ return isBase(BaseUnit::AMPERE); }
bool isBase(const MooseUnits::BaseUnit) const
check if the unit has a pure base
Definition Units.C:520

◆ isLength()

bool MooseUnits::isLength ( ) const
inline

query the nature of the unit

Definition at line 71 of file Units.h.

71{ return isBase(BaseUnit::METER); }

◆ isMass()

bool MooseUnits::isMass ( ) const
inline

Definition at line 73 of file Units.h.

73{ return isBase(BaseUnit::KILOGRAM); }

◆ isTemperature()

bool MooseUnits::isTemperature ( ) const
inline

Definition at line 75 of file Units.h.

75{ return isBase(BaseUnit::KELVIN); }

◆ isTime()

bool MooseUnits::isTime ( ) const
inline

Definition at line 72 of file Units.h.

72{ return isBase(BaseUnit::SECOND); }

◆ latex()

std::ostream & MooseUnits::latex ( std::ostream &  os)
static

iostream manipulators

Definition at line 549 of file Units.C.

550{
551 os.iword(geti()) = 1;
552 return os;
553}
static int geti()
iosteam manipulator helper to toggle latex / text output
Definition Units.C:562

◆ operator Real()

MooseUnits::operator Real ( ) const
explicit

cast of units representing pure numbers

Definition at line 492 of file Units.C.

493{
494 if (!_base.empty())
495 mooseError("Unit '", *this, "' is not a pure number.");
496 return _factor;
497}

◆ operator*() [1/2]

MooseUnits MooseUnits::operator* ( const MooseUnits rhs) const

Unit combination operators for unit pairs zero out the shift.

e.g. temperatures are interpreted as temperature differentials

Definition at line 455 of file Units.C.

456{
457 MooseUnits u = rhs;
458 u._factor *= _factor;
459 u._base.insert(u._base.end(), _base.begin(), _base.end());
460 u._shift = 0.0;
461 u.simplify();
462 return u;
463}
Physical unit management class with runtime unit string parsing, unit checking, unit conversion,...
Definition Units.h:33
void simplify()
simplify into the canonical form that permits comparisons
Definition Units.C:500

◆ operator*() [2/2]

MooseUnits MooseUnits::operator* ( const Real  f) const

Unit prefactor scaling.

Definition at line 446 of file Units.C.

447{
448 MooseUnits u = *this;
449 u._factor *= f;
450 u._shift *= f;
451 return u;
452}

◆ operator/()

MooseUnits MooseUnits::operator/ ( const MooseUnits rhs) const

Definition at line 466 of file Units.C.

467{
468 MooseUnits u = rhs;
469 u._factor = _factor / u._factor;
470 for (auto & b : u._base)
471 b.second *= -1;
472 u._base.insert(u._base.end(), _base.begin(), _base.end());
473 u._shift = 0.0;
474 u.simplify();
475 return u;
476}

◆ operator==() [1/2]

bool MooseUnits::operator== ( const MooseUnits rhs) const

Definition at line 479 of file Units.C.

480{
481 if (_factor != rhs._factor || _shift != rhs._shift)
482 return false;
483 return conformsTo(rhs);
484}

◆ operator==() [2/2]

bool MooseUnits::operator== ( const Real  rhs) const

Definition at line 487 of file Units.C.

488{
489 return (_factor == rhs && _shift == 0.0 && _base.empty());
490}

◆ parse()

void MooseUnits::parse ( const std::string &  unit_string)

parse a unit string into a MooseUnits object

Definition at line 234 of file Units.C.

235{
236 // we need to understand * / ^int ( ) string
237 // m^2*kg/(N*s)^2
238 // no numerical expressions are permitted (e.g. no 1/2 0.5 4*2)
239
240 // parse stack
241 std::stack<std::vector<std::pair<MooseUnits::BaseUnit, int>>> stack;
242 std::stack<char> op_stack;
243 std::stack<MooseUnits> out;
244
245 auto it = unit_string.begin();
246 const auto end = unit_string.end();
247
248 do
249 {
250 // skip whitespace
251 if (*it == ' ')
252 {
253 it++;
254 continue;
255 }
256 // opening parenthesis
257 else if (*it == '(')
258 op_stack.push(*(it++));
259 // multiply or divide
260 else if (*it == '*' || *it == '/')
261 {
262 // pop */ off
263 while (!op_stack.empty() && (op_stack.top() == '*' || op_stack.top() == '/'))
264 {
265 auto top = op_stack.top();
266 op_stack.pop();
267
268 if (out.size() < 2)
270 unit_string, it, "Applying ", top, " but don't have enough items on the stack.");
271 auto rhs = out.top();
272 out.pop();
273 if (top == '*')
274 out.top() = out.top() * rhs;
275 else
276 out.top() = out.top() / rhs;
277 }
278
279 op_stack.push(*(it++));
280 }
281 // closing parenthesis
282 else if (*it == ')')
283 {
284 do
285 {
286 if (op_stack.empty())
287 parseError(unit_string, it, "Mismatching right parenthesis.");
288
289 auto top = op_stack.top();
290 op_stack.pop();
291
292 if (top == '(')
293 break;
294
295 if (top == '*' || top == '/')
296 {
297 if (out.size() < 2)
299 unit_string, it, "Applying ", top, " but don't have enough items on the stack.");
300 auto rhs = out.top();
301 out.pop();
302 if (top == '*')
303 out.top() = out.top() * rhs;
304 else
305 out.top() = out.top() / rhs;
306 }
307 } while (true);
308 it++;
309 }
310 // exponent
311 else if (*it == '^')
312 {
313 // check for sign
314 int sign = 1;
315 ++it;
316 if (it != end && *it == '-')
317 {
318 sign = -1;
319 it++;
320 }
321
322 int num = 0;
323 bool valid = false;
324 while (*it >= '0' && *it <= '9')
325 {
326 num *= 10;
327 num += *(it++) - '0';
328 valid = true;
329 }
330
331 // error
332 if (!valid)
333 {
334 if (it == end)
335 parseError(unit_string, it, "Expected a number but found end of string.");
336 else
337 parseError(unit_string, it, "Expected a number but got '", (*it), "'.");
338 }
339
340 // exponents do not get pushed on the stack, but are applied immediately
341 if (out.empty())
342 parseError(unit_string, it, "Applying an exponent, but found no units in front of it.");
343 out.top() = std::pow(out.top(), sign * num);
344 }
345 else
346 {
347 std::string unit;
348 while (it != end && ((*it >= 'a' && *it <= 'z') || (*it >= 'A' && *it <= 'Z') ||
349 (*it >= '0' && *it <= '9') || *it == '.' || *it == '-'))
350 unit += *(it++);
351
352 // check if a number prefix is present
353 Real si_factor;
354 std::stringstream ss(unit);
355 if ((ss >> si_factor).fail() || !std::isfinite(si_factor))
356 si_factor = 1.0;
357 else
358 {
359 if (ss.eof())
360 {
361 out.push(MooseUnits(si_factor));
362 continue;
363 }
364 ss >> unit;
365 }
366
367 // parse the unit and a potential SI prefix
368 auto len = unit.length();
369 if (len == 0)
370 {
371 if (it == end)
372 parseError(unit_string, it, "Expected unit but found end of string.");
373 else
374 parseError(unit_string, it, "Expected unit but found '", *it, "'.");
375 }
376
377 unsigned int i = 0;
378 for (; i < _unit_table.size(); ++i)
379 {
380 const auto & s = _unit_table[i].first;
381 const auto slen = s.length();
382 if (slen <= len && unit.substr(len - slen) == s)
383 break;
384 }
385
386 // invalid unit
387 if (i == _unit_table.size())
388 parseError(unit_string, it, "Unknown unit '", unit, "'.");
389
390 // get prefix
391 const auto & s = _unit_table[i].first;
392 const auto slen = s.length();
393 if (slen < len)
394 {
395 const auto prefix = unit.substr(0, len - slen);
396 auto jt = _si_prefix.find(prefix);
397 if (jt != _si_prefix.end())
398 si_factor = jt->second;
399 else
400 parseError(unit_string, it, "Unknown SI prefix '", prefix, "' on unit '", unit, "'.");
401 }
402
403 // construct a unit object and push to the output stack
404 MooseUnits d = _unit_table[i].second * si_factor;
405 out.push(d);
406 }
407 } while (it != end);
408
409 // unwind operator stack
410 while (!op_stack.empty())
411 {
412 auto top = op_stack.top();
413 op_stack.pop();
414
415 if (top == '(' || top == ')')
416 parseError(unit_string, it, "Unit string contains unmatched parenthesis.");
417
418 if (top == '*' || top == '/')
419 {
420 if (out.size() < 2)
421 parseError(unit_string,
422 it,
423 "Applying ",
424 top,
425 " but don't have enough items on the stack.",
426 out.size());
427 auto rhs = out.top();
428 out.pop();
429 if (top == '*')
430 out.top() = out.top() * rhs;
431 else
432 out.top() = out.top() / rhs;
433 }
434 }
435
436 // consistency check
437 if (out.size() != 1)
438 mooseError("Internal parse error. Remaining output stack size should be 1, but is ",
439 out.size());
440
441 *this = out.top();
442 simplify();
443}
void parseError(const std::string &unit_string, std::string::const_iterator it, Args... args)
helper function to generate a pretty mooseError
Definition Units.h:126
static const std::vector< std::pair< std::string, MooseUnits > > _unit_table
Definition Units.h:22
static const std::map< std::string, Real > _si_prefix
data tables with SI prefixes and known units
Definition Units.h:17
KOKKOS_INLINE_FUNCTION T sign(T x)
Returns the sign of a value.
Definition KokkosUtils.h:26
std::vector< ElemQuality > valid(const ElemType t)
OStreamProxy out(std::cout)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MooseUnits pow(const MooseUnits &, int)
Definition Units.C:537

Referenced by MooseUnits().

◆ parseError()

template<typename... Args>
void MooseUnits::parseError ( const std::string &  unit_string,
std::string::const_iterator  it,
Args...  args 
)
protected

helper function to generate a pretty mooseError

Definition at line 126 of file Units.h.

129{
130 auto d = std::distance(unit_string.begin(), it);
131 mooseError("At position ", d, " in ", unit_string, ": ", std::forward<Args>(args)...);
132}

Referenced by parse().

◆ simplify()

void MooseUnits::simplify ( )

simplify into the canonical form that permits comparisons

Definition at line 500 of file Units.C.

501{
502 std::map<BaseUnit, int> base_map;
503 for (auto & b : _base)
504 {
505 auto j = base_map.find(b.first);
506 if (j == base_map.end())
507 base_map.insert(b);
508 else
509 j->second += b.second;
510 }
511
512 // replace base vector with map contents
513 _base.clear();
514 for (auto & u : base_map)
515 if (u.second != 0)
516 _base.push_back(u);
517}
if(!dmm->_nl) SETERRQ(PETSC_COMM_WORLD

Referenced by operator*(), operator/(), and parse().

◆ text()

std::ostream & MooseUnits::text ( std::ostream &  os)
static

Definition at line 555 of file Units.C.

556{
557 os.iword(geti()) = 0;
558 return os;
559}

Friends And Related Symbol Documentation

◆ operator<<

std::ostream & operator<< ( std::ostream &  os,
const MooseUnits dt 
)
friend

Definition at line 568 of file Units.C.

570{
571 bool latex = (os.iword(MooseUnits::geti()) == 1);
572 static const std::vector<std::string> base_unit = {"m", "kg", "s", "A", "K", "at", "cd"};
573
574 if (u._factor != 1.0 || u._base.empty())
575 {
576 os << u._factor;
577 if (!u._base.empty())
578 os << ' ';
579 }
580
581 for (const auto i : index_range(u._base))
582 {
583 os << (i ? (latex ? "\\cdot " : "*") : "");
584
585 const auto & unit = base_unit[int(u._base[i].first)];
586 if (latex)
587 os << "\\text{" << unit << "}";
588 else
589 os << unit;
590
591 if (u._base[i].second != 1)
592 {
593 if (latex)
594 os << "^{" << u._base[i].second << '}';
595 else
596 os << '^' << u._base[i].second;
597 }
598 }
599
600 return os;
601}
void ErrorVector unsigned int
static std::ostream & latex(std::ostream &os)
iostream manipulators
Definition Units.C:549
auto index_range(const T &sizable)

◆ std::pow

MooseUnits std::pow ( const MooseUnits ,
int   
)
friend

Member Data Documentation

◆ _base

std::vector<std::pair<BaseUnit, int> > MooseUnits::_base
protected

base SI units and their exponents

Definition at line 118 of file Units.h.

Referenced by conformsTo(), isBase(), operator*(), operator/(), operator==(), std::pow(), and simplify().

◆ _factor

Real MooseUnits::_factor
protected

conversion factor w.r.t. the base SI units

Definition at line 109 of file Units.h.

Referenced by convert(), operator*(), operator*(), operator/(), operator==(), operator==(), and std::pow().

◆ _shift

Real MooseUnits::_shift
protected

additive shift (for Celsius and Fahrenheit)

Definition at line 112 of file Units.h.

Referenced by convert(), operator*(), operator*(), operator/(), operator==(), operator==(), and std::pow().

◆ _si_prefix

const std::map< std::string, Real > MooseUnits::_si_prefix
static
Initial value:
= {
{"Y", 1e24}, {"Z", 1e21}, {"E", 1e18}, {"P", 1e15}, {"T", 1e12}, {"G", 1e9}, {"M", 1e6},
{"k", 1e3}, {"h", 1e2}, {"da", 1e1}, {"d", 1e-1}, {"c", 1e-2}, {"m", 1e-3}, {"mu", 1e-6},
{"n", 1e-9}, {"p", 1e-12}, {"f", 1e-15}, {"a", 1e-18}, {"z", 1e-21}, {"y", 1e-24}}

data tables with SI prefixes and known units

Definition at line 17 of file Units.h.

Referenced by parse().

◆ _unit_table

const std::vector< std::pair< std::string, MooseUnits > > MooseUnits::_unit_table
static

Definition at line 22 of file Units.h.

33{
34 enum class BaseUnit
35 {
36 METER,
38 SECOND,
39 AMPERE,
40 KELVIN,
41 COUNT,
43 };
44
45public:
46 MooseUnits(const std::string & unit_string);
47 MooseUnits(Real f) : _factor(f), _shift(), _base() {}
48 MooseUnits(Real f, Real s, std::vector<std::pair<MooseUnits::BaseUnit, int>> b)
49 : _factor(f), _shift(s), _base(b)
50 {
51 }
52
54 bool conformsTo(const MooseUnits &) const;
55
57 Real convert(Real from_value, const MooseUnits & from_unit) const;
58
60 void parse(const std::string & unit_string);
61
63 void simplify();
64
66 static const std::map<std::string, Real> _si_prefix;
67 static const std::vector<std::pair<std::string, MooseUnits>> _unit_table;
69
71 bool isLength() const { return isBase(BaseUnit::METER); }
72 bool isTime() const { return isBase(BaseUnit::SECOND); }
73 bool isMass() const { return isBase(BaseUnit::KILOGRAM); }
74 bool isCurrent() const { return isBase(BaseUnit::AMPERE); }
75 bool isTemperature() const { return isBase(BaseUnit::KELVIN); }
77
79 MooseUnits operator*(const Real f) const;
80
85 MooseUnits operator*(const MooseUnits & rhs) const;
86 MooseUnits operator/(const MooseUnits & rhs) const;
88
89 bool operator==(const MooseUnits & rhs) const;
90 bool operator==(const Real rhs) const;
91
93 explicit operator Real() const;
94
95 friend std::ostream & operator<<(std::ostream & os, const MooseUnits & dt);
96 friend MooseUnits std::pow(const MooseUnits &, int);
97
99 static std::ostream & latex(std::ostream & os);
100 static std::ostream & text(std::ostream & os);
102
103protected:
105 template <typename... Args>
106 void parseError(const std::string & unit_string, std::string::const_iterator it, Args... args);
107
110
112 Real _shift;
113
115 bool isBase(const MooseUnits::BaseUnit) const;
116
118 std::vector<std::pair<BaseUnit, int>> _base;
119
121 static int geti();
122};
123
124template <typename... Args>
125void
126MooseUnits::parseError(const std::string & unit_string,
127 std::string::const_iterator it,
128 Args... args)
129{
130 auto d = std::distance(unit_string.begin(), it);
131 mooseError("At position ", d, " in ", unit_string, ": ", std::forward<Args>(args)...);
132}
bool isCurrent() const
Definition Units.h:74
MooseUnits operator/(const MooseUnits &rhs) const
Definition Units.C:466
friend std::ostream & operator<<(std::ostream &os, const MooseUnits &dt)
Definition Units.C:569
bool isTemperature() const
Definition Units.h:75
bool isLength() const
query the nature of the unit
Definition Units.h:71
Real convert(Real from_value, const MooseUnits &from_unit) const
Converts from_value in units of from_units to value this units.
Definition Units.C:226
bool isTime() const
Definition Units.h:72
MooseUnits operator*(const Real f) const
Unit prefactor scaling.
Definition Units.C:446
bool operator==(const MooseUnits &rhs) const
Definition Units.C:479
bool isMass() const
Definition Units.h:73
static std::ostream & text(std::ostream &os)
Definition Units.C:555

Referenced by parse().


The documentation for this class was generated from the following files: