diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index bd3faa997..337807755 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -2211,7 +2211,8 @@ namespace Opm { const auto& wname = well->name(); const auto wasClosed = wellTestState.well_is_closed(wname); well->checkWellOperability(simulator_, this->wellState(), local_deferredLogger); - well->updateWellTestState(this->wellState().well(wname), simulationTime, /*writeMessageToOPMLog=*/ true, wellTestState, local_deferredLogger); + const bool under_zero_target = well->wellUnderZeroGroupRateTarget(this->simulator_, this->wellState(), local_deferredLogger); + well->updateWellTestState(this->wellState().well(wname), simulationTime, /*writeMessageToOPMLog=*/ true, under_zero_target, wellTestState, local_deferredLogger); if (!wasClosed && wellTestState.well_is_closed(wname)) { this->closed_this_step_.insert(wname); diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index 2dcaa4ccf..9d43ff88b 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -229,6 +229,11 @@ public: const WellState& well_state, DeferredLogger& deferred_logger) const; + bool wellUnderZeroGroupRateTarget(const Simulator& simulator, + const WellState& well_state, + DeferredLogger& deferred_logger, + std::optional group_control = std::nullopt) const; + bool stoppedOrZeroRateTarget(const Simulator& simulator, const WellState& well_state, DeferredLogger& deferred_logger) const; diff --git a/opm/simulators/wells/WellInterfaceFluidSystem.cpp b/opm/simulators/wells/WellInterfaceFluidSystem.cpp index 7c97994a3..e0fe978cc 100644 --- a/opm/simulators/wells/WellInterfaceFluidSystem.cpp +++ b/opm/simulators/wells/WellInterfaceFluidSystem.cpp @@ -308,11 +308,11 @@ getGroupProductionTargetRate(const Group& group, template bool WellInterfaceFluidSystem:: -wellUnderZeroRateTargetGroup(const SummaryState& summary_state, - const Schedule& schedule, - const WellState& well_state, - const GroupState& group_state, - DeferredLogger& deferred_logger) const +zeroGroupRateTarget(const SummaryState& summary_state, + const Schedule& schedule, + const WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferred_logger) const { const auto& well = this->well_ecl_; const auto& group = schedule.getGroup(well.groupName(), this->currentStep()); diff --git a/opm/simulators/wells/WellInterfaceFluidSystem.hpp b/opm/simulators/wells/WellInterfaceFluidSystem.hpp index 0a29acd9e..bd2a64f91 100644 --- a/opm/simulators/wells/WellInterfaceFluidSystem.hpp +++ b/opm/simulators/wells/WellInterfaceFluidSystem.hpp @@ -117,11 +117,11 @@ protected: Scalar efficiencyFactor, DeferredLogger& deferred_logger) const; - bool wellUnderZeroRateTargetGroup(const SummaryState& summary_state, - const Schedule& schedule, - const WellState& well_state, - const GroupState& group_state, - DeferredLogger& deferredLogger) const; + bool zeroGroupRateTarget(const SummaryState& summary_state, + const Schedule& schedule, + const WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferredLogger) const; // For the conversion between the surface volume rate and reservoir voidage rate const RateConverterType& rateConverter_; diff --git a/opm/simulators/wells/WellInterfaceGeneric.cpp b/opm/simulators/wells/WellInterfaceGeneric.cpp index 7935bb18f..3e6464e11 100644 --- a/opm/simulators/wells/WellInterfaceGeneric.cpp +++ b/opm/simulators/wells/WellInterfaceGeneric.cpp @@ -298,12 +298,14 @@ void WellInterfaceGeneric:: updateWellTestState(const SingleWellState& ws, const double& simulationTime, const bool& writeMessageToOPMLog, + const bool zero_group_target, WellTestState& wellTestState, DeferredLogger& deferred_logger) const { // updating well test state based on Economic limits for operable wells if (this->isOperableAndSolvable()) { - WellTest(*this).updateWellTestStateEconomic(ws, simulationTime, writeMessageToOPMLog, wellTestState, deferred_logger); + WellTest(*this).updateWellTestStateEconomic(ws, simulationTime, writeMessageToOPMLog, wellTestState, + zero_group_target, deferred_logger); } else { // updating well test state based on physical (THP/BHP) limits. WellTest(*this).updateWellTestStatePhysical(simulationTime, writeMessageToOPMLog, wellTestState, deferred_logger); @@ -620,6 +622,16 @@ wellUnderZeroRateTargetIndividual(const SummaryState& summary_state, } } +template +bool WellInterfaceGeneric:: +wellUnderGroupControl(const SingleWellState& ws) const +{ + // Check if well is under group control + const bool isGroupControlled = (this->isInjector() && ws.injection_cmode == Well::InjectorCMode::GRUP) || + (this->isProducer() && ws.production_cmode == Well::ProducerCMode::GRUP); + return isGroupControlled; +} + template void WellInterfaceGeneric::resetWellOperability() { diff --git a/opm/simulators/wells/WellInterfaceGeneric.hpp b/opm/simulators/wells/WellInterfaceGeneric.hpp index edbd57312..07049d76b 100644 --- a/opm/simulators/wells/WellInterfaceGeneric.hpp +++ b/opm/simulators/wells/WellInterfaceGeneric.hpp @@ -168,6 +168,7 @@ public: void updateWellTestState(const SingleWellState& ws, const double& simulationTime, const bool& writeMessageToOPMLog, + const bool zero_group_target, WellTestState& wellTestState, DeferredLogger& deferred_logger) const; @@ -200,6 +201,8 @@ protected: bool wellUnderZeroRateTargetIndividual(const SummaryState& summary_state, const WellState& well_state) const; + bool wellUnderGroupControl(const SingleWellState& ws) const; + std::pair computeWellPotentials(std::vector& well_potentials, const WellState& well_state); diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index 0fa199539..ec451bc56 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -431,9 +431,11 @@ namespace Opm for (int p = 0; p < np; ++p) { ws.well_potentials[p] = std::max(Scalar{0.0}, potentials[p]); } + const bool under_zero_target = this->wellUnderZeroGroupRateTarget(simulator, well_state_copy, deferred_logger); this->updateWellTestState(well_state_copy.well(this->indexOfWell()), simulation_time, /*writeMessageToOPMLog=*/ false, + under_zero_target, welltest_state_temp, deferred_logger); this->closeCompletions(welltest_state_temp); @@ -1440,19 +1442,32 @@ namespace Opm DeferredLogger& deferred_logger) const { // Check if well is under zero rate control, either directly or from group - const auto& ws = well_state.well(this->index_of_well_); - const bool isGroupControlled = (this->isInjector() && ws.injection_cmode == Well::InjectorCMode::GRUP) || - (this->isProducer() && ws.production_cmode == Well::ProducerCMode::GRUP); + const bool isGroupControlled = this->wellUnderGroupControl(well_state.well(this->index_of_well_)); if (!isGroupControlled) { // well is not under group control, check "individual" version const auto& summaryState = simulator.vanguard().summaryState(); return this->wellUnderZeroRateTargetIndividual(summaryState, well_state); } else { + return this->wellUnderZeroGroupRateTarget(simulator, well_state, deferred_logger, isGroupControlled); + } + } + + template + bool + WellInterface::wellUnderZeroGroupRateTarget(const Simulator& simulator, + const WellState& well_state, + DeferredLogger& deferred_logger, + const std::optional group_control) const + { + // Check if well is under zero rate target from group + const bool isGroupControlled = group_control.value_or(this->wellUnderGroupControl(well_state.well(this->index_of_well_))); + if (isGroupControlled) { const auto& summaryState = simulator.vanguard().summaryState(); const auto& group_state = simulator.problem().wellModel().groupState(); const auto& schedule = simulator.vanguard().schedule(); - return this->wellUnderZeroRateTargetGroup(summaryState, schedule, well_state, group_state, deferred_logger); + return this->zeroGroupRateTarget(summaryState, schedule, well_state, group_state, deferred_logger); } + return false; } template diff --git a/opm/simulators/wells/WellTest.cpp b/opm/simulators/wells/WellTest.cpp index d4c4e3a72..d43ba8866 100644 --- a/opm/simulators/wells/WellTest.cpp +++ b/opm/simulators/wells/WellTest.cpp @@ -310,6 +310,7 @@ updateWellTestStateEconomic(const SingleWellState& ws, const double simulation_time, const bool write_message_to_opmlog, WellTestState& well_test_state, + const bool zero_group_target, DeferredLogger& deferred_logger) const { if (well_.wellIsStopped()) @@ -346,9 +347,10 @@ updateWellTestStateEconomic(const SingleWellState& ws, deferred_logger); } else { - rate_limit_violated = this->checkRateEconLimits(econ_production_limits, - ws.surface_rates, - deferred_logger); + if (!zero_group_target) { + rate_limit_violated + = this->checkRateEconLimits(econ_production_limits, ws.surface_rates, deferred_logger); + } } } diff --git a/opm/simulators/wells/WellTest.hpp b/opm/simulators/wells/WellTest.hpp index 52bd8c4b4..38933c0c0 100644 --- a/opm/simulators/wells/WellTest.hpp +++ b/opm/simulators/wells/WellTest.hpp @@ -48,6 +48,7 @@ public: const double simulation_time, const bool write_message_to_opmlog, WellTestState& well_test_state, + bool zero_group_target, DeferredLogger& deferred_logger) const; void updateWellTestStatePhysical(const double simulation_time,