From 23225d24e5ed34baefff947ebe6b8ac822365640 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Wed, 3 Nov 2021 15:52:21 +0100 Subject: [PATCH 1/2] Fix bug in runOptimize1_ --- opm/simulators/wells/GasLiftSingleWellGeneric.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 17dc4ed16..30a87c864 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -843,15 +843,15 @@ GasLiftSingleWellGeneric:: runOptimize1_() { std::unique_ptr state; - auto inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_); - auto dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_); + int inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_); + int dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_); if (dec_count == 0 && inc_count == 0) { state = tryIncreaseLiftGas_(); - if (!state && !state->alqChanged()) { + if (!state || !(state->alqChanged())) { state = tryDecreaseLiftGas_(); } } - else if (dec_count == 0) { + else if (dec_count == 0) { assert(inc_count > 0); state = tryIncreaseLiftGas_(); } From d2fd5505ca9b43b86b0d549a682c5d8c01dc50f5 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Thu, 4 Nov 2021 13:12:05 +0100 Subject: [PATCH 2/2] Check group production LRAT and WRAT targets --- .../wells/BlackoilWellModel_impl.hpp | 8 +- opm/simulators/wells/GasLiftGroupInfo.cpp | 72 +++-- opm/simulators/wells/GasLiftGroupInfo.hpp | 33 ++- .../wells/GasLiftSingleWellGeneric.cpp | 276 +++++++++++++++--- .../wells/GasLiftSingleWellGeneric.hpp | 28 +- 5 files changed, 335 insertions(+), 82 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index c9ef4e0b1..3bf4a9134 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -948,12 +948,15 @@ namespace Opm { group_oil_rates.reserve(num_rates_to_sync); std::vector group_gas_rates; group_gas_rates.reserve(num_rates_to_sync); + std::vector group_water_rates; + group_water_rates.reserve(num_rates_to_sync); if (comm.rank() == i) { for (auto idx : groups_to_sync) { - auto [oil_rate, gas_rate, alq] = group_info.getRates(idx); + auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx); group_indexes.push_back(idx); group_oil_rates.push_back(oil_rate); group_gas_rates.push_back(gas_rate); + group_water_rates.push_back(water_rate); group_alq_rates.push_back(alq); } } @@ -968,11 +971,12 @@ namespace Opm { comm.broadcast(group_indexes.data(), num_rates_to_sync, i); comm.broadcast(group_oil_rates.data(), num_rates_to_sync, i); comm.broadcast(group_gas_rates.data(), num_rates_to_sync, i); + comm.broadcast(group_water_rates.data(), num_rates_to_sync, i); comm.broadcast(group_alq_rates.data(), num_rates_to_sync, i); if (comm.rank() != i) { for (int j=0; j +std::tuple GasLiftGroupInfo:: getRates(int group_idx) { const auto& group_name = groupIdxToName(group_idx); auto& rates = this->group_rate_map_.at(group_name); - return std::make_tuple(rates.oilRate(), rates.gasRate(), rates.alq()); + return std::make_tuple(rates.oilRate(), rates.gasRate(), rates.waterRate(), rates.alq()); } std::vector>& @@ -165,22 +165,46 @@ oilTarget(const std::string &group_name) return group_rate.oilTarget(); } -void +double GasLiftGroupInfo:: -update( - const std::string &group_name, double delta_oil, double delta_gas, double delta_alq) +waterRate(const std::string &group_name) { auto& group_rate = this->group_rate_map_.at(group_name); - group_rate.update(delta_oil, delta_gas, delta_alq); + return group_rate.waterRate(); +} + +std::optional +GasLiftGroupInfo:: +waterTarget(const std::string &group_name) +{ + auto& group_rate = this->group_rate_map_.at(group_name); + return group_rate.waterTarget(); +} + +std::optional +GasLiftGroupInfo:: +liquidTarget(const std::string &group_name) +{ + auto& group_rate = this->group_rate_map_.at(group_name); + return group_rate.liquidTarget(); } void GasLiftGroupInfo:: -updateRate(int idx, double oil_rate, double gas_rate, double alq) +update( + const std::string &group_name, double delta_oil, double delta_gas, double delta_water, double delta_alq) +{ + auto& group_rate = this->group_rate_map_.at(group_name); + group_rate.update(delta_oil, delta_gas, delta_water, delta_alq); +} + +void +GasLiftGroupInfo:: +updateRate(int idx, double oil_rate, double gas_rate, double water_rate, double alq) { const auto& group_name = groupIdxToName(idx); auto& rates = this->group_rate_map_.at(group_name); - rates.assign(oil_rate, gas_rate, alq); + rates.assign(oil_rate, gas_rate, water_rate, alq); } /**************************************** @@ -295,7 +319,7 @@ displayDebugMessage_(const std::string &msg, const std::string &well_name) } -std::pair +std::tuple GasLiftGroupInfo:: getProducerWellRates_(int well_index) { @@ -311,14 +335,19 @@ getProducerWellRates_(int well_index) ? -wrate[pu.phase_pos[Gas]] : 0.0; - return {oil_rate, gas_rate}; + const auto water_rate = pu.phase_used[Water] + ? -wrate[pu.phase_pos[Water]] + : 0.0; + + return {oil_rate, gas_rate, water_rate}; } -std::tuple +std::tuple GasLiftGroupInfo:: initializeGroupRatesRecursive_(const Group &group) { double oil_rate = 0.0; + double water_rate = 0.0; double gas_rate = 0.0; double alq = 0.0; if (group.wellgroup()) { @@ -335,17 +364,19 @@ initializeGroupRatesRecursive_(const Group &group) assert(well); // Should never be nullptr const int index = (itr->second).second; if (well->isProducer()) { - auto [sw_oil_rate, sw_gas_rate] = getProducerWellRates_(index); + auto [sw_oil_rate, sw_gas_rate, sw_water_rate] = getProducerWellRates_(index); auto sw_alq = this->well_state_.getALQ(well_name); double factor = well->getEfficiencyFactor(); oil_rate += (factor * sw_oil_rate); gas_rate += (factor * sw_gas_rate); + water_rate += (factor * sw_water_rate); alq += (factor * sw_alq); } } } oil_rate = this->comm_.sum(oil_rate); gas_rate = this->comm_.sum(gas_rate); + water_rate = this->comm_.sum(water_rate); alq = this->comm_.sum(alq); } else { @@ -354,33 +385,40 @@ initializeGroupRatesRecursive_(const Group &group) continue; const Group& sub_group = this->schedule_.getGroup( group_name, this->report_step_idx_); - auto [sg_oil_rate, sg_gas_rate, sg_alq] + auto [sg_oil_rate, sg_gas_rate, sg_water_rate, sg_alq] = initializeGroupRatesRecursive_(sub_group); const auto gefac = sub_group.getGroupEfficiencyFactor(); oil_rate += (gefac * sg_oil_rate); gas_rate += (gefac * sg_gas_rate); + water_rate += (gefac * sg_water_rate); alq += (gefac * sg_alq); } } - std::optional oil_target, gas_target, max_total_gas, max_alq; + std::optional oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq; const auto controls = group.productionControls(this->summary_state_); + if (group.has_control(Group::ProductionCMode::LRAT)) { + liquid_target = controls.liquid_target; + } if (group.has_control(Group::ProductionCMode::ORAT)) { oil_target = controls.oil_target; } if (group.has_control(Group::ProductionCMode::GRAT)) { gas_target = controls.gas_target; } + if (group.has_control(Group::ProductionCMode::WRAT)) { + water_target = controls.water_target; + } if (this->glo_.has_group(group.name())) { const auto &gl_group = this->glo_.group(group.name()); max_alq = gl_group.max_lift_gas(); max_total_gas = gl_group.max_total_gas(); } - if (oil_target || gas_target || max_total_gas || max_alq) { + if (oil_target || liquid_target || water_target || gas_target || max_total_gas || max_alq) { updateGroupIdxMap_(group.name()); this->group_rate_map_.try_emplace(group.name(), - oil_rate, gas_rate, alq, oil_target, gas_target, max_total_gas, max_alq); + oil_rate, gas_rate, water_rate, alq, oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq); } - return std::make_tuple(oil_rate, gas_rate, alq); + return std::make_tuple(oil_rate, gas_rate, water_rate, alq); } void diff --git a/opm/simulators/wells/GasLiftGroupInfo.hpp b/opm/simulators/wells/GasLiftGroupInfo.hpp index 79f04bc62..fc0d30048 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.hpp +++ b/opm/simulators/wells/GasLiftGroupInfo.hpp @@ -84,25 +84,28 @@ public: double alqRate(const std::string& group_name); double gasRate(const std::string& group_name); int getGroupIdx(const std::string& group_name); - std::tuple getRates(int group_idx); + std::tuple getRates(int group_idx); std::optional gasTarget(const std::string& group_name); const std::string& groupIdxToName(int group_idx); bool hasWell(const std::string& well_name); void initialize(); std::optional maxAlq(const std::string& group_name); double oilRate(const std::string& group_name); + double waterRate(const std::string& group_name); std::optional oilTarget(const std::string& group_name); + std::optional waterTarget(const std::string& group_name); + std::optional liquidTarget(const std::string& group_name); void update(const std::string& well_name, - double delta_oil, double delta_gas, double delta_alq); - void updateRate(int idx, double oil_rate, double gas_rate, double alq); + double delta_oil, double delta_gas, double delta_water, double delta_alq); + void updateRate(int idx, double oil_rate, double gas_rate, double water_rate, double alq); const Well2GroupMap& wellGroupMap() { return well_group_map_; } private: bool checkDoGasLiftOptimization_(const std::string& well_name); bool checkNewtonIterationIdxOk_(const std::string& well_name); void displayDebugMessage_(const std::string& msg); void displayDebugMessage_(const std::string& msg, const std::string& well_name); - std::pair getProducerWellRates_(const int index); - std::tuple + std::tuple getProducerWellRates_(const int index); + std::tuple initializeGroupRatesRecursive_(const Group &group); void initializeWell2GroupMapRecursive_( const Group& group, std::vector& group_names, @@ -112,44 +115,58 @@ private: class GroupRates { public: - GroupRates( double oil_rate, double gas_rate, double alq, + GroupRates( double oil_rate, double gas_rate, double water_rate, double alq, std::optional oil_target, std::optional gas_target, + std::optional water_target, + std::optional liquid_target, std::optional total_gas, std::optional max_alq ) : oil_rate_{oil_rate}, gas_rate_{gas_rate}, + water_rate_{water_rate}, alq_{alq}, oil_target_{oil_target}, gas_target_{gas_target}, + water_target_{water_target}, + liquid_target_{liquid_target}, total_gas_{total_gas}, max_alq_{max_alq} {} double alq() const { return alq_; } - void assign(double oil_rate, double gas_rate, double alq) + void assign(double oil_rate, double gas_rate, double water_rate, double alq) { oil_rate_ = oil_rate; gas_rate_ = gas_rate; + water_rate_ = water_rate; alq_ = alq; } double gasRate() const { return gas_rate_; } + double waterRate() const { return water_rate_; } std::optional gasTarget() const { return gas_target_; } + std::optional waterTarget() const { return water_target_; } std::optional maxAlq() const { return max_alq_; } double oilRate() const { return oil_rate_; } std::optional oilTarget() const { return oil_target_; } - void update(double delta_oil, double delta_gas, double delta_alq) + std::optional liquidTarget() const { return liquid_target_; } + + void update(double delta_oil, double delta_gas, double delta_water, double delta_alq) { oil_rate_ += delta_oil; gas_rate_ += delta_gas; + water_rate_ += delta_water; alq_ += delta_alq; } private: double oil_rate_; double gas_rate_; + double water_rate_; double alq_; std::optional oil_target_; std::optional gas_target_; + std::optional water_target_; + std::optional liquid_target_; std::optional total_gas_; std::optional max_alq_; }; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 30a87c864..65e80a28d 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -317,8 +317,9 @@ computeInitialWellRates_(std::vector& potentials) void GasLiftSingleWellGeneric:: -debugCheckNegativeGradient_(double grad, double alq, double new_alq, double oil_rate, - double new_oil_rate, double gas_rate, double new_gas_rate, bool increase) const +debugCheckNegativeGradient_(double grad, double alq, double new_alq, + double oil_rate, double new_oil_rate, + double gas_rate, double new_gas_rate, bool increase) const { { const std::string msg = fmt::format("calculating gradient: " @@ -471,6 +472,22 @@ getGasRateWithLimit_(const std::vector& potentials) const return { new_rate, limit}; } +std::pair +GasLiftSingleWellGeneric:: +getWaterRateWithLimit_(const std::vector& potentials) const +{ + double new_rate = -potentials[this->water_pos_]; + bool limit = false; + if (this->controls_.hasControl(Well::ProducerCMode::WRAT)) { + auto target = this->controls_.water_rate; + if (new_rate > target) { + new_rate = target; + limit = true; + } + } + return { new_rate, limit}; +} + // NOTE: If the computed oil rate is larger than the target // rate of the well, we reduce it to the target rate. This // will make the economic gradient smaller than it would be @@ -484,44 +501,152 @@ std::pair GasLiftSingleWellGeneric:: getOilRateWithLimit_(const std::vector& potentials) const { - double new_rate = -potentials[this->oil_pos_]; + double oil_rate = -potentials[this->oil_pos_]; + double new_rate = oil_rate; + bool limited = false; if (this->controls_.hasControl(Well::ProducerCMode::ORAT)) { auto target = this->controls_.oil_rate; - if (new_rate > target) { + if (oil_rate > target) { const std::string msg = fmt::format("limiting oil rate to target: " "computed rate: {}, target: {}", new_rate, target); displayDebugMessage_(msg); new_rate = target; - return { new_rate, /*limit=*/true}; + limited = true; } } - // TODO: What to do if both oil and lrat are violated? - // Currently oil rate violation takes precedence if both are - // violated, and the new rate is set to the oil rate target. if (this->controls_.hasControl(Well::ProducerCMode::LRAT)) { auto target = this->controls_.liquid_rate; - auto oil_rate = -potentials[this->oil_pos_]; - auto water_rate = -potentials[this->water_pos_]; - auto liq_rate = oil_rate + water_rate; + double water_rate = -potentials[this->water_pos_]; + double liq_rate = oil_rate + water_rate; if (liq_rate > target) { - new_rate = oil_rate * (target/liq_rate); + double oil_fraction = oil_rate / liq_rate; + new_rate = std::min(new_rate, oil_fraction * target); + limited = true; const std::string msg = fmt::format( - "limiting oil rate due to LRAT target {}: " - "computed rate: {}, target: {}", target, oil_rate, new_rate); + "limiting oil rate due to LRAT target: " + "computed rate: {}, target: {}", oil_rate, new_rate); displayDebugMessage_(msg); - return { new_rate, /*limit=*/true}; } } - return { new_rate, /*limit=*/false}; + return { new_rate, limited}; } -std::tuple + +std::pair +GasLiftSingleWellGeneric:: +getOilRateWithGroupLimit_(const double new_oil_rate, const double oil_rate) const +{ + const double delta_oil = new_oil_rate - oil_rate; + const auto &pairs = + this->group_info_.getWellGroups(this->well_name_); + for (const auto &[group_name, efficiency] : pairs) { + auto gr_oil_target_opt = this->group_info_.oilTarget(group_name); + if (gr_oil_target_opt) { + double gr_oil_rate = + this->group_info_.oilRate(group_name); + double new_gr_oil_rate = gr_oil_rate + efficiency * delta_oil; + if (new_gr_oil_rate > *gr_oil_target_opt) { + const std::string msg = fmt::format("limiting oil rate to group target: " + "computed group rate: {}, target: {}", new_gr_oil_rate, *gr_oil_target_opt); + displayDebugMessage_(msg); + double new_rate = oil_rate + (*gr_oil_target_opt - gr_oil_rate) / efficiency; + return { std::min(new_rate, new_oil_rate), /*limit=*/true}; + } + } + } + return { new_oil_rate, /*limit=*/false}; +} + +std::pair +GasLiftSingleWellGeneric:: +getGasRateWithGroupLimit_(const double new_gas_rate, const double gas_rate) const +{ + const double delta_gas = new_gas_rate - gas_rate; + const auto &pairs = + this->group_info_.getWellGroups(this->well_name_); + for (const auto &[group_name, efficiency] : pairs) { + auto gr_gas_target_opt = this->group_info_.gasTarget(group_name); + if (gr_gas_target_opt) { + double gr_gas_rate = + this->group_info_.gasRate(group_name); + double new_gr_gas_rate = gr_gas_rate + efficiency * delta_gas; + if (new_gr_gas_rate > *gr_gas_target_opt) { + const std::string msg = fmt::format("limiting gas rate to group target: " + "computed group rate: {}, target: {}", new_gr_gas_rate, *gr_gas_target_opt); + displayDebugMessage_(msg); + double new_rate = gas_rate + (*gr_gas_target_opt - gr_gas_rate) / efficiency; + return { std::min(new_rate, new_gas_rate), /*limit=*/true}; + } + } + } + return { new_gas_rate, /*limit=*/false}; +} + +std::pair +GasLiftSingleWellGeneric:: +getWaterRateWithGroupLimit_(const double new_water_rate, const double water_rate) const +{ + const double delta_water = new_water_rate - water_rate; + const auto &pairs = + this->group_info_.getWellGroups(this->well_name_); + for (const auto &[group_name, efficiency] : pairs) { + auto gr_water_target_opt = this->group_info_.waterTarget(group_name); + if (gr_water_target_opt) { + double gr_water_rate = + this->group_info_.waterRate(group_name); + double new_gr_water_rate = gr_water_rate + efficiency * delta_water; + if (new_gr_water_rate > *gr_water_target_opt) { + const std::string msg = fmt::format("limiting water rate to group target: " + "computed group rate: {}, target: {}", new_gr_water_rate, *gr_water_target_opt); + displayDebugMessage_(msg); + double new_rate = water_rate + (*gr_water_target_opt - gr_water_rate) / efficiency; + return { std::min(new_rate, new_water_rate), /*limit=*/true}; + } + } + } + return { new_water_rate, /*limit=*/false}; +} + +std::tuple +GasLiftSingleWellGeneric:: +getLiquidRateWithGroupLimit_(const double new_oil_rate, const double oil_rate, + const double new_water_rate, const double water_rate) const +{ + const double delta_water = new_water_rate - water_rate; + const double delta_oil = new_oil_rate - oil_rate; + const auto &pairs = + this->group_info_.getWellGroups(this->well_name_); + for (const auto &[group_name, efficiency] : pairs) { + auto gr_liquid_target_opt = this->group_info_.liquidTarget(group_name); + if (gr_liquid_target_opt) { + double gr_water_rate = + this->group_info_.waterRate(group_name); + double gr_oil_rate = + this->group_info_.oilRate(group_name); + double new_gr_water_rate = gr_water_rate + efficiency * delta_water; + double new_gr_oil_rate = gr_oil_rate + efficiency * delta_oil; + double new_gr_liquid_rate = new_gr_water_rate + new_gr_oil_rate; + if (new_gr_liquid_rate > *gr_liquid_target_opt) { + const std::string msg = fmt::format("limiting liquid rate to group target: " + "computed group rate: {}, target: {}", new_gr_liquid_rate, *gr_liquid_target_opt); + displayDebugMessage_(msg); + double oil_fraction = new_gr_oil_rate / new_gr_liquid_rate; + double water_rate_limited = water_rate + (1.0 - oil_fraction) * (new_gr_liquid_rate - *gr_liquid_target_opt) / efficiency; + double oil_rate_limited = oil_rate + oil_fraction * (new_gr_liquid_rate - *gr_liquid_target_opt) / efficiency; + return { std::min(oil_rate_limited, new_oil_rate), std::min(water_rate_limited, new_water_rate), /*limit=*/true, /*limit=*/true}; + } + } + } + return { new_oil_rate, new_water_rate, /*limit=*/false, /*limit=*/false}; +} + +std::tuple GasLiftSingleWellGeneric:: getInitialRatesWithLimit_(const std::vector& potentials) { auto [oil_rate, oil_is_limited] = getOilRateWithLimit_(potentials); auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(potentials); - + auto [water_rate, water_is_limited] = getWaterRateWithLimit_(potentials); if (oil_is_limited) { const std::string msg = fmt::format( "initial oil rate was limited to: {}", oil_rate); @@ -532,7 +657,12 @@ getInitialRatesWithLimit_(const std::vector& potentials) "initial gas rate was limited to: {}", gas_rate); displayDebugMessage_(msg); } - return std::make_tuple(oil_rate, gas_rate, oil_is_limited, gas_is_limited); + if (water_is_limited) { + const std::string msg = fmt::format( + "initial water rate was limited to: {}", water_rate); + displayDebugMessage_(msg); + } + return std::make_tuple(oil_rate, gas_rate, water_rate, oil_is_limited, gas_is_limited, water_is_limited); } std::tuple @@ -605,11 +735,11 @@ logSuccess_(double alq, const int iteration_idx) this->deferred_logger_.info(message); } -std::tuple +std::tuple GasLiftSingleWellGeneric:: maybeAdjustALQbeforeOptimizeLoop_( - bool increase, double alq, double oil_rate, double gas_rate, - bool oil_is_limited, bool gas_is_limited, + bool increase, double alq, double oil_rate, double gas_rate, double water_rate, + bool oil_is_limited, bool gas_is_limited,bool water_is_limited, std::vector &potentials) { double orig_alq = alq; @@ -646,7 +776,7 @@ maybeAdjustALQbeforeOptimizeLoop_( const std::string msg = fmt::format("adjusted ALQ to: {}", alq); displayDebugMessage_(msg); } - return std::make_tuple(oil_rate, gas_rate, alq, oil_is_limited, gas_is_limited); + return std::make_tuple(oil_rate, gas_rate, water_rate, alq, oil_is_limited, gas_is_limited, water_is_limited); } std::tuple @@ -720,40 +850,46 @@ runOptimizeLoop_(bool increase) bool alq_is_limited = false; bool oil_is_limited = false; bool gas_is_limited = false; - double oil_rate, gas_rate; - std::tie(oil_rate, gas_rate, oil_is_limited, gas_is_limited) = + bool water_is_limited = false; + double oil_rate, gas_rate, water_rate; + std::tie(oil_rate, gas_rate, water_rate, oil_is_limited, gas_is_limited, water_is_limited) = getInitialRatesWithLimit_(potentials); //if (this->debug_) debugShowBhpAlqTable_(); if (this->debug_) debugShowAlqIncreaseDecreaseCounts_(); if (this->debug_) debugShowTargets_(); bool success = false; // did we succeed to increase alq? auto cur_alq = this->orig_alq_; - double new_oil_rate, new_gas_rate, new_alq; - bool new_oil_is_limited, new_gas_is_limited; - std::tie(new_oil_rate, new_gas_rate, new_alq, new_oil_is_limited, new_gas_is_limited) + double new_oil_rate, new_gas_rate, new_water_rate, new_alq; + bool new_oil_is_limited, new_gas_is_limited, new_water_is_limited; + std::tie(new_oil_rate, new_gas_rate, new_water_rate, new_alq, + new_oil_is_limited, new_gas_is_limited, new_water_is_limited) = maybeAdjustALQbeforeOptimizeLoop_( - increase, cur_alq, oil_rate, gas_rate, - oil_is_limited, gas_is_limited, potentials); + increase, cur_alq, oil_rate, gas_rate, water_rate, + oil_is_limited, gas_is_limited, water_is_limited, potentials); double delta_oil = 0.0; double delta_gas = 0.0; double delta_alq = 0.0; + double delta_water = 0.0; OptimizeState state {*this, increase}; // potentially reduce alq if group control is violated - std::tie(new_oil_rate, new_gas_rate, new_alq) = - state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, potentials); + std::tie(new_oil_rate, new_gas_rate, new_water_rate, new_alq) = + state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, new_water_rate, potentials); if (checkInitialALQmodified_(new_alq, cur_alq)) { delta_oil = new_oil_rate - oil_rate; delta_gas = new_gas_rate - gas_rate; + delta_water = new_water_rate - water_rate; delta_alq = new_alq - cur_alq; - if (!(state.checkGroupTargetsViolated(delta_oil, delta_gas)) && + if (!(state.checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) && !(state.checkGroupALQrateExceeded(delta_alq))) { oil_rate = new_oil_rate; gas_rate = new_gas_rate; + water_rate = new_water_rate; oil_is_limited = new_oil_is_limited; gas_is_limited = new_gas_is_limited; + water_is_limited = new_water_is_limited; cur_alq = new_alq; success = true; } @@ -771,7 +907,7 @@ runOptimizeLoop_(bool increase) while (!state.stop_iteration && (++state.it <= this->max_iterations_)) { if (!increase && state.checkNegativeOilRate(oil_rate)) break; if (state.checkWellRatesViolated(potentials)) break; - if (state.checkGroupTargetsViolated(delta_oil, delta_gas)) break; + if (state.checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) break; if (state.checkAlqOutsideLimits(temp_alq, oil_rate)) break; std::optional alq_opt; std::tie(alq_opt, alq_is_limited) @@ -786,6 +922,8 @@ runOptimizeLoop_(bool increase) auto bhp = state.getBhpWithLimit(); computeWellRates_(bhp, potentials); std::tie(new_oil_rate, new_oil_is_limited) = getOilRateWithLimit_(potentials); + std::tie(new_oil_rate, new_oil_is_limited) = getOilRateWithGroupLimit_(new_oil_rate, oil_rate); + /* if (this->debug_abort_if_decrease_and_oil_is_limited_) { if (oil_is_limited && !increase) { // if oil is limited we do not want to decrease @@ -796,6 +934,15 @@ runOptimizeLoop_(bool increase) } */ std::tie(new_gas_rate, new_gas_is_limited) = getGasRateWithLimit_(potentials); + std::tie(new_gas_rate, new_gas_is_limited) = getGasRateWithGroupLimit_(new_gas_rate, gas_rate); + + std::tie(new_water_rate, new_water_is_limited) = getWaterRateWithLimit_(potentials); + std::tie(new_water_rate, new_water_is_limited) = getWaterRateWithGroupLimit_(new_water_rate, water_rate); + + std::tie(new_oil_rate, new_water_rate, new_oil_is_limited, new_water_is_limited) + = getLiquidRateWithGroupLimit_(new_oil_rate, oil_rate, new_water_rate, water_rate); + + /* if (this->debug_abort_if_increase_and_gas_is_limited_) { if (gas_is_limited && increase) { // if gas is limited we do not want to increase @@ -816,11 +963,14 @@ runOptimizeLoop_(bool increase) success = true; delta_oil = new_oil_rate - oil_rate; delta_gas = new_gas_rate - gas_rate; + delta_water = new_water_rate - water_rate; oil_rate = new_oil_rate; gas_rate = new_gas_rate; + water_rate = new_water_rate; oil_is_limited = new_oil_is_limited; gas_is_limited = new_gas_is_limited; - state.updateGroupRates(delta_oil, delta_gas, delta_alq); + water_is_limited = new_water_is_limited; + state.updateGroupRates(delta_oil, delta_gas, delta_water, delta_alq); } if (state.it > this->max_iterations_) { warnMaxIterationsExceeded_(); @@ -851,7 +1001,7 @@ runOptimize1_() state = tryDecreaseLiftGas_(); } } - else if (dec_count == 0) { + else if (dec_count == 0) { assert(inc_count > 0); state = tryIncreaseLiftGas_(); } @@ -1137,7 +1287,7 @@ checkGroupALQrateExceeded(double delta_alq) bool GasLiftSingleWellGeneric::OptimizeState:: -checkGroupTargetsViolated(double delta_oil, double delta_gas) +checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water) { const auto &pairs = this->parent.group_info_.getWellGroups(this->parent.well_name_); @@ -1170,19 +1320,49 @@ checkGroupTargetsViolated(double delta_oil, double delta_gas) return true; } } + auto liquid_target_opt = this->parent.group_info_.liquidTarget(group_name); + if (liquid_target_opt) { + double oil_rate = + this->parent.group_info_.oilRate(group_name) + efficiency * delta_oil; + double water_rate = + this->parent.group_info_.waterRate(group_name) + efficiency * delta_water; + double liquid_rate = oil_rate + water_rate; + if (liquid_rate > *liquid_target_opt) { + if (this->parent.debug_) { + const std::string msg = fmt::format( + "Group {} : liquid rate {} exceeds liquid target {}. Stopping iteration", + group_name, liquid_rate, *liquid_target_opt); + this->parent.displayDebugMessage_(msg); + } + return true; + } + } + auto water_target_opt = this->parent.group_info_.waterTarget(group_name); + if (water_target_opt) { + double water_rate = + this->parent.group_info_.waterRate(group_name) + efficiency * delta_water; + if (water_rate > *water_target_opt) { + if (this->parent.debug_) { + const std::string msg = fmt::format( + "Group {} : water rate {} exceeds water target {}. Stopping iteration", + group_name, water_rate, *water_target_opt); + this->parent.displayDebugMessage_(msg); + } + return true; + } + } } return false; } -std::tuple +std::tuple GasLiftSingleWellGeneric::OptimizeState:: reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, + double water_rate, std::vector& potentials) { - // Note: Currently the checkGroupTargetsViolated only check - // for GRAT and ORAT group controls. bool stop_this_iteration = true; const auto &pairs = this->parent.group_info_.getWellGroups(this->parent.well_name_); @@ -1190,7 +1370,10 @@ reduceALQtoGroupTarget(double alq, if (!this->parent.group_state_.has_production_control(groups.first)) continue; const auto& current_control = this->parent.group_state_.production_control(groups.first); - if(current_control == Group::ProductionCMode::ORAT || current_control == Group::ProductionCMode::GRAT){ + if(current_control == Group::ProductionCMode::ORAT + || current_control == Group::ProductionCMode::LRAT + || current_control == Group::ProductionCMode::WRAT + || current_control == Group::ProductionCMode::GRAT){ stop_this_iteration = false; this->parent.displayDebugMessage_("Reducing ALQ to meet groups target before iteration starts."); break; @@ -1199,6 +1382,7 @@ reduceALQtoGroupTarget(double alq, double temp_alq = alq; double oil_rate_orig = oil_rate; double gas_rate_orig = gas_rate; + double water_rate_orig = water_rate; while(!stop_this_iteration) { temp_alq -= this->parent.increment_; if (temp_alq <= 0) break; @@ -1208,15 +1392,17 @@ reduceALQtoGroupTarget(double alq, this->parent.computeWellRates_(bhp_this.first, potentials); oil_rate = -potentials[this->parent.oil_pos_]; gas_rate = -potentials[this->parent.gas_pos_]; + water_rate = -potentials[this->parent.gas_pos_]; double delta_oil = oil_rate_orig - oil_rate; double delta_gas = gas_rate_orig - gas_rate; + double delta_water = water_rate_orig - water_rate; - if (!this->checkGroupTargetsViolated(delta_oil, delta_gas)) { + if (!this->checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) { break; } alq = temp_alq; } - return std::make_tuple(oil_rate, gas_rate, alq); + return std::make_tuple(oil_rate, gas_rate, water_rate, alq); } bool GasLiftSingleWellGeneric::OptimizeState:: @@ -1367,7 +1553,7 @@ getBhpWithLimit() void GasLiftSingleWellGeneric::OptimizeState:: -updateGroupRates(double delta_oil, double delta_gas, double delta_alq) +updateGroupRates(double delta_oil, double delta_gas, double delta_water, double delta_alq) { const auto &pairs = this->parent.group_info_.getWellGroups(this->parent.well_name_); @@ -1375,7 +1561,7 @@ updateGroupRates(double delta_oil, double delta_gas, double delta_alq) int idx = this->parent.group_info_.getGroupIdx(group_name); this->parent.sync_groups_.insert(idx); this->parent.group_info_.update(group_name, - efficiency * delta_oil, efficiency * delta_gas, efficiency * delta_alq); + efficiency * delta_oil, efficiency * delta_gas, efficiency * delta_water, efficiency * delta_alq); } } diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp index 844e86260..988028c97 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp @@ -126,9 +126,9 @@ protected: bool checkAlqOutsideLimits(double alq, double oil_rate); bool checkEcoGradient(double gradient); bool checkGroupALQrateExceeded(double delta_alq); - bool checkGroupTargetsViolated(double delta_oil, double delta_gas); - std::tuple - reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, std::vector &potentials); + bool checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water); + std::tuple + reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, double water_rate, std::vector &potentials); bool checkNegativeOilRate(double oil_rate); bool checkThpControl(); bool checkOilRateExceedsTarget(double oil_rate); @@ -137,7 +137,7 @@ protected: bool computeBhpAtThpLimit(double alq); void debugShowIterationInfo(double alq); double getBhpWithLimit(); - void updateGroupRates(double delta_oil, double delta_gas, double delta_alq); + void updateGroupRates(double delta_oil, double delta_gas, double delta_water, double delta_alq); void warn_(std::string msg) {parent.displayWarning_(msg);} }; @@ -162,8 +162,9 @@ protected: bool computeInitialWellRates_(std::vector& potentials); void debugCheckNegativeGradient_(double grad, double alq, double new_alq, - double oil_rate, double new_oil_rate, double gas_rate, - double new_gas_rate, bool increase) const; + double oil_rate, double new_oil_rate, + double gas_rate, double new_gas_rate, + bool increase) const; void debugShowAlqIncreaseDecreaseCounts_(); @@ -178,9 +179,16 @@ protected: std::pair getBhpWithLimit_(double bhp) const; std::pair getGasRateWithLimit_(const std::vector& potentials) const; - std::tuple + std::tuple getInitialRatesWithLimit_(const std::vector& potentials); std::pair getOilRateWithLimit_(const std::vector& potentials) const; + std::pair getWaterRateWithLimit_(const std::vector& potentials) const; + + std::pair getOilRateWithGroupLimit_(const double new_oil_rate, const double oil_rate) const; + std::pair getGasRateWithGroupLimit_(const double new_gas_rate, const double gas_rate) const; + std::pair getWaterRateWithGroupLimit_(const double new_water_rate, const double water_rate) const; + std::tuple getLiquidRateWithGroupLimit_(double new_oil_rate, const double oil_rate, + double new_water_rate, const double water_rate) const; std::tuple increaseALQtoPositiveOilRate_(double alq, @@ -200,10 +208,10 @@ protected: void logSuccess_(double alq, const int iteration_idx); - std::tuple + std::tuple maybeAdjustALQbeforeOptimizeLoop_( - bool increase, double alq, double oil_rate, double gas_rate, - bool oil_is_limited, bool gas_is_limited, std::vector &potentials); + bool increase, double alq, double oil_rate, double gas_rate, double water_rate, + bool oil_is_limited, bool gas_is_limited, bool water_is_limited, std::vector &potentials); std::tuple reduceALQtoOilTarget_(double alq, double oil_rate, double gas_rate, bool oil_is_limited, bool gas_is_limited, std::vector &potentials);