unit system: add temperature
this requires the possibility of specifying an offset for the SI conversion because Eclipse in its eternal wisdom chooses to specify temperatures using degrees Celsius and degrees Fahrenheit instead of using Kelvin an Rankine...
This commit is contained in:
@@ -46,15 +46,10 @@ namespace Opm {
|
||||
return;
|
||||
}
|
||||
m_SIdata.resize( m_data.size() );
|
||||
if (m_dimensions.size() == 1) {
|
||||
double SIfactor = m_dimensions[0]->getSIScaling();
|
||||
std::transform( m_data.begin() , m_data.end() , m_SIdata.begin() , std::bind1st(std::multiplies<double>(),SIfactor));
|
||||
} else {
|
||||
for (size_t index=0; index < m_data.size(); index++) {
|
||||
size_t dimIndex = (index % m_dimensions.size());
|
||||
double SIfactor = m_dimensions[dimIndex]->getSIScaling();
|
||||
m_SIdata[index] = m_data[index] * SIfactor;
|
||||
}
|
||||
|
||||
for (size_t index=0; index < m_data.size(); index++) {
|
||||
size_t dimIndex = (index % m_dimensions.size());
|
||||
m_SIdata[index] = m_dimensions[dimIndex]->convertRawToSi(m_data[index]);
|
||||
}
|
||||
} else
|
||||
throw std::invalid_argument("No dimension has been set for item:" + name() + " can not ask for SI data");
|
||||
|
||||
@@ -59,15 +59,10 @@ namespace Opm {
|
||||
return;
|
||||
}
|
||||
m_SIdata.resize( m_data.size() );
|
||||
if (m_dimensions.size() == 1) {
|
||||
float SIfactor = m_dimensions[0]->getSIScaling();
|
||||
std::transform( m_data.begin() , m_data.end() , m_SIdata.begin() , std::bind1st(std::multiplies<float>(),SIfactor));
|
||||
} else {
|
||||
for (size_t index=0; index < m_data.size(); index++) {
|
||||
size_t dimIndex = (index % m_dimensions.size());
|
||||
float SIfactor = m_dimensions[dimIndex]->getSIScaling();
|
||||
m_SIdata[index] = m_data[index] * SIfactor;
|
||||
}
|
||||
|
||||
for (size_t index=0; index < m_data.size(); index++) {
|
||||
size_t dimIndex = (index % m_dimensions.size());
|
||||
m_SIdata[index] = m_dimensions[dimIndex]->convertRawToSi(m_data[index]);
|
||||
}
|
||||
} else
|
||||
throw std::invalid_argument("No dimension has been set for item:" + name() + " can not ask for SI data");
|
||||
|
||||
@@ -143,6 +143,19 @@ namespace Opm {
|
||||
const double psia = lbf / square(inch);
|
||||
/// @}
|
||||
|
||||
/// \name Temperature. This one is more complicated
|
||||
/// because the unit systems used by Eclipse (i.e. degrees
|
||||
/// Celsius and degrees Fahrenheit require to add or
|
||||
/// subtract an offset for the conversion between from/to
|
||||
/// Kelvin
|
||||
/// @{
|
||||
const double degCelsius = 1.0; // scaling factor °C -> K
|
||||
const double degCelsiusOffset = 273.15; // offset for the °C -> K conversion
|
||||
|
||||
const double degFahrenheit = 5.0/9; // scaling factor °F -> K
|
||||
const double degFahrenheitOffset = 255.37; // offset for the °C -> K conversion
|
||||
/// @}
|
||||
|
||||
/// \name Viscosity
|
||||
/// @{
|
||||
const double Pas = Pascal * second; // == 1
|
||||
@@ -179,6 +192,8 @@ namespace Opm {
|
||||
using namespace details::prefix;
|
||||
using namespace details::unit;
|
||||
const double Pressure = barsa;
|
||||
const double Temperature = degCelsius;
|
||||
const double TemperatureOffset = degCelsiusOffset;
|
||||
const double Length = meter;
|
||||
const double Time = day;
|
||||
const double Mass = kilogram;
|
||||
@@ -198,6 +213,8 @@ namespace Opm {
|
||||
using namespace details::prefix;
|
||||
using namespace details::unit;
|
||||
const double Pressure = psia;
|
||||
const double Temperature = degFahrenheit;
|
||||
const double TemperatureOffset = degFahrenheitOffset;
|
||||
const double Length = feet;
|
||||
const double Time = day;
|
||||
const double Mass = pound;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Opm {
|
||||
|
||||
}
|
||||
|
||||
Dimension::Dimension(const std::string& name, double SIfactor)
|
||||
Dimension::Dimension(const std::string& name, double SIfactor, double SIoffset)
|
||||
{
|
||||
for (auto iter = name.begin(); iter != name.end(); ++iter) {
|
||||
if (!isalpha(*iter) && (*iter) != '1')
|
||||
@@ -37,9 +37,9 @@ namespace Opm {
|
||||
}
|
||||
m_name = name;
|
||||
m_SIfactor = SIfactor;
|
||||
m_SIoffset = SIoffset;
|
||||
}
|
||||
|
||||
|
||||
double Dimension::getSIScaling() const {
|
||||
if (!std::isfinite(m_SIfactor))
|
||||
throw std::logic_error("The DeckItem contains a field with a context dependent unit. "
|
||||
@@ -47,15 +47,39 @@ namespace Opm {
|
||||
return m_SIfactor;
|
||||
}
|
||||
|
||||
double Dimension::getSIOffset() const {
|
||||
return m_SIoffset;
|
||||
}
|
||||
|
||||
double Dimension::convertRawToSi(double rawValue) const {
|
||||
if (!std::isfinite(m_SIfactor))
|
||||
throw std::logic_error("The DeckItem contains a field with a context dependent unit. "
|
||||
"Use getRawDoubleData() and convert the returned value manually!");
|
||||
|
||||
return rawValue*m_SIfactor + m_SIoffset;
|
||||
}
|
||||
|
||||
double Dimension::convertSiToRaw(double siValue) const {
|
||||
if (!std::isfinite(m_SIfactor))
|
||||
throw std::logic_error("The DeckItem contains a field with a context dependent unit. "
|
||||
"Use getRawDoubleData() and convert the returned value manually!");
|
||||
|
||||
return (siValue - m_SIoffset)/m_SIfactor;
|
||||
}
|
||||
|
||||
const std::string& Dimension::getName() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
// only dimensions with zero offset are compositable...
|
||||
bool Dimension::isCompositable() const
|
||||
{ return m_SIoffset == 0.0; }
|
||||
|
||||
Dimension * Dimension::newComposite(const std::string& dim , double SIfactor) {
|
||||
Dimension * Dimension::newComposite(const std::string& dim , double SIfactor, double SIoffset) {
|
||||
Dimension * dimension = new Dimension();
|
||||
dimension->m_name = dim;
|
||||
dimension->m_SIfactor = SIfactor;
|
||||
dimension->m_SIoffset = SIoffset;
|
||||
|
||||
return dimension;
|
||||
}
|
||||
@@ -64,7 +88,7 @@ namespace Opm {
|
||||
bool Dimension::equal(const Dimension& other) const {
|
||||
if (m_name != other.m_name)
|
||||
return false;
|
||||
if (m_SIfactor == other.m_SIfactor)
|
||||
if (m_SIfactor == other.m_SIfactor && m_SIoffset == other.m_SIoffset)
|
||||
return true;
|
||||
if (std::isnan(m_SIfactor) && std::isnan(other.m_SIfactor))
|
||||
return true;
|
||||
|
||||
@@ -26,16 +26,24 @@ namespace Opm {
|
||||
|
||||
class Dimension {
|
||||
public:
|
||||
Dimension(const std::string& name, double SI_factor);
|
||||
Dimension(const std::string& name, double SIfactor, double SIoffset = 0.0);
|
||||
|
||||
double getSIScaling() const;
|
||||
double getSIOffset() const;
|
||||
|
||||
double convertRawToSi(double rawValue) const;
|
||||
double convertSiToRaw(double siValue) const;
|
||||
|
||||
bool equal(const Dimension& other) const;
|
||||
const std::string& getName() const;
|
||||
static Dimension * newComposite(const std::string& dim , double SIfactor);
|
||||
bool isCompositable() const;
|
||||
static Dimension * newComposite(const std::string& dim, double SIfactor, double SIoffset = 0.0);
|
||||
|
||||
private:
|
||||
Dimension();
|
||||
std::string m_name;
|
||||
double m_SIfactor;
|
||||
double m_SIoffset;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace Opm {
|
||||
m_dimensions.insert( std::make_pair(dimension->getName() , dimension));
|
||||
}
|
||||
|
||||
void UnitSystem::addDimension(const std::string& dimension , double SI_factor) {
|
||||
std::shared_ptr<const Dimension> dim( new Dimension(dimension , SI_factor) );
|
||||
void UnitSystem::addDimension(const std::string& dimension , double SIfactor, double SIoffset) {
|
||||
std::shared_ptr<const Dimension> dim( new Dimension(dimension , SIfactor, SIoffset) );
|
||||
addDimension(dim);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,13 @@ namespace Opm {
|
||||
double SIfactor = 1.0;
|
||||
for (auto iter = dimensionList.begin(); iter != dimensionList.end(); ++iter) {
|
||||
std::shared_ptr<const Dimension> dim = getDimension( *iter );
|
||||
|
||||
// all constituing dimension must be compositable. The
|
||||
// only exception is if there is the "composite" dimension
|
||||
// consists of exactly a single atomic dimension...
|
||||
if (dimensionList.size() > 1 && !dim->isCompositable())
|
||||
throw std::invalid_argument("Composite dimensions currently cannot require a conversion offset");
|
||||
|
||||
SIfactor *= dim->getSIScaling();
|
||||
}
|
||||
return std::shared_ptr<Dimension>(Dimension::newComposite( dimension , SIfactor ));
|
||||
@@ -106,6 +113,9 @@ namespace Opm {
|
||||
boost::split(parts , dimension , boost::is_any_of("/"));
|
||||
std::shared_ptr<const Dimension> dividend = parseFactor( parts[0] );
|
||||
std::shared_ptr<const Dimension> divisor = parseFactor( parts[1] );
|
||||
|
||||
if (dividend->getSIOffset() != 0.0 || divisor->getSIOffset() != 0.0)
|
||||
throw std::invalid_argument("Composite dimensions cannot currently require a conversion offset");
|
||||
|
||||
return std::shared_ptr<Dimension>( Dimension::newComposite( dimension , dividend->getSIScaling() / divisor->getSIScaling() ));
|
||||
} else {
|
||||
@@ -139,6 +149,7 @@ namespace Opm {
|
||||
|
||||
system->addDimension("1" , 1.0);
|
||||
system->addDimension("Pressure" , Metric::Pressure );
|
||||
system->addDimension("Temperature", Metric::Temperature, Metric::TemperatureOffset);
|
||||
system->addDimension("Length" , Metric::Length);
|
||||
system->addDimension("Time" , Metric::Time );
|
||||
system->addDimension("Mass" , Metric::Mass );
|
||||
@@ -162,6 +173,7 @@ namespace Opm {
|
||||
|
||||
system->addDimension("1" , 1.0);
|
||||
system->addDimension("Pressure", Field::Pressure );
|
||||
system->addDimension("Temperature", Field::Temperature, Field::TemperatureOffset);
|
||||
system->addDimension("Length", Field::Length);
|
||||
system->addDimension("Time" , Field::Time);
|
||||
system->addDimension("Mass", Field::Mass);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Opm {
|
||||
UnitSystem(const std::string& unitSystem);
|
||||
const std::string& getName() const;
|
||||
|
||||
void addDimension(const std::string& dimension , double SI_factor);
|
||||
void addDimension(const std::string& dimension, double SIfactor, double SIoffset = 0.0);
|
||||
void addDimension(std::shared_ptr<const Dimension> dimension);
|
||||
std::shared_ptr<const Dimension> getNewDimension(const std::string& dimension);
|
||||
std::shared_ptr<const Dimension> getDimension(const std::string& dimension) const;
|
||||
|
||||
@@ -41,6 +41,11 @@ BOOST_AUTO_TEST_CASE(makeComposite) {
|
||||
BOOST_CHECK_EQUAL(100 , composite->getSIScaling());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MakeCompositeInvalid) {
|
||||
// conversion to SI temperatures requires an offset, but such
|
||||
// composite units are (currently?) invalid
|
||||
BOOST_CHECK_THROW(Dimension::newComposite("Length*Temperature", 100), std::logic_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CreateDimensionInvalidNameThrows) {
|
||||
BOOST_CHECK_THROW(Dimension(" " , 1) , std::invalid_argument);
|
||||
@@ -89,11 +94,15 @@ BOOST_AUTO_TEST_CASE(UnitSystemAddDimensions) {
|
||||
UnitSystem system("Metric");
|
||||
system.addDimension("Length" , 1 );
|
||||
system.addDimension("Time" , 86400 );
|
||||
system.addDimension("Temperature", 1.0, 273.15);
|
||||
|
||||
std::shared_ptr<const Dimension> length = system.getDimension("Length");
|
||||
std::shared_ptr<const Dimension> time = system.getDimension("Time");
|
||||
std::shared_ptr<const Dimension> temperature = system.getDimension("Temperature");
|
||||
BOOST_CHECK_EQUAL(1 , length->getSIScaling());
|
||||
BOOST_CHECK_EQUAL(86400 , time->getSIScaling());
|
||||
BOOST_CHECK_EQUAL(1.0 , temperature->getSIScaling());
|
||||
BOOST_CHECK_EQUAL(273.15, temperature->getSIOffset());
|
||||
|
||||
system.addDimension("Length" , 0.3048);
|
||||
length = system.getDimension("Length");
|
||||
@@ -123,6 +132,7 @@ static void checkSystemHasRequiredDimensions(std::shared_ptr<const UnitSystem> s
|
||||
BOOST_CHECK( system->hasDimension("Time"));
|
||||
BOOST_CHECK( system->hasDimension("Permeability"));
|
||||
BOOST_CHECK( system->hasDimension("Pressure"));
|
||||
BOOST_CHECK( system->hasDimension("Temperature"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user