/* 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 . */ #include "common/Units.h" #include "common/Utilities.h" #include #include #include 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 Units::str(UnitPrefix p) noexcept { std::array str; str[0] = d_prefixSymbol[static_cast(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"; }