diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 7ea03fdd3..e6455ecca 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -496,6 +496,7 @@ namespace Opm // Keyword Handlers void handlePYACTION (std::shared_ptr python, const std::string& input_path, const DeckKeyword&, std::size_t currentStep); + void handleGCONPROD(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors); // Normal keyword handlers -- in KeywordHandlers.cpp void handleBRANPROP (const HandlerContext&, const ParseContext&, ErrorGuard&); diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.cpp index 736299232..71e4cdf2e 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Action/ActionX.cpp @@ -33,7 +33,7 @@ namespace Action { bool ActionX::valid_keyword(const std::string& keyword) { - static std::unordered_set actionx_allowed_list = {"EXIT", "WELSPECS","WELOPEN", "UDQ"}; + static std::unordered_set actionx_allowed_list = {"EXIT", "GCONPROD", "WELSPECS","WELOPEN", "UDQ"}; return (actionx_allowed_list.find(keyword) != actionx_allowed_list.end()); } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp index 1babaef98..afe5ad689 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp @@ -322,11 +322,17 @@ namespace { } void Schedule::handleGCONPROD(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) { - for (const auto& record : handlerContext.keyword) { + auto current_step = handlerContext.currentStep; + const auto& keyword = handlerContext.keyword; + this->handleGCONPROD(keyword, current_step, parseContext, errors); + } + + void Schedule::handleGCONPROD(const DeckKeyword& keyword, std::size_t current_step, const ParseContext& parseContext, ErrorGuard& errors) { + for (const auto& record : keyword) { const std::string& groupNamePattern = record.getItem("GROUP").getTrimmedString(0); const auto group_names = this->groupNames(groupNamePattern); if (group_names.empty()) - invalidNamePattern(groupNamePattern, handlerContext.currentStep, parseContext, errors, handlerContext.keyword); + invalidNamePattern(groupNamePattern, current_step, parseContext, errors, keyword); const Group::ProductionCMode controlMode = Group::ProductionCModeFromString(record.getItem("CONTROL_MODE").getTrimmedString(0)); const Group::ExceedAction exceedAction = Group::ExceedActionFromString(record.getItem("EXCEED_PROC").getTrimmedString(0)); @@ -372,7 +378,7 @@ namespace { std::string msg_fmt = "Problem with {keyword}\n" "In {file} line {line}\n" "The supplied guide rate will be ignored"; - parseContext.handleError(ParseContext::SCHEDULE_IGNORED_GUIDE_RATE, msg_fmt, handlerContext.keyword.location(), errors); + parseContext.handleError(ParseContext::SCHEDULE_IGNORED_GUIDE_RATE, msg_fmt, keyword.location(), errors); } else { guide_rate = record.getItem("GUIDE_RATE").get(0); if (guide_rate == 0) @@ -382,7 +388,7 @@ namespace { } { - auto group_ptr = std::make_shared(this->getGroup(group_name, handlerContext.currentStep)); + auto group_ptr = std::make_shared(this->getGroup(group_name, current_step)); Group::GroupProductionProperties production(this->unit_system, group_name); production.gconprod_cmode = controlMode; production.active_cmode = controlMode; @@ -421,17 +427,17 @@ namespace { production.production_controls += static_cast(Group::ProductionCMode::RESV); if (group_ptr->updateProduction(production)) { - auto new_config = std::make_shared( this->guideRateConfig(handlerContext.currentStep) ); + auto new_config = std::make_shared( this->guideRateConfig(current_step) ); new_config->update_group(*group_ptr); - this->guide_rate_config.update( handlerContext.currentStep, std::move(new_config) ); + this->guide_rate_config.update( current_step, std::move(new_config) ); - this->updateGroup(std::move(group_ptr), handlerContext.currentStep); - m_events.addEvent(ScheduleEvents::GROUP_PRODUCTION_UPDATE, handlerContext.currentStep); - this->addWellGroupEvent(group_name, ScheduleEvents::GROUP_PRODUCTION_UPDATE, handlerContext.currentStep); + this->updateGroup(std::move(group_ptr), current_step); + m_events.addEvent(ScheduleEvents::GROUP_PRODUCTION_UPDATE, current_step); + this->addWellGroupEvent(group_name, ScheduleEvents::GROUP_PRODUCTION_UPDATE, current_step); - auto udq = std::make_shared(this->udqActive(handlerContext.currentStep)); - if (production.updateUDQActive(this->getUDQConfig(handlerContext.currentStep), *udq)) - this->updateUDQActive(handlerContext.currentStep, udq); + auto udq = std::make_shared(this->udqActive(current_step)); + if (production.updateUDQActive(this->getUDQConfig(current_step), *udq)) + this->updateUDQActive(current_step, udq); } } } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index a3f820d49..d426cfcd3 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -1496,9 +1496,14 @@ private: if (keyword.name() == "UDQ") this->updateUDQ(keyword, reportStep); + + if (keyword.name() == "GCONPROD") + this->handleGCONPROD(keyword, reportStep, parseContext, errors); } } + + void Schedule::applyWellProdIndexScaling(const std::string& well_name, const std::size_t reportStep, const double scalingFactor) { auto wstat = this->wells_static.find(well_name); if (wstat == this->wells_static.end()) diff --git a/tests/parser/ACTIONX.cpp b/tests/parser/ACTIONX.cpp index 298fe5de2..d011e67b3 100644 --- a/tests/parser/ACTIONX.cpp +++ b/tests/parser/ACTIONX.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -928,3 +929,64 @@ ENDACTIO BOOST_CHECK_EQUAL( st.run_count(action1), 1U); BOOST_CHECK_EQUAL( st.run_count(action2), 0U); } + + + + +BOOST_AUTO_TEST_CASE(Action_GCONPROD) { + const auto deck_string = std::string{ R"( +SCHEDULE + + +WELSPECS + 'PROD1' 'G1' 1 1 10 'OIL' / +/ + +GCONPROD +'G1' 'ORAT' 100 / +/ + +ACTIONX +'A' / +WWCT 'OPX' > 0.75 AND / +FPR < 100 / +/ + +GCONPROD + 'G1' 'ORAT' 200 / +/ + +ENDACTIO + +TSTEP +10 / + + )"}; + + auto unit_system = UnitSystem::newMETRIC(); + Opm::Parser parser; + auto deck = parser.parseString(deck_string); + EclipseGrid grid1(10,10,10); + TableManager table ( deck ); + FieldPropsManager fp( deck, Phases{true, true, true}, grid1, table); + auto python = std::make_shared(); + const auto st = SummaryState{ std::chrono::system_clock::now() }; + + Runspec runspec (deck); + Schedule sched(deck, grid1, fp, runspec, python); + const auto& action1 = sched.actions(0).get("A"); + { + const auto& group = sched.getGroup("G1", 0); + const auto& prod = group.productionControls(st); + BOOST_CHECK_CLOSE( prod.oil_target , unit_system.to_si(UnitSystem::measure::liquid_surface_rate, 100), 1e-5 ); + } + + Action::Result action_result(true); + sched.applyAction(0, action1, action_result); + + { + const auto& group = sched.getGroup("G1", 1); + const auto& prod = group.productionControls(st); + BOOST_CHECK_CLOSE( prod.oil_target , unit_system.to_si(UnitSystem::measure::liquid_surface_rate, 200), 1e-5 ); + } +}