diff --git a/opm/parser/eclipse/CMakeLists.txt b/opm/parser/eclipse/CMakeLists.txt index 101d0829f..e5bc00791 100644 --- a/opm/parser/eclipse/CMakeLists.txt +++ b/opm/parser/eclipse/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(RawDeck/tests) add_subdirectory(Deck/tests) add_subdirectory(IntegrationTests) add_subdirectory(EclipseState/Schedule/tests) +add_subdirectory(Units/tests) add_subdirectory( Applications ) @@ -11,6 +12,11 @@ RawDeck/StarToken.cpp RawDeck/RawKeyword.cpp RawDeck/RawRecord.cpp ) +set( unit_source +Units/UnitSystemMap.cpp +Units/UnitSystem.cpp +Units/Dimension.cpp) + set( deck_source Deck/Deck.cpp Deck/DeckKeyword.cpp @@ -83,6 +89,11 @@ Parser/ParserBoolItem.hpp Parser/ParserDoubleItem.hpp Parser/ParserStringItem.hpp # +Units/UnitSystemMap.hpp +Units/UnitSystem.hpp +Units/Dimension.hpp +Units/ConversionFactors.hpp +# EclipseState/Schedule/TimeMap.hpp EclipseState/Schedule/Schedule.hpp EclipseState/Schedule/Well.hpp @@ -96,7 +107,7 @@ EclipseState/Schedule/GroupTreeNode.hpp EclipseState/Schedule/GroupTree.hpp ) -add_library(buildParser ${rawdeck_source} ${build_parser_source} ${deck_source}) +add_library(buildParser ${rawdeck_source} ${build_parser_source} ${deck_source} ${unit_source}) target_link_libraries(buildParser opm-json ${Boost_LIBRARIES}) #----------------------------------------------------------------- @@ -111,7 +122,7 @@ add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/generated-source/DefaultKeyword #----------------------------------------------------------------- -add_library(Parser ${rawdeck_source} ${parser_source} ${deck_source} ${state_source}) +add_library(Parser ${rawdeck_source} ${parser_source} ${deck_source} ${state_source} ${unit_source}) target_link_libraries(Parser opm-json ${Boost_LIBRARIES}) include( ${PROJECT_SOURCE_DIR}/cmake/Modules/install_headers.cmake ) diff --git a/opm/parser/eclipse/Parser/Dimension.hpp b/opm/parser/eclipse/Parser/Dimension.hpp new file mode 100644 index 000000000..bea732fa3 --- /dev/null +++ b/opm/parser/eclipse/Parser/Dimension.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#ifndef DIMENSION_H +#define DIMENSION_H + +#include + +namespace Opm { + + class Dimension { + public: + Dimension(const std::string& name, double SI_factor); + double getSIScaling() const; + const std::string& getName() const; + static Dimension makeComposite(const std::string& dim , double SIfactor); + + private: + Dimension(); + std::string m_name; + double m_SIfactor; + }; +} + + +#endif + diff --git a/opm/parser/eclipse/Units/ConversionFactors.hpp b/opm/parser/eclipse/Units/ConversionFactors.hpp new file mode 100644 index 000000000..5f4e0011f --- /dev/null +++ b/opm/parser/eclipse/Units/ConversionFactors.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#ifndef CONVERSION_FACTORS_HPP +#define CONVERSION_FACTORS_HPP + + +namespace Opm { + + namespace Metric { + const double Pressure = 100000; + const double Length = 1.0; + const double Time = 86400; + const double Mass = 1.0; + const double Permeability = 9.869233e-10; + } + + namespace Field { + const double Pressure = 6894.76; + const double Length = 0.3048; + const double Time = 86400; + const double Mass = 0.45359237; + const double Permeability = 9.869233e-10; + } + +} + + +#endif diff --git a/opm/parser/eclipse/Units/Dimension.cpp b/opm/parser/eclipse/Units/Dimension.cpp new file mode 100644 index 000000000..64d369605 --- /dev/null +++ b/opm/parser/eclipse/Units/Dimension.cpp @@ -0,0 +1,60 @@ +/* + Copyright 2013 Statoil 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 + +#include +#include + +namespace Opm { + + Dimension::Dimension() { + + } + + Dimension::Dimension(const std::string& name, double SIfactor) + { + for (auto iter = name.begin(); iter != name.end(); ++iter) { + if (!isalpha(*iter) && (*iter) != '1') + throw std::invalid_argument("Invalid dimension name"); + } + m_name = name; + m_SIfactor = SIfactor; + } + + + double Dimension::getSIScaling() const { + return m_SIfactor; + } + + const std::string& Dimension::getName() const { + return m_name; + } + + Dimension Dimension::makeComposite(const std::string& dim , double SIfactor) { + Dimension dimension; + dimension.m_name = dim; + dimension.m_SIfactor = SIfactor; + + return dimension; + } + +} + + diff --git a/opm/parser/eclipse/Units/Dimension.hpp b/opm/parser/eclipse/Units/Dimension.hpp new file mode 100644 index 000000000..bea732fa3 --- /dev/null +++ b/opm/parser/eclipse/Units/Dimension.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#ifndef DIMENSION_H +#define DIMENSION_H + +#include + +namespace Opm { + + class Dimension { + public: + Dimension(const std::string& name, double SI_factor); + double getSIScaling() const; + const std::string& getName() const; + static Dimension makeComposite(const std::string& dim , double SIfactor); + + private: + Dimension(); + std::string m_name; + double m_SIfactor; + }; +} + + +#endif + diff --git a/opm/parser/eclipse/Units/UnitSystem.cpp b/opm/parser/eclipse/Units/UnitSystem.cpp new file mode 100644 index 000000000..5ade6492a --- /dev/null +++ b/opm/parser/eclipse/Units/UnitSystem.cpp @@ -0,0 +1,133 @@ +/* + Copyright 2013 Statoil 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 +#include +#include + +#include +#include +#include + + +namespace Opm { + + UnitSystem::UnitSystem(const std::string& unitSystem) : + m_name( unitSystem ) + { + + } + + bool UnitSystem::hasDimension(const std::string& dimension) const { + return (m_dimensions.find( dimension ) != m_dimensions.end()); + } + + + const Dimension& UnitSystem::getDimension(const std::string& dimension) const { + if (hasDimension( dimension )) + return m_dimensions.at( dimension ); + else + throw std::invalid_argument("Dimension: " + dimension + " not recognized "); + } + + + void UnitSystem::addDimension(const std::string& dimension , double SI_factor) { + if (hasDimension(dimension)) + m_dimensions.erase( dimension ); + + m_dimensions.insert( std::make_pair(dimension , Dimension(dimension , SI_factor))); + } + + + const std::string& UnitSystem::getName() const { + return m_name; + } + + + Dimension UnitSystem::parseFactor(const std::string& dimension) const { + std::vector dimensionList; + boost::split(dimensionList , dimension , boost::is_any_of("*")); + double SIfactor = 1.0; + for (auto iter = dimensionList.begin(); iter != dimensionList.end(); ++iter) { + Dimension dim = getDimension( *iter ); + SIfactor *= dim.getSIScaling(); + } + return Dimension::makeComposite( dimension , SIfactor ); + } + + + + Dimension UnitSystem::parse(const std::string& dimension) const { + bool haveDivisor; + { + size_t divCount = std::count( dimension.begin() , dimension.end() , '/' ); + if (divCount == 0) + haveDivisor = false; + else if (divCount == 1) + haveDivisor = true; + else + throw std::invalid_argument("Dimension string can only have one division sign /"); + } + + if (haveDivisor) { + std::vector parts; + boost::split(parts , dimension , boost::is_any_of("/")); + Dimension dividend = parseFactor( parts[0] ); + Dimension divisor = parseFactor( parts[1] ); + + return Dimension::makeComposite( dimension , dividend.getSIScaling() / divisor.getSIScaling() ); + } else { + return parseFactor( dimension ); + } + } + + + UnitSystem * UnitSystem::newMETRIC() { + UnitSystem * system = new UnitSystem("Metric"); + + system->addDimension("1" , 1.0); + system->addDimension("P" , Metric::Pressure ); + system->addDimension("L" , Metric::Length); + system->addDimension("t" , Metric::Time ); + system->addDimension("m" , Metric::Mass ); + system->addDimension("K" , Metric::Permeability ); + + return system; + } + + + + UnitSystem * UnitSystem::newFIELD() { + UnitSystem * system = new UnitSystem("Field"); + + system->addDimension("1" , 1.0); + system->addDimension("P" , Field::Pressure ); + system->addDimension("L" , Field::Length); + system->addDimension("t" , Field::Time); + system->addDimension("m" , Field::Mass); + system->addDimension("K" , Field::Permeability ); + + return system; + } + +} + + + diff --git a/opm/parser/eclipse/Units/UnitSystem.hpp b/opm/parser/eclipse/Units/UnitSystem.hpp new file mode 100644 index 000000000..76921036f --- /dev/null +++ b/opm/parser/eclipse/Units/UnitSystem.hpp @@ -0,0 +1,53 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#ifndef UNITSYSTEM_H +#define UNITSYSTEM_H + +#include +#include + +#include + +namespace Opm { + + class UnitSystem { + public: + UnitSystem(const std::string& unitSystem); + const std::string& getName() const; + + void addDimension(const std::string& dimension , double SI_factor); + const Dimension& getDimension(const std::string& dimension) const; + bool hasDimension(const std::string& dimension) const; + + Dimension parse(const std::string& dimension) const; + + static UnitSystem * newMETRIC(); + static UnitSystem * newFIELD(); + private: + Dimension parseFactor(const std::string& dimension) const; + + const std::string m_name; + std::map m_dimensions; + }; +} + + +#endif + diff --git a/opm/parser/eclipse/Units/UnitSystemMap.cpp b/opm/parser/eclipse/Units/UnitSystemMap.cpp new file mode 100644 index 000000000..6d67ff46d --- /dev/null +++ b/opm/parser/eclipse/Units/UnitSystemMap.cpp @@ -0,0 +1,66 @@ +/* + Copyright 2013 Statoil 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 + +#include +#include +#include +#include +#include + +namespace Opm { + + UnitSystemMap::UnitSystemMap() { + + } + + std::string UnitSystemMap::makeRegularName(const std::string& name) { + std::string regularName; + for (auto iter = name.begin(); iter != name.end(); ++iter) + regularName.push_back( std::tolower( *iter )); + + return regularName; + } + + + bool UnitSystemMap::hasSystem(const std::string& name) const { + std::string regularName = makeRegularName(name); + return (m_systemMap.find(regularName) != m_systemMap.end()); + } + + + void UnitSystemMap::addSystem(std::shared_ptr system) { + std::string regularName = makeRegularName(system->getName()); + if (m_systemMap.find(regularName) != m_systemMap.end()) + m_systemMap.erase( regularName ); + + m_systemMap.insert( std::make_pair( regularName , system)); + } + + + std::shared_ptr UnitSystemMap::getSystem( const std::string& name) const { + std::string regularName = makeRegularName(name); + if (m_systemMap.find(regularName) != m_systemMap.end()) + return m_systemMap.at( regularName ); + else + throw std::invalid_argument( "Does not have a unit system: " + name); + } + +} diff --git a/opm/parser/eclipse/Units/UnitSystemMap.hpp b/opm/parser/eclipse/Units/UnitSystemMap.hpp new file mode 100644 index 000000000..cdd157036 --- /dev/null +++ b/opm/parser/eclipse/Units/UnitSystemMap.hpp @@ -0,0 +1,48 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#ifndef UNITSYSTEMMAP_H +#define UNITSYSTEMMAP_H + +#include + +#include +#include +#include + +namespace Opm { + + class UnitSystemMap { + public: + UnitSystemMap(); + bool hasSystem(const std::string& name) const; + std::shared_ptr getSystem( const std::string& name) const; + void addSystem(std::shared_ptr system); + + private: + static std::string makeRegularName(const std::string& name); + + std::map > m_systemMap; + }; + + +} + + +#endif diff --git a/opm/parser/eclipse/Units/tests/CMakeLists.txt b/opm/parser/eclipse/Units/tests/CMakeLists.txt new file mode 100644 index 000000000..87c1e1702 --- /dev/null +++ b/opm/parser/eclipse/Units/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(runUnitTests UnitTests.cpp) +target_link_libraries(runUnitTests Parser ${Boost_LIBRARIES}) +add_test(NAME runUnitTests COMMAND ${EXECUTABLE_OUTPUT_PATH}/runUnitTests ) diff --git a/opm/parser/eclipse/Units/tests/UnitTests.cpp b/opm/parser/eclipse/Units/tests/UnitTests.cpp new file mode 100644 index 000000000..6094ab349 --- /dev/null +++ b/opm/parser/eclipse/Units/tests/UnitTests.cpp @@ -0,0 +1,157 @@ +/* + Copyright 2013 Statoil 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 . +*/ + +#define BOOST_TEST_MODULE UnitTests +#include + +#include +#include +#include +#include + + + +using namespace Opm; + +BOOST_AUTO_TEST_CASE(CreateDimension) { + Dimension length("L" , 1); + BOOST_CHECK_EQUAL("L" , length.getName()); + BOOST_CHECK_EQUAL(1 , length.getSIScaling()); +} + +BOOST_AUTO_TEST_CASE(makeComposite) { + Dimension composite = Dimension::makeComposite("L*L*L/t" , 100); + BOOST_CHECK_EQUAL("L*L*L/t" , composite.getName()); + BOOST_CHECK_EQUAL(100 , composite.getSIScaling()); +} + + +BOOST_AUTO_TEST_CASE(CreateDimensionInvalidNameThrows) { + BOOST_CHECK_THROW(Dimension(" " , 1) , std::invalid_argument); + BOOST_CHECK_THROW(Dimension(".LX" , 1) , std::invalid_argument); + BOOST_CHECK_THROW(Dimension("*" , 1) , std::invalid_argument); + BOOST_CHECK_THROW(Dimension("/" , 1) , std::invalid_argument); + BOOST_CHECK_THROW(Dimension("2" , 1) , std::invalid_argument); + BOOST_CHECK_NO_THROW(Dimension("1" , 1)); +} + + +BOOST_AUTO_TEST_CASE(CreateUnitSystem) { + UnitSystem system("Metric"); + BOOST_CHECK_EQUAL("Metric" , system.getName()); +} + + +BOOST_AUTO_TEST_CASE(UnitSystemEmptyHasNone) { + UnitSystem system("Metric"); + BOOST_CHECK_EQUAL( false , system.hasDimension("L")); + BOOST_CHECK_EQUAL( false , system.hasDimension("LXY")); +} + + + +BOOST_AUTO_TEST_CASE(UnitSystemGetMissingDimensionThrows) { + UnitSystem system("Metric"); + BOOST_CHECK_THROW( system.getDimension("L") , std::invalid_argument ); +} + + +BOOST_AUTO_TEST_CASE(UnitSystemAddDimensions) { + UnitSystem system("Metric"); + system.addDimension("L" , 1 ); + system.addDimension("t" , 86400 ); + + Dimension length = system.getDimension("L"); + Dimension time = system.getDimension("t"); + BOOST_CHECK_EQUAL(1 , length.getSIScaling()); + BOOST_CHECK_EQUAL(86400 , time.getSIScaling()); + + system.addDimension("L" , 0.3048); + length = system.getDimension("L"); + BOOST_CHECK_EQUAL(0.3048 , length.getSIScaling()); +} + + +BOOST_AUTO_TEST_CASE(UnitSystemParseInvalidThrows) { + UnitSystem system("Metric"); + BOOST_CHECK_THROW( system.parse("//") , std::invalid_argument); + BOOST_CHECK_THROW( system.parse("L * L / t") , std::invalid_argument); + + system.addDimension("L" , 3.00 ); + system.addDimension("t" , 9.0 ); + + Dimension volumePerTime = system.parse("L*L*L/t"); + BOOST_CHECK_EQUAL("L*L*L/t" , volumePerTime.getName() ); + BOOST_CHECK_EQUAL(3.0 , volumePerTime.getSIScaling()); +} + + + +void checkSystemHasRequiredDimensions(std::shared_ptr system) { + BOOST_CHECK( system->hasDimension("1")); + BOOST_CHECK( system->hasDimension("L")); + BOOST_CHECK( system->hasDimension("m")); + BOOST_CHECK( system->hasDimension("t")); + BOOST_CHECK( system->hasDimension("K")); + BOOST_CHECK( system->hasDimension("P")); +} + + + +BOOST_AUTO_TEST_CASE(CreateMetricSystem) { + std::shared_ptr system = std::shared_ptr( UnitSystem::newMETRIC() ); + checkSystemHasRequiredDimensions( system ); + + BOOST_CHECK_EQUAL( Metric::Length , system->getDimension("L").getSIScaling() ); + BOOST_CHECK_EQUAL( Metric::Mass , system->getDimension("m").getSIScaling() ); + BOOST_CHECK_EQUAL( Metric::Time , system->getDimension("t").getSIScaling() ); + BOOST_CHECK_EQUAL( Metric::Permeability , system->getDimension("K").getSIScaling() ); + BOOST_CHECK_EQUAL( Metric::Pressure , system->getDimension("P").getSIScaling() ); +} + + + +BOOST_AUTO_TEST_CASE(CreateFieldSystem) { + std::shared_ptr system = std::shared_ptr( UnitSystem::newFIELD() ); + checkSystemHasRequiredDimensions( system ); + + BOOST_CHECK_EQUAL( Field::Length , system->getDimension("L").getSIScaling() ); + BOOST_CHECK_EQUAL( Field::Mass , system->getDimension("m").getSIScaling() ); + BOOST_CHECK_EQUAL( Field::Time , system->getDimension("t").getSIScaling() ); + BOOST_CHECK_EQUAL( Field::Permeability , system->getDimension("K").getSIScaling() ); + BOOST_CHECK_EQUAL( Field::Pressure , system->getDimension("P").getSIScaling() ); +} + + + +BOOST_AUTO_TEST_CASE(CreateUnitMap) { + UnitSystemMap systemMap; + systemMap.addSystem( std::shared_ptr( UnitSystem::newMETRIC() )); + systemMap.addSystem( std::shared_ptr( UnitSystem::newFIELD() )); + + BOOST_CHECK( systemMap.hasSystem("METRIC")); + BOOST_CHECK( systemMap.hasSystem("meTRIC")); + BOOST_CHECK( systemMap.hasSystem("meTRic")); + BOOST_CHECK( systemMap.hasSystem("Field")); + + BOOST_CHECK_EQUAL( false , systemMap.hasSystem("NoNotThisOne")); + BOOST_CHECK_THROW( systemMap.getSystem( "NoNotThisOne") , std::invalid_argument); +} + +