From bec10dbfbe7c9e691c6a3f60932248b3a6756412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Thu, 29 Jun 2023 12:35:36 +0200 Subject: [PATCH] Implement GECON keyword Implements support for the GECON keyword. --- CMakeLists_files.cmake | 2 + .../Group/GroupEconProductionLimits.hpp | 131 +++++++ opm/input/eclipse/Schedule/Schedule.hpp | 2 + opm/input/eclipse/Schedule/ScheduleState.hpp | 6 + .../Group/GroupEconProductionLimits.cpp | 322 ++++++++++++++++++ .../eclipse/Schedule/KeywordHandlers.cpp | 21 ++ src/opm/input/eclipse/Schedule/Schedule.cpp | 2 + .../input/eclipse/Schedule/ScheduleState.cpp | 2 + .../share/keywords/000_Eclipse100/G/GECON | 6 +- tests/parser/GroupTests.cpp | 71 +++- tests/parser/ScheduleSerializeTest.cpp | 21 ++ tests/test_Serialization.cpp | 2 + 12 files changed, 573 insertions(+), 15 deletions(-) create mode 100644 opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp create mode 100644 src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 258ee71a9..d54a261d4 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -174,6 +174,7 @@ if(ENABLE_ECL_INPUT) src/opm/input/eclipse/Schedule/Group/GuideRateModel.cpp src/opm/input/eclipse/Schedule/Group/GConSale.cpp src/opm/input/eclipse/Schedule/Group/GConSump.cpp + src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp src/opm/input/eclipse/Schedule/Group/GTNode.cpp src/opm/input/eclipse/Schedule/KeywordHandlers.cpp src/opm/input/eclipse/Schedule/MessageLimits.cpp @@ -1274,6 +1275,7 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/Group/GuideRate.hpp opm/input/eclipse/Schedule/Group/GConSale.hpp opm/input/eclipse/Schedule/Group/GConSump.hpp + opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp opm/input/eclipse/Schedule/Group/GuideRateConfig.hpp opm/input/eclipse/Schedule/Group/GuideRateModel.hpp opm/input/eclipse/Schedule/MessageLimits.hpp diff --git a/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp b/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp new file mode 100644 index 000000000..6d58ab7dc --- /dev/null +++ b/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.hpp @@ -0,0 +1,131 @@ +/* + Copyright 2023 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 GROUP_ECON_PRODUCTION_LIMITS_H +#define GROUP_ECON_PRODUCTION_LIMITS_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Opm { + +class DeckRecord; + +class GroupEconProductionLimits { +public: + enum class EconWorkover { + NONE = 0, + CON = 1, // CON + CONP = 2, // +CON + WELL = 3, + PLUG = 4, + ALL = 5 + }; + + class GEconGroup { + public: + GEconGroup() = default; + GEconGroup(const DeckRecord &record, const int report_step); + bool endRun() const; + UDAValue minOilRate() const; + UDAValue minGasRate() const; + UDAValue maxWaterCut() const; + UDAValue maxGasOilRatio() const; + UDAValue maxWaterGasRatio() const; + int maxOpenWells() const; + bool operator==(const GEconGroup& other) const; + int reportStep() const; + template void serializeOp(Serializer& serializer); + static GEconGroup serializationTestObject(); + EconWorkover workover() const; + + private: + UDAValue m_min_oil_rate; + UDAValue m_min_gas_rate; + UDAValue m_max_water_cut; + UDAValue m_max_gas_oil_ratio; + UDAValue m_max_water_gas_ratio; + EconWorkover m_workover; + bool m_end_run; + int m_max_open_wells; + int m_report_step; // Used to get UDQ undefined value + }; + + class GEconGroupProp { + /* Same as GEconGroup but with UDA values realized at given report step*/ + public: + GEconGroupProp(const double min_oil_rate, + const double min_gas_rate, + const double max_water_cut, + const double max_gas_oil_ratio, + const double max_water_gas_ratio, + EconWorkover workover, + bool end_run, + int max_open_wells); + bool endRun() const; + std::optional minOilRate() const; + std::optional minGasRate() const; + std::optional maxWaterCut() const; + std::optional maxGasOilRatio() const; + std::optional maxWaterGasRatio() const; + int maxOpenWells() const; + EconWorkover workover() const; + + private: + std::optional m_min_oil_rate; + std::optional m_min_gas_rate; + std::optional m_max_water_cut; + std::optional m_max_gas_oil_ratio; + std::optional m_max_water_gas_ratio; + EconWorkover m_workover; + bool m_end_run; + int m_max_open_wells; + }; + + GroupEconProductionLimits() = default; + //explicit GroupEconProductionLimits(const RestartIO::RstWell& rstWell); + + void add_group(const int report_step, const std::string &group_name, const DeckRecord &record); + static EconWorkover econWorkoverFromString(const std::string& string_value); + const GEconGroup& get_group(const std::string& gname) const; + GEconGroupProp get_group_prop( + const Schedule &schedule, const SummaryState &st, const std::string& gname) const; + bool has_group(const std::string& gname) const; + bool operator==(const GroupEconProductionLimits& other) const; + bool operator!=(const GroupEconProductionLimits& other) const; + template void serializeOp(Serializer& serializer) const; + static GroupEconProductionLimits serializationTestObject(); + size_t size() const; + +private: + std::map m_groups; +}; + +} // namespace Opm + + +#endif diff --git a/opm/input/eclipse/Schedule/Schedule.hpp b/opm/input/eclipse/Schedule/Schedule.hpp index 0a9ba4886..d0da80a24 100644 --- a/opm/input/eclipse/Schedule/Schedule.hpp +++ b/opm/input/eclipse/Schedule/Schedule.hpp @@ -350,6 +350,7 @@ namespace Opm this->template pack_unpack(serializer); this->template pack_unpack(serializer); this->template pack_unpack(serializer); + this->template pack_unpack(serializer); this->template pack_unpack(serializer); this->template pack_unpack(serializer); this->template pack_unpack(serializer); @@ -697,6 +698,7 @@ namespace Opm void handleGCONPROD (HandlerContext&); void handleGCONSALE (HandlerContext&); void handleGCONSUMP (HandlerContext&); + void handleGECON (HandlerContext&); void handleGEFAC (HandlerContext&); void handleGEOKeyword(HandlerContext&); void handleGLIFTOPT (HandlerContext&); diff --git a/opm/input/eclipse/Schedule/ScheduleState.hpp b/opm/input/eclipse/Schedule/ScheduleState.hpp index 6c105b92b..4457b09a8 100644 --- a/opm/input/eclipse/Schedule/ScheduleState.hpp +++ b/opm/input/eclipse/Schedule/ScheduleState.hpp @@ -64,6 +64,7 @@ namespace Opm { class GasLiftOpt; class GConSale; class GConSump; + class GroupEconProductionLimits; class GroupOrder; class GuideRateConfig; class NameOrder; @@ -359,6 +360,7 @@ namespace Opm { ptr_member gconsale; ptr_member gconsump; + ptr_member gecon; ptr_member guide_rate; ptr_member wlist_manager; @@ -391,6 +393,8 @@ namespace Opm { return this->gconsale; else if constexpr ( std::is_same_v ) return this->gconsump; + else if constexpr ( std::is_same_v ) + return this->gecon; else if constexpr ( std::is_same_v ) return this->wlist_manager; else if constexpr ( std::is_same_v ) @@ -431,6 +435,8 @@ namespace Opm { return this->gconsale; else if constexpr ( std::is_same_v ) return this->gconsump; + else if constexpr ( std::is_same_v ) + return this->gecon; else if constexpr ( std::is_same_v ) return this->wlist_manager; else if constexpr ( std::is_same_v ) diff --git a/src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp b/src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp new file mode 100644 index 000000000..d8bc83f12 --- /dev/null +++ b/src/opm/input/eclipse/Schedule/Group/GroupEconProductionLimits.cpp @@ -0,0 +1,322 @@ +/* + Copyright 2023 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 +#include +#include +#include "../eval_uda.hpp" + +namespace { + template + std::optional get_positive_value(T value) + { + std::optional result; + if (value > 0.0) { + result = value; + } + return result; + } +} + +namespace Opm { + +void GroupEconProductionLimits::add_group( + const int report_step, const std::string &group_name, const DeckRecord& record) +{ + // NOTE: report_step is needed when retrieving UDA values later. + // To get the correct UDQ config for the UDQ-undefined value + auto group = GEconGroup {record, report_step}; + this->m_groups.insert_or_assign(group_name, group); +} + +bool GroupEconProductionLimits::has_group(const std::string& gname) const { + const auto iter = this->m_groups.find(gname); + return (iter != this->m_groups.end()); +} + +const GroupEconProductionLimits::GEconGroup& GroupEconProductionLimits::get_group( + const std::string& name) const +{ + auto it = this->m_groups.find(name); + if (it == this->m_groups.end()) + throw std::invalid_argument("GroupEconProdctionLimits object does not contain group '" + name + "'."); + else + return it->second; +} + +GroupEconProductionLimits::GEconGroupProp GroupEconProductionLimits::get_group_prop( + const Schedule &schedule, const SummaryState &st, const std::string& name) const +{ + const GEconGroup& group0 = this->get_group(name); + auto udq_undefined = schedule.getUDQConfig(group0.reportStep()).params().undefinedValue(); + auto min_oil_rate = UDA::eval_group_uda(group0.minOilRate(), name, st, udq_undefined); + auto min_gas_rate = UDA::eval_group_uda(group0.minGasRate(), name, st, udq_undefined); + auto max_water_cut = UDA::eval_group_uda(group0.maxWaterCut(), name, st, udq_undefined); + auto max_gas_oil_ratio = UDA::eval_group_uda(group0.maxGasOilRatio(), name, st, udq_undefined); + auto max_water_gas_ratio = UDA::eval_group_uda(group0.maxWaterGasRatio(), name, st, udq_undefined); + + return GEconGroupProp { + min_oil_rate, + min_gas_rate, + max_water_cut, + max_gas_oil_ratio, + max_water_gas_ratio, + group0.workover(), + group0.endRun(), + group0.maxOpenWells() + }; +} + +bool GroupEconProductionLimits::operator==(const GroupEconProductionLimits& other) const +{ + return this->m_groups == other.m_groups; +} + +bool GroupEconProductionLimits::operator!=(const GroupEconProductionLimits& other) const +{ + return !(*this == other); +} + + +template +void GroupEconProductionLimits::serializeOp(Serializer& serializer) const +{ + serializer(m_groups); +} + +// TODO: The template function serializeOp() needs to be specialized here or else +// the linker will not be able to link test_Serialization. The error I got was +// +// CMakeFiles/test_Serialization.dir/tests/test_Serialization.cpp.o: +// in function `void Opm::Serializer +// ::operator()(Opm::GroupEconProductionLimits const&)': +// /home/hakon/test/opm/opm-common/opm/common/utility/Serializer.hpp:113: +// undefined reference to `void Opm::GroupEconProductionLimits::serializeOp< +// Opm::Serializer >(Opm::Serializer&)' +// collect2: error: ld returned 1 exit status +// +template<> void GroupEconProductionLimits::serializeOp( + Opm::Serializer& serializer) const +{ + serializer(m_groups); +} + + +GroupEconProductionLimits GroupEconProductionLimits::serializationTestObject() +{ + GroupEconProductionLimits gecon; + gecon.m_groups["P1"] = {GEconGroup::serializationTestObject()}; + return gecon; +} + +size_t GroupEconProductionLimits::size() const { + return this->m_groups.size(); +} + +/* Methods for inner class GEconGroup */ + +GroupEconProductionLimits::GEconGroup::GEconGroup(const DeckRecord &record, const int report_step) + : m_min_oil_rate{record.getItem("MIN_OIL_RATE").get(0)} + , m_min_gas_rate{record.getItem("MIN_GAS_RATE").get(0)} + , m_max_water_cut{record.getItem("MAX_WCT").get(0)} + , m_max_gas_oil_ratio{record.getItem("MAX_GOR").get(0)} + , m_max_water_gas_ratio{record.getItem("MAX_WATER_GAS_RATIO").get(0)} + , m_workover{econWorkoverFromString(record.getItem("WORKOVER").getTrimmedString(0))} + , m_end_run{false} + , m_max_open_wells{record.getItem("MAX_OPEN_WELLS").get(0)} + , m_report_step{report_step} +{ + if (record.getItem("END_RUN").hasValue(0)) { + std::string string_endrun = record.getItem("END_RUN").getTrimmedString(0); + if (string_endrun == "YES") { + m_end_run = true; + } else if (string_endrun != "NO") { + throw std::invalid_argument("Unknown input: " + string_endrun + " for END_RUN in GECON"); + } + } +} + +GroupEconProductionLimits::EconWorkover +GroupEconProductionLimits::econWorkoverFromString(const std::string& string_value) +{ + if (string_value == "NONE") + return EconWorkover::NONE; + else if (string_value == "CON") + return EconWorkover::CON; + else if (string_value == "+CON") + return EconWorkover::CONP; + else if (string_value == "WELL") + return EconWorkover::WELL; + else if (string_value == "PLUG") + return EconWorkover::PLUG; + else if (string_value == "ALL") + return EconWorkover::ALL; + else + throw std::invalid_argument("GroupEconProductionLimits: Unknown enum string value '" + + string_value + "' for EconWorkover enum"); +} + +bool GroupEconProductionLimits::GEconGroup::endRun() const { + return m_end_run; +} + +UDAValue GroupEconProductionLimits::GEconGroup::maxGasOilRatio() const +{ + return m_max_gas_oil_ratio; +} + +UDAValue GroupEconProductionLimits::GEconGroup::maxWaterCut() const +{ + return m_max_water_cut; +} + +UDAValue GroupEconProductionLimits::GEconGroup::maxWaterGasRatio() const +{ + return m_max_water_gas_ratio; +} + +int GroupEconProductionLimits::GEconGroup::maxOpenWells() const +{ + return m_max_open_wells; +} + +UDAValue GroupEconProductionLimits::GEconGroup::minGasRate() const +{ + return m_min_gas_rate; +} + +UDAValue GroupEconProductionLimits::GEconGroup::minOilRate() const +{ + return m_min_oil_rate; +} + +bool GroupEconProductionLimits::GEconGroup::operator==(const GEconGroup& other) const +{ + return this->m_min_oil_rate == other.m_min_oil_rate && + this->m_min_gas_rate == other.m_min_gas_rate && + this->m_max_water_cut == other.m_max_water_cut && + this->m_max_gas_oil_ratio == other.m_max_gas_oil_ratio && + this->m_max_water_gas_ratio == other.m_max_water_gas_ratio && + this->m_workover == other.m_workover && + this->m_end_run == other.m_end_run && + this->m_max_open_wells == other.m_max_open_wells; +} + +int GroupEconProductionLimits::GEconGroup::reportStep() const { + return m_report_step; +} + +template +void GroupEconProductionLimits::GEconGroup::serializeOp(Serializer& serializer) +{ + serializer(m_min_oil_rate); + serializer(m_min_gas_rate); + serializer(m_max_water_cut); + serializer(m_max_gas_oil_ratio); + serializer(m_max_water_gas_ratio); + serializer(m_workover); + serializer(m_end_run); + serializer(m_max_open_wells); +} + +GroupEconProductionLimits::GEconGroup GroupEconProductionLimits::GEconGroup::serializationTestObject() +{ + GEconGroup group; + group.m_min_oil_rate = UDAValue{1.0}; + group.m_min_gas_rate = UDAValue{2.0}; + group.m_max_water_cut = UDAValue{3.0}; + group.m_max_gas_oil_ratio = UDAValue{4.0}; + group.m_max_water_gas_ratio = UDAValue{5.0}; + group.m_workover = EconWorkover::CON; + group.m_end_run = false; + group.m_max_open_wells = 6; + return group; +} + +GroupEconProductionLimits::EconWorkover GroupEconProductionLimits::GEconGroup::workover() const { + return m_workover; +} + + +/* Methods for inner class GEconGroupProp */ + +GroupEconProductionLimits::GEconGroupProp::GEconGroupProp( + const double min_oil_rate, + const double min_gas_rate, + const double max_water_cut, + const double max_gas_oil_ratio, + const double max_water_gas_ratio, + EconWorkover workover, + bool end_run, + int max_open_wells) + : m_min_oil_rate{get_positive_value(min_oil_rate)} + , m_min_gas_rate{get_positive_value(min_gas_rate)} + , m_max_water_cut{get_positive_value(max_water_cut)} + , m_max_gas_oil_ratio{get_positive_value(max_gas_oil_ratio)} + , m_max_water_gas_ratio{get_positive_value(max_water_gas_ratio)} + , m_workover{workover} + , m_end_run{end_run} + , m_max_open_wells{max_open_wells} +{ + +} + +bool GroupEconProductionLimits::GEconGroupProp::endRun() const { + return m_end_run; +} + +std::optional GroupEconProductionLimits::GEconGroupProp::minOilRate() const +{ + return m_min_oil_rate; +} + +std::optional GroupEconProductionLimits::GEconGroupProp::minGasRate() const +{ + return m_min_gas_rate; +} + +std::optional GroupEconProductionLimits::GEconGroupProp::maxWaterCut() const +{ + return m_max_water_cut; +} + +std::optional GroupEconProductionLimits::GEconGroupProp::maxGasOilRatio() const +{ + return m_max_gas_oil_ratio; +} + +int GroupEconProductionLimits::GEconGroupProp::maxOpenWells() const +{ + return m_max_open_wells; +} + +std::optional GroupEconProductionLimits::GEconGroupProp::maxWaterGasRatio() const +{ + return m_max_water_gas_ratio; +} + +GroupEconProductionLimits::EconWorkover GroupEconProductionLimits::GEconGroupProp::workover() const { + return m_workover; +} + + +} // namespace Opm + diff --git a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp index 189be4be8..d0f3c646d 100644 --- a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp +++ b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -690,6 +691,25 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno) this->snapshots.back().gconsump.update( std::move(new_gconsump) ); } + void + Schedule::handleGECON(HandlerContext& handlerContext) + { + auto gecon = this->snapshots.back().gecon(); + const auto& keyword = handlerContext.keyword; + auto report_step = handlerContext.currentStep; + for (const auto& record : keyword) { + const std::string& groupNamePattern + = record.getItem().getTrimmedString(0); + const auto group_names = this->groupNames(groupNamePattern); + if (group_names.empty()) + this->invalidNamePattern(groupNamePattern, handlerContext); + for (const auto& gname : group_names) { + gecon.add_group(report_step, gname, record); + } + } + this->snapshots.back().gecon.update(std::move(gecon)); + } + void Schedule::handleGEFAC(HandlerContext& handlerContext) { for (const auto& record : handlerContext.keyword) { const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0); @@ -2566,6 +2586,7 @@ Well{0} entered with 'FIELD' parent group: { "GCONPROD", &Schedule::handleGCONPROD }, { "GCONSALE", &Schedule::handleGCONSALE }, { "GCONSUMP", &Schedule::handleGCONSUMP }, + { "GECON", &Schedule::handleGECON }, { "GEFAC" , &Schedule::handleGEFAC }, { "GLIFTOPT", &Schedule::handleGLIFTOPT }, { "GPMAINT" , &Schedule::handleGPMAINT }, diff --git a/src/opm/input/eclipse/Schedule/Schedule.cpp b/src/opm/input/eclipse/Schedule/Schedule.cpp index 98fcd7048..bb1d1dc30 100644 --- a/src/opm/input/eclipse/Schedule/Schedule.cpp +++ b/src/opm/input/eclipse/Schedule/Schedule.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -2293,6 +2294,7 @@ void Schedule::create_first(const time_point& start_time, const std::optional #include #include +#include #include #include #include @@ -318,6 +319,7 @@ ScheduleState ScheduleState::serializationTestObject() { ts.wtest_config.update( WellTestConfig::serializationTestObject() ); ts.gconsump.update( GConSump::serializationTestObject() ); ts.gconsale.update( GConSale::serializationTestObject() ); + ts.gecon.update( GroupEconProductionLimits::serializationTestObject() ); ts.wlist_manager.update( WListManager::serializationTestObject() ); ts.rpt_config.update( RPTConfig::serializationTestObject() ); ts.actions.update( Action::Actions::serializationTestObject() ); diff --git a/src/opm/input/eclipse/share/keywords/000_Eclipse100/G/GECON b/src/opm/input/eclipse/share/keywords/000_Eclipse100/G/GECON index d1308d5a1..b0a375b49 100644 --- a/src/opm/input/eclipse/share/keywords/000_Eclipse100/G/GECON +++ b/src/opm/input/eclipse/share/keywords/000_Eclipse100/G/GECON @@ -11,12 +11,14 @@ { "name": "MIN_OIL_RATE", "value_type": "UDA", - "default": 0 + "default": 0, + "dimension": "LiquidSurfaceVolume/Time" }, { "name": "MIN_GAS_RATE", "value_type": "UDA", - "default": 0 + "default": 0, + "dimension": "GasSurfaceVolume/Time" }, { "name": "MAX_WCT", diff --git a/tests/parser/GroupTests.cpp b/tests/parser/GroupTests.cpp index 8352243cf..aa59b8036 100644 --- a/tests/parser/GroupTests.cpp +++ b/tests/parser/GroupTests.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,11 @@ GRUPTREE 'G2' 'FIELD' / / +GECON + 'G1' 1* 200000.0 / + 'G2' 100000.0 1* 0.5 3* 'YES' / +/ + GCONSALE 'G1' 50000 55000 45000 WELL / / @@ -327,20 +333,59 @@ GCONSUMP auto schedule = create_schedule(input); double metric_to_si = 1.0 / (24.0 * 3600.0); //cubic meters / day + SummaryState st(TimeService::now()); - const auto& gconsale = schedule[0].gconsale.get(); - BOOST_CHECK_EQUAL(gconsale.size(), 1U); - BOOST_CHECK(gconsale.has("G1")); - BOOST_CHECK(!gconsale.has("G2")); - const GConSale::GCONSALEGroup& group = gconsale.get("G1"); - BOOST_CHECK_EQUAL(group.sales_target.get(), 50000); - BOOST_CHECK_EQUAL(group.max_sales_rate.get(), 55000); - BOOST_CHECK_EQUAL(group.min_sales_rate.get(), 45000); - BOOST_CHECK_EQUAL(group.sales_target.getSI(), 50000 * metric_to_si); - BOOST_CHECK_EQUAL(group.max_sales_rate.getSI(), 55000 * metric_to_si); - BOOST_CHECK_EQUAL(group.min_sales_rate.getSI(), 45000 * metric_to_si); - BOOST_CHECK(group.max_proc == GConSale::MaxProcedure::WELL); - + { + const auto& gconsale = schedule[0].gconsale.get(); + BOOST_CHECK_EQUAL(gconsale.size(), 1U); + BOOST_CHECK(gconsale.has("G1")); + BOOST_CHECK(!gconsale.has("G2")); + const GConSale::GCONSALEGroup& group = gconsale.get("G1"); + BOOST_CHECK_EQUAL(group.sales_target.get(), 50000); + BOOST_CHECK_EQUAL(group.max_sales_rate.get(), 55000); + BOOST_CHECK_EQUAL(group.min_sales_rate.get(), 45000); + BOOST_CHECK_EQUAL(group.sales_target.getSI(), 50000 * metric_to_si); + BOOST_CHECK_EQUAL(group.max_sales_rate.getSI(), 55000 * metric_to_si); + BOOST_CHECK_EQUAL(group.min_sales_rate.getSI(), 45000 * metric_to_si); + BOOST_CHECK(group.max_proc == GConSale::MaxProcedure::WELL); + } + { + const auto& gecon = schedule[0].gecon.get(); + BOOST_CHECK_EQUAL(gecon.size(), 2U); + BOOST_CHECK(gecon.has_group("G1")); + BOOST_CHECK(gecon.has_group("G2")); + { + const GroupEconProductionLimits::GEconGroupProp group = gecon.get_group_prop(schedule, st, "G1"); + BOOST_CHECK(group.minOilRate().has_value() == false); + BOOST_CHECK(group.minGasRate().has_value() == true); + if (group.minGasRate()) { + BOOST_CHECK_EQUAL(group.minGasRate().value(), 200000.0 * metric_to_si); + } + BOOST_CHECK(group.maxWaterCut().has_value() == false); + BOOST_CHECK(group.maxGasOilRatio().has_value() == false); + BOOST_CHECK(group.maxWaterGasRatio().has_value() == false); + BOOST_CHECK(group.workover() == GroupEconProductionLimits::EconWorkover::NONE); + BOOST_CHECK(group.endRun() == false); + BOOST_CHECK_EQUAL(group.maxOpenWells(), 0); + } + { + const GroupEconProductionLimits::GEconGroupProp group = gecon.get_group_prop(schedule, st, "G2"); + BOOST_CHECK(group.minOilRate().has_value() == true); + if (group.minOilRate()) { + BOOST_CHECK_EQUAL(group.minOilRate().value(), 100000.0 * metric_to_si); + } + BOOST_CHECK(group.minGasRate().has_value() == false); + BOOST_CHECK(group.maxWaterCut().has_value() == true); + if (group.maxWaterCut()) { + BOOST_CHECK_EQUAL(group.maxWaterCut().value(), 0.5); + } + BOOST_CHECK(group.maxGasOilRatio().has_value() == false); + BOOST_CHECK(group.maxWaterGasRatio().has_value() == false); + BOOST_CHECK(group.workover() == GroupEconProductionLimits::EconWorkover::NONE); + BOOST_CHECK(group.endRun() == true); + BOOST_CHECK_EQUAL(group.maxOpenWells(), 0); + } + } const auto& gconsump = schedule[0].gconsump.get(); BOOST_CHECK_EQUAL(gconsump.size(), 2U); BOOST_CHECK(gconsump.has("G1")); diff --git a/tests/parser/ScheduleSerializeTest.cpp b/tests/parser/ScheduleSerializeTest.cpp index ce6e88a83..bbf6bb7d5 100644 --- a/tests/parser/ScheduleSerializeTest.cpp +++ b/tests/parser/ScheduleSerializeTest.cpp @@ -53,6 +53,7 @@ #include #include +#include #include #include @@ -227,6 +228,11 @@ GCONSALE 'G1' 50000 55000 45000 WELL / / +GECON + 'G1' 1* 200000.0 / + 'G2' 1* 200000.0 / +/ + GCONSUMP 'G1' 20 50 'a_node' / 'G2' 30 60 / @@ -385,6 +391,21 @@ BOOST_AUTO_TEST_CASE(SerializeWList) { BOOST_CHECK( wlm2 == sched0[5].wlist_manager()); } +BOOST_AUTO_TEST_CASE(SerializeGECON) { + auto sched = make_schedule(GCONSALE_deck); + auto sched0 = make_schedule(deck0); + auto gecon1 = sched[0].gecon.get(); + + { + std::vector value_list; + std::vector index_list; + sched.pack_state( value_list, index_list ); + BOOST_CHECK_EQUAL( value_list.size(), 1 ); + sched0.unpack_state( value_list, index_list ); + } + BOOST_CHECK( gecon1 == sched0[0].gecon()); + BOOST_CHECK( gecon1 == sched0[1].gecon()); +} BOOST_AUTO_TEST_CASE(SerializeGCONSALE) { diff --git a/tests/test_Serialization.cpp b/tests/test_Serialization.cpp index d98b6484a..50b4a779f 100644 --- a/tests/test_Serialization.cpp +++ b/tests/test_Serialization.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -239,6 +240,7 @@ TEST_FOR_TYPE(FoamConfig) TEST_FOR_TYPE(FoamData) TEST_FOR_TYPE(GConSale) TEST_FOR_TYPE(GConSump) +TEST_FOR_TYPE(GroupEconProductionLimits) TEST_FOR_TYPE(GridDims) TEST_FOR_TYPE(Group) TEST_FOR_TYPE_NAMED(Group::GroupInjectionProperties, GroupInjectionProperties)