10#include <unordered_map>
20struct Unit : std::pair<double,std::array<int,7>>
30 inline static const std::map<std::string, std::pair<double,std::array<int,7>>>
base_units =
32 {
"1", {1.0, {0,0,0,0,0,0,0}}},
33 {
"m", {1.0, {1,0,0,0,0,0,0}}},
34 {
"s", {1.0, {0,1,0,0,0,0,0}}},
35 {
"kg", {1.0, {0,0,1,0,0,0,0}}},
36 {
"K", {1.0, {0,0,0,1,0,0,0}}},
37 {
"A", {1.0, {0,0,0,0,1,0,0}}},
38 {
"mol",{1.0, {0,0,0,0,0,1,0}}},
39 {
"cd", {1.0, {0,0,0,0,0,0,1}}}
47 inline static const std::map<std::string, std::pair<double,std::string>>
compound = {
51 {
"dam", {1e+1,
"m" }},
57 {
"pm", {1e-12,
"m" }},
58 {
"in", {0.0254,
"m" }},
59 {
"ft", {0.3048,
"m" }},
60 {
"yd", {0.9144,
"m" }},
61 {
"mi", {5280.0,
"ft" }},
62 {
"furlong", {660.0,
"ft" }},
63 {
"au", {1.495978707e11,
"m" }},
64 {
"ly", {9.4607304725808e15,
"m"}},
65 {
"pc", {3.08567758149137e16,
"m"}},
69 {
"deg", {0.01745329251,
"rad" }},
75 {
"ps", {1e-12,
"s" }},
76 {
"min", {60.0,
"s" }},
77 {
"hr", {60.0,
"min" }},
78 {
"day", {24.0,
"hr" }},
79 {
"week", {7.0,
"day" }},
80 {
"fortnight", {14.0,
"day" }},
81 {
"year", {365.25,
"day" }},
82 {
"decade", {10.0,
"year" }},
86 {
"mg", {1e-6,
"kg" }},
87 {
"ug", {1e-9,
"kg" }},
88 {
"tonne", {1000.0,
"kg" }},
89 {
"lb", {0.45359237,
"kg" }},
90 {
"oz", {0.0283495,
"kg" }},
91 {
"slug", {14.5939,
"kg" }},
94 {
"mph", {1.0,
"mi/hr" }},
95 {
"kph", {1.0,
"km/hr" }},
96 {
"mps", {1.0,
"m/s" }},
97 {
"fps", {1.0,
"ft/s" }},
98 {
"knot", {1852.0 / 3600.0,
"m/s"}},
101 {
"ha", {1e4,
"m^2" }},
102 {
"acre", {4046.85642,
"m^2" }},
103 {
"sqft", {1.0,
"ft^2" }},
104 {
"sqin", {1.0,
"in^2" }},
105 {
"sqkm", {1.0,
"km^2" }},
106 {
"sqmi", {1.0,
"mi^2" }},
109 {
"L", {1e-3,
"m^3" }},
110 {
"mL", {1e-6,
"m^3" }},
111 {
"cc", {1e-6,
"m^3" }},
112 {
"gal", {3.78541e-3,
"m^3" }},
113 {
"qt", {0.946353e-3,
"m^3" }},
114 {
"pt", {0.473176e-3,
"m^3" }},
115 {
"cup", {0.24e-3,
"m^3" }},
116 {
"floz", {29.5735e-6,
"m^3" }},
117 {
"tbsp", {14.7868e-6,
"m^3" }},
118 {
"tsp", {4.92892e-6,
"m^3" }},
121 {
"N", {1.0,
"kg*m/s^2" }},
123 {
"lbf", {4.44822162,
"N" }},
124 {
"dyn", {1e-5,
"N" }},
127 {
"J", {1.0,
"N*m" }},
128 {
"mJ", {1e-3,
"J" }},
131 {
"eV", {1.602176634e-19,
"J"}},
132 {
"cal", {4.184,
"J" }},
133 {
"kcal", {4184.0,
"J" }},
134 {
"BTU", {1055.06,
"J" }},
135 {
"ft*lbf", {1.35582,
"J" }},
138 {
"W", {1.0,
"J/s" }},
139 {
"mW", {1e-3,
"W" }},
142 {
"hp", {745.7,
"W" }},
145 {
"Pa", {1.0,
"N/m^2" }},
146 {
"kPa", {1e3,
"Pa" }},
147 {
"MPa", {1e6,
"Pa" }},
148 {
"GPa", {1e9,
"Pa" }},
149 {
"bar", {1e5,
"Pa" }},
150 {
"atm", {101325.0,
"Pa" }},
151 {
"psi", {6894.76,
"Pa" }},
152 {
"mmHg", {133.322,
"Pa" }},
153 {
"torr", {133.322,
"Pa" }},
157 {
"degR", {5.0/9.0,
"K" }},
160 {
"C", {1.0,
"A*s" }},
161 {
"mAh", {3.6,
"C" }},
164 {
"V", {1.0,
"J/C" }},
167 {
"F", {1.0,
"C/V" }},
170 {
"ohm", {1.0,
"V/A" }},
171 {
"kOhm", {1e3,
"ohm" }},
172 {
"MOhm", {1e6,
"ohm" }},
175 {
"S", {1.0,
"1/ohm" }},
178 {
"T", {1.0,
"kg/(A*s^2)"}},
182 {
"Hz", {1.0,
"1/s" }},
183 {
"kHz", {1e3,
"Hz" }},
184 {
"MHz", {1e6,
"Hz" }},
185 {
"GHz", {1e9,
"Hz" }},
188 {
"kmol", {1e3,
"mol" }}
255 inline static std::array<std::pair<std::string,double>, 7>
normalization = {
258 std::pair{
"kg", 1.0},
261 std::pair{
"mol",1.0},
265 using std::pair<double, std::array<int,7>>::pair;
266 Unit(
const std::pair<
double, std::array<int, 7>>& p) : std::pair<double, std::array<int, 7>>(p) {}
267 static std::map<std::string, int>
ParseUnitString(
const std::string& input);
270 static Unit Parse(
double val, std::string unitstring,
bool verbose =
false)
276 static Unit Parse(std::string unit,
bool verbose =
false)
279 std::vector<std::string> split;
280 std::stringstream ss(unit);
282 while (std::getline(ss, item,
'_')) {
283 split.push_back(item);
285 if (split.size() == 2)
287 return Parse(std::stod(split[0]),split[1], verbose);
289 else if (split.size() == 1)
299 value = std::strtod(unit.c_str(), &end);
303 if (end != unit.data() && *end ==
'\0')
317 throw std::runtime_error(
"Invalid unit string "+unit);
330 for (
auto parsed_unit : parsed_units)
332 std::cout << parsed_unit.first <<
" " << parsed_unit.second << std::endl;
336 for (
auto &p : parsed_units)
338 const std::string &token = p.first;
351 double factor = pair.first;
352 const std::string &subunit_str = pair.second;
356 t.first *= std::pow(factor, exp);
362 throw std::runtime_error(
"Unknown unit token: " + token);
372 if (parsed.second !=
Length().second)
throw std::runtime_error(
"Not a unit of length: " + unit);
380 if (parsed.second !=
Time().second)
throw std::runtime_error(
"Not a unit of time: " + unit);
388 if (parsed.second !=
Mass().second)
throw std::runtime_error(
"Not a unit of mass: " + unit);
396 if (parsed.second !=
Temperature().second)
throw std::runtime_error(
"Not a unit of temperature: " + unit);
404 if (parsed.second !=
Current().second)
throw std::runtime_error(
"Not a unit of current: " + unit);
412 if (parsed.second !=
Amount().second)
throw std::runtime_error(
"Not a unit of amount: " + unit);
420 if (parsed.second !=
LuminousIntensity().second)
throw std::runtime_error(
"Not a unit of luminous intensity: " + unit);
427 return this->second == test.second;
433 ret.first = this->first * rhs.first;
434 for (
unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i] + rhs.second[i];
439 ret.first = lhs * rhs.first;
440 ret.second = rhs.second;
445 ret.first = rhs * lhs.first;
446 ret.second = lhs.second;
452 ret.first = this->first / rhs.first;
453 for (
unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i] - rhs.second[i];
458 ret.first = lhs * rhs.first;
463 ret.first = lhs.first / rhs;
464 ret.second = lhs.second;
471 ret.first = this->first + rhs.first;
472 for (
unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i];
477 Util::Assert(
INFO,
TEST(this->second == rhs.second),
"Error subtracting values with unequal units");
479 ret.first = this->first - rhs.first;
480 for (
unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i];
486 ret.first = std::pow(this->first,rhs);
487 for (
unsigned int i = 0; i < this->second.size(); i++)
489 ret.second[i] = (this->second)[i]*rhs;
504 for (
unsigned int i = 0 ; i < this->second.size(); i++)
507 return this->first * fac;
513 auto join = [] (std::vector<std::string>vec,std::string sep){
514 std::ostringstream oss;
515 for (
size_t i = 0; i < vec.size(); ++i) {
517 if (i < vec.size() - 1) {
524 std::vector<std::string> num, den;
525 for (
unsigned int i = 0 ; i < this->second.size(); i++)
527 if (this->second[i] > 1)
528 num.push_back(
normalization[i].first +
"^" + std::to_string(this->second[i]));
529 else if (this->second[i] == 1)
531 else if (this->second[i] == -1)
533 else if (this->second[i] < -1)
534 den.push_back(
normalization[i].first +
"^" + std::to_string(std::abs(this->second[i])));
538 if (num.size()) ret = join(num,
"*");
540 if (den.size()) ret +=
"/" + join(den,
"/");
547inline std::map<std::string, int>
549 std::map<std::string, int> result;
550 enum class Op { Mul = 1, Div = -1 };
551 Op currentOp = Op::Mul;
554 auto parse_unit = [&](
const std::string&
t, Op op) {
555 if (
t.empty())
return;
557 size_t caret =
t.find(
'^');
558 std::string base =
t;
561 if (caret != std::string::npos) {
562 base =
t.substr(0, caret);
563 std::string exp_str =
t.substr(caret + 1);
565 exp = std::stoi(exp_str);
567 throw std::runtime_error(
"Invalid exponent: " + exp_str);
570 int signed_exp = (op == Op::Mul ? +1 : -1) * exp;
571 result[base] += signed_exp;
574 while (i < input.size()) {
579 parse_unit(token, currentOp);
586 parse_unit(token, currentOp);
599 parse_unit(token, currentOp);
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Unit operator^(const int &rhs)
static void setTimeUnit(std::string unit)
bool isType(const Unit &test) const
Unit(const std::pair< double, std::array< int, 7 > > &p)
friend Unit operator*(double lhs, const Unit &rhs)
Unit operator-(const Unit &rhs)
static Unit Conductance()
static Unit HeatTransferCoefficient()
friend std::ostream & operator<<(std::ostream &out, const Unit &a)
static std::array< std::pair< std::string, double >, 7 > normalization
std::string normalized_unitstring() const
static const std::map< std::string, std::pair< double, std::string > > compound
static Unit ThermalDiffusivity()
static std::map< std::string, int > ParseUnitString(const std::string &input)
static Unit Parse(double val, std::string unitstring, bool verbose=false)
double normalized_value() const
static Unit ThermalConductivity()
Unit operator+(const Unit &rhs)
static void setLuminousIntensityUnit(std::string unit)
static Unit Temperature()
static void setLengthUnit(std::string unit)
static void setMassUnit(std::string unit)
static Unit Illuminance()
friend Unit operator/(double lhs, const Unit &rhs)
static Unit LuminousFlux()
static Unit Capacitance()
static void setTemperatureUnit(std::string unit)
static Unit LuminousIntensity()
static void setCurrentUnit(std::string unit)
static Unit Acceleration()
static const std::map< std::string, std::pair< double, std::array< int, 7 > > > base_units
friend Unit operator*(const Unit &lhs, double rhs)
static void setAmountUnit(std::string unit)
static Unit MolarEnergy()
static Unit Concentration()
static Unit Parse(std::string unit, bool verbose=false)
static Unit MolarHeatCapacity()
static Unit SpecificWeight()
static Unit SpecificHeatCapacity()
static Unit MagneticFlux()
static Unit StringParse(std::string unitstring, bool verbose=false)
static Unit MagneticField()