diff --git a/opm/simulators/flow/EclActionHandler.cpp b/opm/simulators/flow/EclActionHandler.cpp index 4c3ef0ad6..c9d63b58b 100644 --- a/opm/simulators/flow/EclActionHandler.cpp +++ b/opm/simulators/flow/EclActionHandler.cpp @@ -188,21 +188,24 @@ void EclActionHandler::applySimulatorUpdate(const int report_step, const SimulatorUpdate& sim_update, bool& commit_wellstate, const TransFunc& updateTrans) - { - OPM_TIMEBLOCK(applySimulatorUpdate); - this->wellModel_.updateEclWells(report_step, sim_update.affected_wells, summaryState_); - if (!sim_update.affected_wells.empty()) - commit_wellstate = true; +{ + OPM_TIMEBLOCK(applySimulatorUpdate); - if (sim_update.tran_update) { - const auto& keywords = schedule_[report_step].geo_keywords(); - ecl_state_.apply_schedule_keywords( keywords ); - eclBroadcast(comm_, ecl_state_.getTransMult() ); + this->wellModel_.updateEclWells(report_step, sim_update, this->summaryState_); - // re-compute transmissibility - updateTrans(true); - } - } + if (!sim_update.affected_wells.empty()) { + commit_wellstate = true; + } + + if (sim_update.tran_update) { + const auto& keywords = schedule_[report_step].geo_keywords(); + ecl_state_.apply_schedule_keywords( keywords ); + eclBroadcast(comm_, ecl_state_.getTransMult() ); + + // re-compute transmissibility + updateTrans(true); + } +} std::unordered_map EclActionHandler::fetchWellPI(const int reportStep, diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index 843929deb..697ba75b6 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -32,6 +32,9 @@ #include #include +#include + +#include #include #include #include @@ -42,7 +45,7 @@ #include #include #include -#include + #include #include @@ -669,10 +672,10 @@ checkGroupHigherConstraints(const Group& group, void BlackoilWellModelGeneric:: updateEclWells(const int timeStepIdx, - const std::unordered_set& wells, + const SimulatorUpdate& sim_update, const SummaryState& st) { - for (const auto& wname : wells) { + for (const auto& wname : sim_update.affected_wells) { auto well_iter = std::find_if(this->wells_ecl_.begin(), this->wells_ecl_.end(), [&wname] (const auto& well) -> bool { @@ -683,25 +686,36 @@ updateEclWells(const int timeStepIdx, continue; } - auto well_index = std::distance(this->wells_ecl_.begin(), well_iter); - this->wells_ecl_[well_index] = schedule_.getWell(wname, timeStepIdx); + const auto well_index = std::distance(this->wells_ecl_.begin(), well_iter); - 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] = + this->schedule_.getWell(wname, timeStepIdx); + + 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; + } } } - auto& ws = this->wellState().well(well_index); - ws.updateStatus( well.getStatus() ); - ws.reset_connection_factors(pd); - ws.update_targets(well, st); + { + auto& ws = this->wellState().well(well_index); + + ws.updateStatus(well.getStatus()); + ws.reset_connection_factors(pd); + ws.update_targets(well, st); + } + this->prod_index_calc_[well_index].reInit(well); } + + this->wellStructureChangedDynamically_ = sim_update.well_structure_changed; } double diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 4eeb98077..b7428b6fe 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -54,14 +54,15 @@ namespace Opm { class DeferredLogger; class EclipseState; + class GasLiftGroupInfo; class GasLiftSingleWellGeneric; class GasLiftWellState; - class GasLiftGroupInfo; class Group; class GuideRateConfig; class ParallelWellInfo; class RestartValue; class Schedule; + struct SimulatorUpdate; class SummaryConfig; class VFPProperties; class WellInterfaceGeneric; @@ -152,7 +153,7 @@ public: double wellPI(const std::string& well_name) const; void updateEclWells(const int timeStepIdx, - const std::unordered_set& wells, + const SimulatorUpdate& sim_update, const SummaryState& st); void initFromRestartFile(const RestartValue& restartValues, @@ -579,6 +580,8 @@ protected: double last_glift_opt_time_ = -1.0; + bool wellStructureChangedDynamically_{false}; + std::map switched_prod_groups_; std::map, std::string> switched_inj_groups_; diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 1e0a61d05..45a76f3b7 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -272,6 +272,8 @@ namespace Opm { // Store the current well and group states in order to recover in // the case of failed iterations this->commitWGState(); + + this->wellStructureChangedDynamically_ = false; } @@ -371,16 +373,46 @@ namespace Opm { beginTimeStep() { OPM_TIMEBLOCK(beginTimeStep); - updateAverageFormationFactor(); + + this->updateAverageFormationFactor(); + DeferredLogger local_deferredLogger; - switched_prod_groups_.clear(); - switched_inj_groups_.clear(); + + this->switched_prod_groups_.clear(); + this->switched_inj_groups_.clear(); + + if (this->wellStructureChangedDynamically_) { + // Something altered the well structure/topology. Possibly + // WELSPECS/COMPDAT and/or WELOPEN run from an ACTIONX block. + // Reconstruct the local wells to account for the new well + // structure. + const auto reportStepIdx = + this->ebosSimulator_.episodeIndex(); + + // Disable WELPI scaling when well structure is updated in the + // middle of a report step. + const auto enableWellPIScaling = false; + + this->initializeLocalWellStructure(reportStepIdx, enableWellPIScaling); + this->initializeGroupStructure(reportStepIdx); + + this->commitWGState(); + + // Reset topology flag to signal that we've handled this + // structure change. That way we don't end up here in + // subsequent calls to beginTimeStep() unless there's a new + // dynamic change to the well structure during a report step. + this->wellStructureChangedDynamically_ = false; + } this->resetWGState(); + const int reportStepIdx = ebosSimulator_.episodeIndex(); updateAndCommunicateGroupData(reportStepIdx, ebosSimulator_.model().newtonMethod().numIterations()); + this->wellState().gliftTimeStepInit(); + const double simulationTime = ebosSimulator_.time(); OPM_BEGIN_PARALLEL_TRY_CATCH(); {