diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 900eb8dbb..0caffb40b 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -97,6 +97,7 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateModel.cpp + src/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/GTNode.cpp src/opm/parser/eclipse/EclipseState/Schedule/Well/injection.cpp src/opm/parser/eclipse/EclipseState/Schedule/MessageLimits.cpp diff --git a/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp b/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp new file mode 100644 index 000000000..d2bd73f2c --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp @@ -0,0 +1,57 @@ +/* + Copyright 2019 Equinor 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 GCONSALE_H +#define GCONSALE_H + +#include +#include + +namespace Opm { + + class GConSale { + public: + + enum class MaxProcedure { + NONE, CON, CON_P, WELL, PLUG, RATE, MAXR, END + }; + + struct GCONSALEGroup { + UDAValue sales_target; + UDAValue max_sales_rate; + UDAValue min_sales_rate; + MaxProcedure max_proc; + }; + + GConSale(); + + bool has(const std::string& name) const; + const GCONSALEGroup& getGroup(const std::string& name) const; + MaxProcedure stringToProcedure(const std::string& procedure); + void add_group(const std::string& name, const UDAValue& sales_target, const UDAValue& max_rate, const UDAValue& min_rate, const std::string& procedure); + size_t size() const; + + private: + std::map groups; + }; + +} + + +#endif diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 4a4f2434f..c17e9c873 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,7 @@ namespace Opm const UDQActive& udqActive(size_t timeStep) const; const WellTestConfig& wtestConfig(size_t timestep) const; + const GConSale& gConSale(size_t timestep) const; const WListManager& getWListManager(size_t timeStep) const; const UDQConfig& getUDQConfig(size_t timeStep) const; const Action::Actions& actions(std::size_t timeStep) const; @@ -234,6 +236,7 @@ namespace Opm DynamicState> udq_config; DynamicState> udq_active; DynamicState> guide_rate_config; + DynamicState> gconsale; DynamicState global_whistctl_mode; DynamicState> m_actions; RFTConfig rft_config; @@ -281,6 +284,7 @@ namespace Opm void handleGCONINJE( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); void handleGCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); + void handleGCONSALE( const DeckKeyword& keyword, size_t currentStep); void handleGUIDERAT( const DeckKeyword& keyword, size_t currentStep); void handleLINCOM( const DeckKeyword& keyword, size_t currentStep); void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.cpp new file mode 100644 index 000000000..918ed48c9 --- /dev/null +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.cpp @@ -0,0 +1,71 @@ +/* + Copyright 2019 Equinor 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 + +namespace Opm { + +GConSale::GConSale() { +} + +bool GConSale::has(const std::string& name) const { + return (groups.find(name) != groups.end()); +} + +const GConSale::GCONSALEGroup& GConSale::getGroup(const std::string& name) const { + + auto it = groups.find(name); + if (it == groups.end()) + throw std::invalid_argument("Current GConSale obj. does not contain '" + name + "'."); + else + return it->second; +} + +GConSale::MaxProcedure GConSale::stringToProcedure(const std::string& str_proc) { + + if (str_proc == "NONE") return MaxProcedure::NONE; + else if (str_proc == "CON" ) return MaxProcedure::CON; + else if (str_proc == "+CON") return MaxProcedure::CON_P; + else if (str_proc == "WELL") return MaxProcedure::WELL; + else if (str_proc == "PLUG") return MaxProcedure::PLUG; + else if (str_proc == "RATE") return MaxProcedure::RATE; + else if (str_proc == "MAXR") return MaxProcedure::MAXR; + else if (str_proc == "END" ) return MaxProcedure::END; + else + throw std::invalid_argument(str_proc + "invalid argument to GConSake::stringToProcedure"); + + return MaxProcedure::NONE; +} + +void GConSale::add_group(const std::string& name, const UDAValue& sales_target, const UDAValue& max_rate, const UDAValue& min_rate, const std::string& procedure) { + groups[name] = GCONSALEGroup(); + GConSale::GCONSALEGroup& group = groups[name]; + group.sales_target = sales_target; + group.max_sales_rate = max_rate; + group.min_sales_rate = min_rate; + group.max_proc = stringToProcedure(procedure); +} + +size_t GConSale::size() const { + return groups.size(); +} + +} diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 1152d9405..c73b1a142 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -119,6 +119,7 @@ namespace { m_messageLimits( this->m_timeMap ), m_runspec( runspec ), wtest_config(this->m_timeMap, std::make_shared() ), + gconsale(this->m_timeMap, std::make_shared() ), wlist_manager( this->m_timeMap, std::make_shared()), udq_config(this->m_timeMap, std::make_shared(deck)), udq_active(this->m_timeMap, std::make_shared()), @@ -337,6 +338,9 @@ namespace { else if (keyword.name() == "GEFAC") handleGEFAC(keyword, currentStep, parseContext, errors); + else if (keyword.name() == "GCONSALE") + handleGCONSALE(keyword, currentStep); + else if (keyword.name() == "GUIDERAT") handleGUIDERAT(keyword, currentStep); @@ -1594,6 +1598,24 @@ namespace { } } + void Schedule::handleGCONSALE( const DeckKeyword& keyword, size_t currentStep) { + const auto& current = *this->gconsale.get(currentStep); + std::shared_ptr new_gconsale(new GConSale(current)); + for( const auto& record : keyword ) { + const std::string& groupName = record.getItem("GROUP").getTrimmedString(0); + auto sales_target = record.getItem("SALES_TARGET").get(0); + auto max_rate = record.getItem("MAX_SALES_RATE").get(0); + auto min_rate = record.getItem("MIN_SALES_RATE").get(0); + std::cout << "SALES TARGET = " << sales_target.get() << std::endl; + std::string procedure = record.getItem("MAX_PROC").getTrimmedString(0); + + new_gconsale->add_group(groupName, sales_target, max_rate, min_rate, procedure); + + } + this->gconsale.update(currentStep, new_gconsale); + } + + void Schedule::handleGUIDERAT( const DeckKeyword& keyword, size_t currentStep) { const auto& record = keyword.getRecord(0); @@ -2567,6 +2589,11 @@ void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, c return *ptr; } + const GConSale& Schedule::gConSale(size_t timeStep) const { + const auto& ptr = this->gconsale.get(timeStep); + return *ptr; + } + const WListManager& Schedule::getWListManager(size_t timeStep) const { const auto& ptr = this->wlist_manager.get(timeStep); return *ptr; diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GCONSALE b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GCONSALE index b19054b95..c214e4251 100644 --- a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GCONSALE +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GCONSALE @@ -1,7 +1,7 @@ {"name" : "GCONSALE" , "sections" : ["SCHEDULE"], "items" : [ {"name" : "GROUP" , "value_type" : "STRING" }, {"name" : "SALES_TARGET" , "value_type" : "UDA", "dimension": "GasSurfaceVolume/Time"}, - {"name" : "MAX_SALES_RATE" , "value_type" : "UDA", "dimension": "GasSurfaceVolume/Time"}, + {"name" : "MAX_SALES_RATE" , "value_type" : "UDA", "dimension": "GasSurfaceVolume/Time", "default": 1e20}, {"name" : "MIN_SALES_RATE" , "value_type" : "UDA", "dimension": "GasSurfaceVolume/Time", "default" : -1e20}, {"name" : "MAX_PROC" , "value_type" : "STRING", "default" : "NONE"} ]} diff --git a/tests/parser/GroupTests.cpp b/tests/parser/GroupTests.cpp index a9f127780..ffba4ce9e 100644 --- a/tests/parser/GroupTests.cpp +++ b/tests/parser/GroupTests.cpp @@ -378,3 +378,42 @@ BOOST_AUTO_TEST_CASE(TESTGuideRate) { GuideRate gr(schedule); } + +BOOST_AUTO_TEST_CASE(TESTGCONSALE) { + Parser parser; + std::string input = R"( + START -- 0 + 31 AUG 1993 / + SCHEDULE + + GRUPTREE + 'G1' 'FIELD' / + 'G2' 'FIELD' / + / + + GCONSALE + 'G1' 50000 55000 45000 WELL / + / + )"; + + auto deck = parser.parseString(input); + EclipseGrid grid(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid); + Runspec runspec (deck ); + Schedule schedule(deck, grid, eclipseProperties, runspec); + + double metric_to_si = 1.0 / (24.0 * 3600.0); //cubic meters / day + + const auto& gconsale = schedule.gConSale(0); + BOOST_CHECK_EQUAL(gconsale.size(), 1); + BOOST_CHECK(gconsale.has("G1")); + BOOST_CHECK(!gconsale.has("G2")); + const GConSale::GCONSALEGroup& group = gconsale.getGroup("G1"); + BOOST_CHECK_EQUAL(group.sales_target.get(), 50000 * metric_to_si); + BOOST_CHECK_EQUAL(group.max_sales_rate.get(), 55000 * metric_to_si); + BOOST_CHECK_EQUAL(group.min_sales_rate.get(), 45000 * metric_to_si); + BOOST_CHECK(group.max_proc == GConSale::MaxProcedure::WELL); + + +}