From 43925ae4f217422492e3730d0893bb31920cdd84 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 25 Mar 2021 14:20:07 +0100 Subject: [PATCH 1/5] Explicily assign CMODE_UNDEFINED when controls vector is resized --- opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp index a434baed8..137451278 100644 --- a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp +++ b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp @@ -66,6 +66,7 @@ namespace Opm using BaseType :: numWells; using BaseType :: numPhases; using BaseType :: resetConnectionTransFactors; + using BaseType :: updateStatus; /// Allocate and initialize if wells is non-null. Also tries /// to give useful initial values to the bhp(), wellRates() @@ -166,8 +167,8 @@ namespace Opm is_producer_[w] = wells_ecl[w].isProducer(); } - current_injection_controls_.resize(nw); - current_production_controls_.resize(nw); + current_injection_controls_.resize(nw, Well::InjectorCMode::CMODE_UNDEFINED); + current_production_controls_.resize(nw, Well::ProducerCMode::CMODE_UNDEFINED); for (int w = 0; w < nw; ++w) { if (wells_ecl[w].isProducer()) { const auto controls = wells_ecl[w].productionControls(summary_state); From 90a9ed49a2302240be191408eb8de4a1ae88df4b Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 25 Mar 2021 14:20:42 +0100 Subject: [PATCH 2/5] Add function WellState::updateStatus() --- opm/simulators/wells/WellState.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/opm/simulators/wells/WellState.hpp b/opm/simulators/wells/WellState.hpp index d71cfbe74..f71d6f1cf 100644 --- a/opm/simulators/wells/WellState.hpp +++ b/opm/simulators/wells/WellState.hpp @@ -239,6 +239,22 @@ namespace Opm this->thp_[well_index] = 0; } + void updateStatus(int well_index, Well::Status status) { + switch (status) { + case Well::Status::OPEN: + this->openWell(well_index); + break; + case Well::Status::SHUT: + this->shutWell(well_index); + break; + case Well::Status::STOP: + this->stopWell(well_index); + break; + default: + throw std::logic_error("Invalid well status"); + } + } + virtual data::Wells report(const PhaseUsage& pu, const int* globalCellIdxMap, From 5fe43c09cbb0b9d5cef2fedde0e2048884176eed Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 25 Mar 2021 14:42:03 +0100 Subject: [PATCH 3/5] Implement updateEclWell() as an internal function in wellPI code --- opm/simulators/wells/BlackoilWellModel.hpp | 1 - .../wells/BlackoilWellModel_impl.hpp | 47 +++++++++---------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 6e0477d8e..6e05f2779 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -365,7 +365,6 @@ namespace Opm { /// Returns true if the well was actually found and shut. bool forceShutWellByNameIfPredictionMode(const std::string& wellname, const double simulation_time); - void updateEclWell(const int timeStepIdx, const int well_index); void updateEclWell(const int timeStepIdx, const std::string& wname); bool hasWell(const std::string& wname); double wellPI(const int well_index) const; diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index e7b5c1fde..69994bb9c 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -2622,30 +2622,6 @@ namespace Opm { - template - void - BlackoilWellModel:: - updateEclWell(const int timeStepIdx, const int well_index) - { - const auto& schedule = this->ebosSimulator_.vanguard().schedule(); - const auto& wname = this->wells_ecl_[well_index].name(); - this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx); - - const auto& well = this->wells_ecl_[well_index]; - auto& pd = this->well_perf_data_[well_index]; - auto pdIter = pd.begin(); - for (const auto& conn : well.getConnections()) { - if (conn.state() != Connection::State::SHUT) { - pdIter->connection_transmissibility_factor = conn.CF(); - ++pdIter; - } - } - - this->wellState().resetConnectionTransFactors(well_index, pd); - this->prod_index_calc_[well_index].reInit(well); - } - - @@ -2762,6 +2738,26 @@ namespace Opm { ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX); }; + auto updateEclWell = [this, timeStepIdx](const int well_index) -> void + { + const auto& schedule = this->schedule(); + const auto& wname = this->wells_ecl_[well_index].name(); + this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx); + + const auto& well = this->wells_ecl_[well_index]; + auto& pd = this->well_perf_data_[well_index]; + auto pdIter = pd.begin(); + for (const auto& conn : well.getConnections()) { + if (conn.state() != Connection::State::SHUT) { + pdIter->connection_transmissibility_factor = conn.CF(); + ++pdIter; + } + } + this->well_state_.resetConnectionTransFactors(well_index, pd); + this->prod_index_calc_[well_index].reInit(well); + }; + + auto rescaleWellPI = [this, timeStepIdx](const int well_index, const double newWellPI) -> void @@ -2770,8 +2766,6 @@ namespace Opm { auto& schedule = this->ebosSimulator_.vanguard().schedule(); // Mutable schedule.applyWellProdIndexScaling(wname, timeStepIdx, newWellPI); - - this->updateEclWell(timeStepIdx, well_index); }; // Minimal well setup to compute PI/II values @@ -2797,6 +2791,7 @@ namespace Opm { for (auto wellID = 0*nw; wellID < nw; ++wellID) { if (hasWellPIEvent(wellID)) { rescaleWellPI(wellID, this->wellPI(wellID)); + updateEclWell(wellID); } } From 98f6a9a7acda61b45dacf1c127512eb3763d4a7c Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 25 Mar 2021 14:46:35 +0100 Subject: [PATCH 4/5] Update collection of wells after ACTIONX --- ebos/eclpeacemanwell.hh | 5 +-- ebos/eclproblem.hh | 8 ++--- ebos/eclwellmanager.hh | 3 +- opm/simulators/wells/BlackoilWellModel.hpp | 2 +- .../wells/BlackoilWellModel_impl.hpp | 35 +++++++++++-------- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/ebos/eclpeacemanwell.hh b/ebos/eclpeacemanwell.hh index 4a2b1dcb8..7248eb356 100644 --- a/ebos/eclpeacemanwell.hh +++ b/ebos/eclpeacemanwell.hh @@ -45,6 +45,7 @@ #include #include +#include namespace Opm { @@ -1449,8 +1450,8 @@ protected: void - updateEclWell(int, const std::string&) { - throw std::logic_error("updateEclWell() method not implemented for class eclpeacemanwell"); + updateEclWells(int, const std::unordered_set&) { + throw std::logic_error("updateEclWells() method not implemented for class eclpeacemanwell"); } diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 45a2a0b78..07d298127 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1393,14 +1393,10 @@ public: const auto& wellpi = this->fetchWellPI(reportStep, *action, schedule, matching_wells); - schedule.applyAction(reportStep, Opm::TimeService::from_time_t(simTime), *action, actionResult, wellpi); + auto affected_wells = schedule.applyAction(reportStep, Opm::TimeService::from_time_t(simTime), *action, actionResult, wellpi); actionState.add_run(*action, simTime); + this->wellModel_.updateEclWells(reportStep, affected_wells); - for ( const auto& [wname, _] : wellpi) { - (void)_; - if (this->wellModel_.hasWell(wname)) - this->wellModel_.updateEclWell(reportStep, wname); - } } else { std::string msg = "The action: " + action->name() + " evaluated to false at " + ts; Opm::OpmLog::info(msg); diff --git a/ebos/eclwellmanager.hh b/ebos/eclwellmanager.hh index cd7706646..d7999e4ac 100644 --- a/ebos/eclwellmanager.hh +++ b/ebos/eclwellmanager.hh @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -658,7 +659,7 @@ public: void - updateEclWell(int, const std::string&) { + updateEclWells(int, const std::unordered_set&) { throw std::logic_error("wellPI() method not implemented for class eclwellmanager"); } diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 6e05f2779..8ec4adc42 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -365,7 +365,7 @@ namespace Opm { /// Returns true if the well was actually found and shut. bool forceShutWellByNameIfPredictionMode(const std::string& wellname, const double simulation_time); - void updateEclWell(const int timeStepIdx, const std::string& wname); + void updateEclWells(const int timeStepIdx, const std::unordered_set& wells); bool hasWell(const std::string& wname); double wellPI(const int well_index) const; double wellPI(const std::string& well_name) const; diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 69994bb9c..416d5b65e 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -2628,25 +2628,32 @@ namespace Opm { template void BlackoilWellModel:: - updateEclWell(const int timeStepIdx, const std::string& wname) - { - auto well_iter = std::find_if(this->wells_ecl_.begin(), this->wells_ecl_.end(), - [&wname](const auto& well) -> bool - { - return well.name() == wname; - }); + updateEclWells(const int timeStepIdx, const std::unordered_set& wells) { + const auto& schedule = this->ebosSimulator_.vanguard().schedule(); + for (const auto& wname : wells) { + auto well_iter = std::find_if( this->wells_ecl_.begin(), this->wells_ecl_.end(), [wname] (const auto& well) -> bool { return well.name() == wname;}); + if (well_iter != this->wells_ecl_.end()) { + auto well_index = std::distance( this->wells_ecl_.begin(), well_iter ); + this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx); - if (well_iter == this->wells_ecl_.end()) { - throw std::logic_error { "Could not find well: " + wname }; + const auto& well = this->wells_ecl_[well_index]; + auto& pd = this->well_perf_data_[well_index]; + auto pdIter = pd.begin(); + for (const auto& conn : well.getConnections()) { + if (conn.state() != Connection::State::SHUT) { + pdIter->connection_transmissibility_factor = conn.CF(); + ++pdIter; + } + } + this->wellState().updateStatus(well_index, well.getStatus()); + this->wellState().resetConnectionTransFactors(well_index, pd); + this->prod_index_calc_[well_index].reInit(well); + } } - - auto well_index = std::distance(this->wells_ecl_.begin(), well_iter); - this->updateEclWell(timeStepIdx, well_index); } - template double BlackoilWellModel:: @@ -2753,7 +2760,7 @@ namespace Opm { ++pdIter; } } - this->well_state_.resetConnectionTransFactors(well_index, pd); + this->wellState().resetConnectionTransFactors(well_index, pd); this->prod_index_calc_[well_index].reInit(well); }; From b71a273ada3446a2e9f5ccd10eeb6dc82ea3ae0e Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Fri, 26 Mar 2021 22:58:21 +0100 Subject: [PATCH 5/5] Commit wellstate after appplyActions --- ebos/eclproblem.hh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 07d298127..d8bccd94a 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1377,6 +1377,7 @@ public: pyaction->run(ecl_state, schedule, reportStep, summaryState); } + bool commit_wellstate = false; auto simTime = schedule.simTime(reportStep); for (const auto& action : actions.pending(actionState, simTime)) { auto actionResult = action->eval(context); @@ -1396,12 +1397,21 @@ public: auto affected_wells = schedule.applyAction(reportStep, Opm::TimeService::from_time_t(simTime), *action, actionResult, wellpi); actionState.add_run(*action, simTime); this->wellModel_.updateEclWells(reportStep, affected_wells); - + if (!affected_wells.empty()) + commit_wellstate = true; } else { std::string msg = "The action: " + action->name() + " evaluated to false at " + ts; Opm::OpmLog::info(msg); } } + /* + The well state has been stored in a previous object when the time step + has completed successfully, the action process might have modified the + well state, and to be certain that is not overwritten when starting + the next timestep we must commit it. + */ + if (commit_wellstate) + this->wellModel_.commitWellState(); }