diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 9841c6cd2..fdc5fdf37 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -313,7 +313,7 @@ namespace Opm void updateGroup(std::shared_ptr group, size_t reportStep); bool checkGroups(const ParseContext& parseContext, ErrorGuard& errors); void updateUDQActive( std::size_t timeStep, std::shared_ptr udq ); - bool updateWellStatus( const std::string& well, size_t reportStep , Well::Status status); + bool updateWellStatus( const std::string& well, size_t reportStep , Well::Status status, bool update_connections); void addWellToGroup( const std::string& group_name, const std::string& well_name , size_t timeStep); void iterateScheduleSection(const ParseContext& parseContext , ErrorGuard& errors, const SCHEDULESection& , const EclipseGrid& grid, const FieldPropsManager& fp, diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp index 967fd822a..ddb3acde3 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp @@ -497,7 +497,7 @@ public: bool updateRefDepth(double ref_dpeth); bool updateDrainageRadius(double drainage_radius); bool updateConnections(const std::shared_ptr connections); - bool updateStatus(Status status); + bool updateStatus(Status status, bool update_connections); bool updateGroup(const std::string& group); bool updateProducer(bool is_producer); bool updateWellGuideRate(bool available, double guide_rate, GuideRateTarget guide_phase, double scale_factor); diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 42ced066e..dcc648bb9 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -813,7 +813,7 @@ namespace { invalidNamePattern(wellNamePattern, parseContext, errors, keyword); for( const auto& well_name : well_names) { - updateWellStatus( well_name , currentStep , status ); + updateWellStatus( well_name , currentStep , status, false ); { auto& dynamic_state = this->wells_static.at(well_name); auto well2 = std::make_shared(*dynamic_state[currentStep]); @@ -856,7 +856,7 @@ namespace { "Well " + well2->name() + " is a history matched well with zero rate where crossflow is banned. " + "This well will be closed at " + std::to_string ( m_timeMap.getTimePassedUntil(currentStep) / (60*60*24) ) + " days"; OpmLog::note(msg); - updateWellStatus( well_name, currentStep, Well::Status::SHUT ); + updateWellStatus( well_name, currentStep, Well::Status::SHUT, false ); } } } @@ -877,7 +877,7 @@ namespace { for( const auto& well_name : well_names) { - updateWellStatus( well_name , currentStep , status ); + updateWellStatus( well_name , currentStep , status, false ); { auto& dynamic_state = this->wells_static.at(well_name); auto well2 = std::make_shared(*dynamic_state[currentStep]); @@ -918,15 +918,15 @@ namespace { void Schedule::shut_well(const std::string& well_name, std::size_t report_step) { - this->updateWellStatus(well_name, report_step, Well::Status::SHUT ); + this->updateWellStatus(well_name, report_step, Well::Status::SHUT, true); } void Schedule::open_well(const std::string& well_name, std::size_t report_step) { - this->updateWellStatus(well_name, report_step, Well::Status::OPEN ); + this->updateWellStatus(well_name, report_step, Well::Status::OPEN, true); } void Schedule::stop_well(const std::string& well_name, std::size_t report_step) { - this->updateWellStatus(well_name, report_step, Well::Status::STOP ); + this->updateWellStatus(well_name, report_step, Well::Status::STOP, true); } void Schedule::updateWell(std::shared_ptr well, size_t reportStep) { @@ -939,19 +939,17 @@ namespace { Function is quite dangerous - because if this is called while holding a Well pointer that will go stale and needs to be refreshed. */ - bool Schedule::updateWellStatus( const std::string& well_name, size_t reportStep , Well::Status status) { + bool Schedule::updateWellStatus( const std::string& well_name, size_t reportStep , Well::Status status, bool update_connections) { bool update = false; - { - auto& dynamic_state = this->wells_static.at(well_name); - auto well2 = std::make_shared(*dynamic_state[reportStep]); - if (well2->updateStatus(status)) { - m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep ); - this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep); - this->updateWell(well2, reportStep); - update = true; - if (status == Well::Status::OPEN) - this->rft_config.addWellOpen(well_name, reportStep); - } + auto& dynamic_state = this->wells_static.at(well_name); + auto well2 = std::make_shared(*dynamic_state[reportStep]); + if (well2->updateStatus(status, update_connections)) { + m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep ); + this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep); + this->updateWell(well2, reportStep); + update = true; + if (status == Well::Status::OPEN) + this->rft_config.addWellOpen(well_name, reportStep); } return update; } @@ -985,7 +983,7 @@ namespace { for( const auto& well_name : well_names ) { Well::Status status = Well::StatusFromString( record.getItem("STATUS").getTrimmedString(0)); - updateWellStatus( well_name , currentStep , status ); + updateWellStatus( well_name , currentStep , status, false ); { bool update_well = false; auto& dynamic_state = this->wells_static.at(well_name); @@ -1018,14 +1016,14 @@ namespace { if (injection->surfaceInjectionRate.is()) { if (injection->hasInjectionControl(Well::InjectorCMode::RATE) && injection->surfaceInjectionRate.zero()) { OpmLog::note(msg); - updateWellStatus( well_name, currentStep, Well::Status::SHUT ); + updateWellStatus( well_name, currentStep, Well::Status::SHUT, false ); } } if (injection->reservoirInjectionRate.is()) { if (injection->hasInjectionControl(Well::InjectorCMode::RESV) && injection->reservoirInjectionRate.zero()) { OpmLog::note(msg); - updateWellStatus( well_name, currentStep, Well::Status::SHUT ); + updateWellStatus( well_name, currentStep, Well::Status::SHUT, false ); } } } @@ -1048,7 +1046,7 @@ namespace { invalidNamePattern( wellNamePattern, parseContext, errors, keyword); for (const auto& well_name : well_names) { - updateWellStatus( well_name, currentStep, status ); + updateWellStatus( well_name, currentStep, status, false ); { bool update_well = false; auto& dynamic_state = this->wells_static.at(well_name); @@ -1076,7 +1074,7 @@ namespace { "Well " + well_name + " is an injector with zero rate where crossflow is banned. " + "This well will be closed at " + std::to_string ( m_timeMap.getTimePassedUntil(currentStep) / (60*60*24) ) + " days"; OpmLog::note(msg); - updateWellStatus( well_name, currentStep, Well::Status::SHUT ); + updateWellStatus( well_name, currentStep, Well::Status::SHUT, false ); } } } @@ -1478,7 +1476,7 @@ namespace { + std::to_string( days ) + " days"; OpmLog::note(msg); } else { - this->updateWellStatus( wname, currentStep, well_status ); + this->updateWellStatus( wname, currentStep, well_status, false ); if (well_status == open) this->rft_config.addWellOpen(wname, currentStep); @@ -2709,7 +2707,7 @@ void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, c const auto& well = this->getWell(wname, timeStep); const auto& connections = well.getConnections(); if (connections.allConnectionsShut()) - this->updateWellStatus( well.name(), timeStep, Well::Status::SHUT); + this->updateWellStatus( well.name(), timeStep, Well::Status::SHUT, false); } } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 673b9a417..8992f9536 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -379,13 +379,41 @@ bool Well::updateHead(int I, int J) { } -bool Well::updateStatus(Status status_arg) { - if (this->status != status_arg) { - this->status = status_arg; - return true; +bool Well::updateStatus(Status well_state, bool update_connections) { + bool update = false; + if (update_connections) { + Connection::State connection_state; + + switch (well_state) { + case Status::OPEN: + connection_state = Connection::State::OPEN; + break; + case Status::SHUT: + connection_state = Connection::State::SHUT; + break; + case Status::AUTO: + connection_state = Connection::State::AUTO; + break; + case Status::STOP: + connection_state = Connection::State::SHUT; + break; + } + + auto new_connections = std::make_shared(this->headI, this->headJ); + for (auto c : *this->connections) { + c.setState(connection_state); + new_connections->add(c); + } + + update = this->updateConnections(new_connections); } - return false; + if (this->status != well_state) { + this->status = well_state; + update = true; + } + + return update; } @@ -627,7 +655,7 @@ Phase Well::getPreferredPhase() const { When all connections of a well are closed with the WELOPEN keywords, the well itself should also be SHUT. In the main parsing code this is handled by the function checkIfAllConnectionsIsShut() which is called at the end of every - report step in Schedule::iterateScheduleSection(). This is donn in this way + report step in Schedule::iterateScheduleSection(). This is done in this way because there is some twisted logic aggregating connection changes over a complete report step. @@ -666,6 +694,10 @@ bool Well::handleWELOPEN(const DeckRecord& record, Connection::State state_arg, return this->updateConnections(new_connections); } + + + + bool Well::handleCOMPLUMP(const DeckRecord& record) { auto match = [=]( const Connection &c) -> bool { diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index bdcac78bd..9d611e47a 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -3351,9 +3351,9 @@ BOOST_AUTO_TEST_CASE(WELL_STATIC) { BOOST_CHECK(ws.updateRefDepth(1.0)); BOOST_CHECK(!ws.updateRefDepth(1.0)); - ws.updateStatus(Well::Status::OPEN); - BOOST_CHECK(!ws.updateStatus(Well::Status::OPEN)); - BOOST_CHECK(ws.updateStatus(Well::Status::SHUT)); + ws.updateStatus(Well::Status::OPEN, false); + BOOST_CHECK(!ws.updateStatus(Well::Status::OPEN, false)); + BOOST_CHECK(ws.updateStatus(Well::Status::SHUT, false)); const auto& connections = ws.getConnections(); BOOST_CHECK_EQUAL(connections.size(), 0); diff --git a/tests/parser/WTEST.cpp b/tests/parser/WTEST.cpp index 6b91933dc..ef0108822 100644 --- a/tests/parser/WTEST.cpp +++ b/tests/parser/WTEST.cpp @@ -78,13 +78,13 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE2) { std::vector wells; wells.emplace_back("WELL_NAME", "A", 0, 0, 1, 1, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.); { - wells[0].updateStatus(Well::Status::SHUT); + wells[0].updateStatus(Well::Status::SHUT, false); auto shut_wells = st.updateWells(wc, wells, 5000); BOOST_CHECK_EQUAL(shut_wells.size(), 0); } { - wells[0].updateStatus(Well::Status::OPEN); + wells[0].updateStatus(Well::Status::OPEN, false); auto shut_wells = st.updateWells(wc, wells, 5000); BOOST_CHECK_EQUAL( shut_wells.size(), 1); } @@ -115,12 +115,12 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE) { WellTestConfig wc; { - wells[0].updateStatus(Well::Status::SHUT); + wells[0].updateStatus(Well::Status::SHUT, false); auto shut_wells = st.updateWells(wc, wells, 110. * day); BOOST_CHECK_EQUAL(shut_wells.size(), 0); } { - wells[0].updateStatus(Well::Status::OPEN); + wells[0].updateStatus(Well::Status::OPEN, false); auto shut_wells = st.updateWells(wc, wells, 110. * day); BOOST_CHECK_EQUAL(shut_wells.size(), 0); } @@ -151,10 +151,10 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE) { wc.add_well("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 1000. * day, 3, 0, 5); - wells[0].updateStatus(Well::Status::SHUT); + wells[0].updateStatus(Well::Status::SHUT, false); BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 4100. * day).size(), 0); - wells[0].updateStatus(Well::Status::OPEN); + wells[0].updateStatus(Well::Status::OPEN, false); BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 4100. * day).size(), 1); BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 5200. * day).size(), 1); @@ -182,9 +182,9 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE_COMPLETIONS) { const UnitSystem us{}; std::vector wells; wells.emplace_back("WELL_NAME", "A", 0, 0, 1, 1, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.); - wells[0].updateStatus(Well::Status::OPEN); + wells[0].updateStatus(Well::Status::OPEN, false); wells.emplace_back("WELLX", "A", 0, 0, 2, 2, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.); - wells[1].updateStatus(Well::Status::OPEN); + wells[1].updateStatus(Well::Status::OPEN, false); auto closed_completions = st.updateWells(wc, wells, 5000); BOOST_CHECK_EQUAL( closed_completions.size(), 0);