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..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); @@ -1393,19 +1394,24 @@ 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); - - for ( const auto& [wname, _] : wellpi) { - (void)_; - if (this->wellModel_.hasWell(wname)) - this->wellModel_.updateEclWell(reportStep, wname); - } + 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(); } 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 6e0477d8e..8ec4adc42 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -365,8 +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 int well_index); - 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 e7b5c1fde..416d5b65e 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -2622,55 +2622,38 @@ namespace Opm { + + + template void BlackoilWellModel:: - updateEclWell(const int timeStepIdx, const int well_index) - { + updateEclWells(const int timeStepIdx, const std::unordered_set& wells) { 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); + 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); - 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; + 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); } } - - this->wellState().resetConnectionTransFactors(well_index, pd); - this->prod_index_calc_[well_index].reInit(well); } - - - 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; - }); - - if (well_iter == this->wells_ecl_.end()) { - throw std::logic_error { "Could not find well: " + wname }; - } - - auto well_index = std::distance(this->wells_ecl_.begin(), well_iter); - this->updateEclWell(timeStepIdx, well_index); - } - - - - template double BlackoilWellModel:: @@ -2762,6 +2745,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->wellState().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 +2773,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 +2798,7 @@ namespace Opm { for (auto wellID = 0*nw; wellID < nw; ++wellID) { if (hasWellPIEvent(wellID)) { rescaleWellPI(wellID, this->wellPI(wellID)); + updateEclWell(wellID); } } 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, 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);