LBPM/common/Units.cpp
2023-10-23 04:18:20 -04:00

229 lines
8.5 KiB
C++

/*
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
Copyright Equnior ASA
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Units.h"
#include "common/Utilities.h"
#include <algorithm>
#include <cmath>
#include <string>
constexpr double Units::d_pow10[22];
constexpr char Units::d_prefixSymbol[];
/********************************************************************
* Constructors *
********************************************************************/
Units::Units() : d_prefix(UnitPrefix::unknown), d_unit(UnitValue::unknown) {}
Units::Units(UnitPrefix p, UnitValue u) : d_prefix(p), d_unit(u) {}
Units::Units(const std::string &unit)
: d_prefix(UnitPrefix::unknown), d_unit(UnitValue::unknown) {
// Parse the string to get it into a more friendly format
auto tmp = unit;
tmp.erase(std::remove(tmp.begin(), tmp.end(), ' '), tmp.end());
// Check if the character '-' is present indicating a seperation between the prefix and unit
size_t index = tmp.find('-');
if (index != std::string::npos) {
d_prefix = getUnitPrefix(tmp.substr(0, index));
d_unit = getUnitValue(tmp.substr(index + 1));
} else {
if (tmp.size() <= 1) {
d_prefix = UnitPrefix::none;
d_unit = getUnitValue(tmp);
} else if (tmp.substr(0, 2) == "da") {
d_prefix = UnitPrefix::deca;
d_unit = getUnitValue(tmp.substr(2));
} else {
d_prefix = getUnitPrefix(tmp.substr(0, 1));
d_unit = getUnitValue(tmp.substr(1));
if (d_prefix == UnitPrefix::unknown ||
d_unit == UnitValue::unknown) {
d_prefix = UnitPrefix::none;
d_unit = getUnitValue(tmp);
}
}
}
}
/********************************************************************
* Get prefix *
********************************************************************/
Units::UnitPrefix Units::getUnitPrefix(const std::string &str) noexcept {
Units::UnitPrefix value = UnitPrefix::unknown;
if (str.empty()) {
value = UnitPrefix::none;
} else if (str == "yotta" || str == "Y") {
value = UnitPrefix::yotta;
} else if (str == "zetta" || str == "Z") {
value = UnitPrefix::zetta;
} else if (str == "exa" || str == "E") {
value = UnitPrefix::exa;
} else if (str == "peta" || str == "P") {
value = UnitPrefix::peta;
} else if (str == "tera" || str == "T") {
value = UnitPrefix::tera;
} else if (str == "giga" || str == "G") {
value = UnitPrefix::giga;
} else if (str == "mega" || str == "M") {
value = UnitPrefix::mega;
} else if (str == "kilo" || str == "k") {
value = UnitPrefix::kilo;
} else if (str == "hecto" || str == "h") {
value = UnitPrefix::hecto;
} else if (str == "deca" || str == "da") {
value = UnitPrefix::deca;
} else if (str == "deci" || str == "d") {
value = UnitPrefix::deci;
} else if (str == "centi" || str == "c") {
value = UnitPrefix::centi;
} else if (str == "milli" || str == "m") {
value = UnitPrefix::milli;
} else if (str == "micro" || str == "u") {
value = UnitPrefix::micro;
} else if (str == "nano" || str == "n") {
value = UnitPrefix::nano;
} else if (str == "pico" || str == "p") {
value = UnitPrefix::pico;
} else if (str == "femto" || str == "f") {
value = UnitPrefix::femto;
} else if (str == "atto" || str == "a") {
value = UnitPrefix::atto;
} else if (str == "zepto" || str == "z") {
value = UnitPrefix::zepto;
} else if (str == "yocto" || str == "y") {
value = UnitPrefix::yocto;
}
return value;
}
/********************************************************************
* Get unit value *
********************************************************************/
Units::UnitValue Units::getUnitValue(const std::string &str) noexcept {
Units::UnitValue value = UnitValue::unknown;
if (str == "meter" || str == "m") {
value = UnitValue::meter;
} else if (str == "gram" || str == "g") {
value = UnitValue::gram;
} else if (str == "second" || str == "s") {
value = UnitValue::second;
} else if (str == "ampere" || str == "A") {
value = UnitValue::ampere;
} else if (str == "kelvin" || str == "K") {
value = UnitValue::kelvin;
} else if (str == "joule" || str == "J") {
value = UnitValue::joule;
} else if (str == "ergs" || str == "erg") {
value = UnitValue::erg;
} else if (str == "degree" || str == "degrees") {
value = UnitValue::degree;
} else if (str == "radian" || str == "radians") {
value = UnitValue::radian;
}
return value;
}
/********************************************************************
* Get unit type *
********************************************************************/
Units::UnitType Units::getUnitType(UnitValue u) noexcept {
switch (u) {
case UnitValue::meter:
return UnitType::length;
case UnitValue::gram:
return UnitType::mass;
case UnitValue::second:
return UnitType::time;
case UnitValue::ampere:
return UnitType::current;
case UnitValue::kelvin:
return UnitType::temperature;
case UnitValue::joule:
case UnitValue::erg:
return UnitType::energy;
case UnitValue::degree:
case UnitValue::radian:
return UnitType::angle;
default:
return UnitType::unknown;
}
}
/********************************************************************
* Convert to another unit system *
********************************************************************/
double Units::convert(const Units &rhs) const noexcept {
if (this->operator==(rhs))
return 1;
// Convert the prefix
double cp = convert(d_prefix) / convert(rhs.d_prefix);
if (d_unit == rhs.d_unit)
return cp; // Only need to convert prefix
// Convert the unit
if (getUnitType(d_unit) != getUnitType(rhs.d_unit))
return 0; // Invalid conversion
double cu = 0;
if (d_unit == UnitValue::joule && rhs.d_unit == UnitValue::erg)
cu = 1e7;
else if (d_unit == UnitValue::erg && rhs.d_unit == UnitValue::joule)
cu = 1e-7;
else if (d_unit == UnitValue::degree && rhs.d_unit == UnitValue::radian)
cu = 0.017453292519943;
else if (d_unit == UnitValue::radian && rhs.d_unit == UnitValue::degree)
cu = 57.295779513082323;
// Return the total conversion
return cp * cu;
}
/********************************************************************
* Write a string for the units *
********************************************************************/
std::string Units::str() const {
ASSERT(!isNull());
return std::string(str(d_prefix).data()) + str(d_unit);
}
std::array<char, 3> Units::str(UnitPrefix p) noexcept {
std::array<char, 3> str;
str[0] = d_prefixSymbol[static_cast<int8_t>(p)];
str[1] = 0;
str[2] = 0;
if (p == UnitPrefix::deca)
str[1] = 'a';
return str;
}
std::string Units::str(UnitValue u) {
if (u == UnitValue::meter) {
return "m";
} else if (u == UnitValue::gram) {
return "g";
} else if (u == UnitValue::second) {
return "s";
} else if (u == UnitValue::ampere) {
return "A";
} else if (u == UnitValue::kelvin) {
return "K";
} else if (u == UnitValue::joule) {
return "J";
} else if (u == UnitValue::erg) {
return "erg";
} else if (u == UnitValue::degree) {
return "degree";
} else if (u == UnitValue::radian) {
return "radian";
}
return "unknown";
}