From 61ed8037400c08278ba2447952bc86444dcaf935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Sun, 9 Oct 2022 17:47:48 +0200 Subject: [PATCH 01/11] Do stage2 even if GLIFTOPT is not defined --- .../wells/GasLiftSingleWellGeneric.cpp | 2 +- opm/simulators/wells/GasLiftStage2.cpp | 39 ++++++++++++------- opm/simulators/wells/GasLiftStage2.hpp | 2 + 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 65a6607f7..bced1e3a8 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -765,7 +765,7 @@ getRateWithGroupLimit_( const double delta_rate = new_rate - old_rate; if (delta_rate > 0) { // It is required that the production rate for a given group is - // is less than or equal to its target rate, see assert() below. + // is less than or equal to its target rate. // Then it only makes sense to check if the group target is exceeded // if delta_rate > 0 const auto &pairs = diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 422f7e134..627f7fbb5 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -403,6 +403,26 @@ getCurrentWellRates_(const std::string &well_name, const std::string &group_name return std::make_tuple(oil_rate, gas_rate, alq); } +std::optional +GasLiftStage2::getGroupMaxALQ_(const Group &group) +{ + if (this->glo_.has_group(group.name())) { + const auto &gl_group = this->glo_.group(group.name()); + return gl_group.max_lift_gas(); + } + return std::nullopt; // If GLIFTOPT is missing from schedule, assume unlimited alq +} + +std::optional +GasLiftStage2::getGroupMaxTotalGas_(const Group &group) +{ + if (this->glo_.has_group(group.name())) { + const auto &gl_group = this->glo_.group(group.name()); + return gl_group.max_total_gas(); + } + return std::nullopt; // If GLIFTOPT is missing from schedule, assume unlimited alq +} + std::pair GasLiftStage2:: getWellRates_(const WellInterfaceGeneric &well) @@ -517,9 +537,8 @@ void GasLiftStage2:: optimizeGroup_(const Group &group) { - const auto &gl_group = this->glo_.group(group.name()); - const auto &max_glift = gl_group.max_lift_gas(); - const auto &max_total_gas = gl_group.max_total_gas(); + const auto max_glift = getGroupMaxALQ_(group); + const auto max_total_gas = getGroupMaxTotalGas_(group); if (group.has_control(Group::ProductionCMode::ORAT) || max_glift || max_total_gas) { @@ -546,16 +565,7 @@ optimizeGroupsRecursive_(const Group &group) group_name, this->report_step_idx_); optimizeGroupsRecursive_(sub_group); } - // TODO: should we also optimize groups that do not have GLIFTOPT defined? - // (i.e. glo_.has_group(name) returns false) - // IF GLIFTOPT is not specified for the group or if item 2 of GLIFTOPT - // is defaulted, there is no maximum lift gas supply for the group. - // But even if there is no limit on the liftgas supply it can still - // be desireable to use as little ALQ as possible to achieve a - // group oil rate limit or gas rate limit. - if (this->glo_.has_group(group.name())) // only optimize if GLIFTOPT is given - optimizeGroup_(group); - + optimizeGroup_(group); } void @@ -718,8 +728,7 @@ removeSurplusALQ_(const Group &group, return; } assert(!dec_grads.empty()); - const auto &gl_group = this->glo_.group(group.name()); - const auto &max_glift = gl_group.max_lift_gas(); + const auto max_glift = getGroupMaxALQ_(group); const auto controls = group.productionControls(this->summary_state_); //const auto &max_total_gas = gl_group.max_total_gas(); auto [oil_rate, gas_rate, alq] = getCurrentGroupRates_(group); diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index e2ce7bcbb..660af32b7 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -92,6 +92,8 @@ protected: const Group& group); std::tuple getCurrentWellRates_( const std::string& well_name, const std::string& group_name); + std::optional getGroupMaxALQ_(const Group &group); + std::optional getGroupMaxTotalGas_(const Group &group); std::vector getGroupGliftWells_( const Group& group); void getGroupGliftWellsRecursive_( From bc566e3981dcad6b0b1fa351b7ba2d58d9453abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Mon, 10 Oct 2022 08:10:57 +0200 Subject: [PATCH 02/11] Also check LRAT group target in stage2 Also account for a group LRAT limit when removing surplus ALQ in gaslift optimization stage 2. --- .../wells/BlackoilWellModelGeneric.hpp | 2 +- opm/simulators/wells/GasLiftStage2.cpp | 103 ++++++++++++------ opm/simulators/wells/GasLiftStage2.hpp | 22 ++-- opm/simulators/wells/WellInterface_impl.hpp | 1 - 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 48fd43362..7ca81aafc 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -380,7 +380,7 @@ protected: WGState last_valid_wgstate_; WGState nupcol_wgstate_; - bool glift_debug = false; + bool glift_debug = true; double last_glift_opt_time_ = -1.0; diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 627f7fbb5..415eaf741 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -272,38 +272,40 @@ displayDebugMessage_(const std::string &msg, const std::string &group_name) } } -std::tuple +std::tuple GasLiftStage2:: getCurrentGroupRates_(const Group &group) { auto rates = getCurrentGroupRatesRecursive_(group); this->comm_.sum(rates.data(), rates.size()); - auto [oil_rate, gas_rate, alq] = rates; + auto [oil_rate, gas_rate, water_rate, alq] = rates; if (this->debug) { const std::string msg = fmt::format( - "Current group rates for {} : oil: {}, gas: {}, alq: {}", - group.name(), oil_rate, gas_rate, alq); + "Current group rates for {} : oil: {}, gas: {}, water: {}, alq: {}", + group.name(), oil_rate, gas_rate, water_rate, alq); displayDebugMessageOnRank0_(msg); } - return {oil_rate, gas_rate, alq}; + return {oil_rate, gas_rate, water_rate, alq}; } -std::array +std::array GasLiftStage2:: getCurrentGroupRatesRecursive_(const Group &group) { double oil_rate = 0.0; double gas_rate = 0.0; + double water_rate = 0.0; double alq = 0.0; // NOTE: A group can either contain wells or groups, but not both if (group.wellgroup()) { for (const std::string& well_name : group.wells()) { - auto [sw_oil_rate, sw_gas_rate, sw_alq] = + auto [sw_oil_rate, sw_gas_rate, sw_water_rate, sw_alq] = getCurrentWellRates_(well_name, group.name()); oil_rate += sw_oil_rate; gas_rate += sw_gas_rate; + water_rate += sw_water_rate; alq += sw_alq; } @@ -321,21 +323,22 @@ getCurrentGroupRatesRecursive_(const Group &group) // parent group. const auto gefac = sub_group.getGroupEfficiencyFactor(); auto rates = getCurrentGroupRatesRecursive_(sub_group); - auto [sg_oil_rate, sg_gas_rate, sg_alq] = rates; + auto [sg_oil_rate, sg_gas_rate, sg_water_rate, sg_alq] = rates; oil_rate += (gefac * sg_oil_rate); gas_rate += (gefac * sg_gas_rate); + water_rate += (gefac * sg_water_rate); alq += (gefac * sg_alq); } } } - return {oil_rate, gas_rate, alq}; + return {oil_rate, gas_rate, water_rate, alq}; } -std::tuple +std::tuple GasLiftStage2:: getCurrentWellRates_(const std::string &well_name, const std::string &group_name) { - double oil_rate, gas_rate, alq; + double oil_rate, gas_rate, water_rate, alq; bool success = false; const WellInterfaceGeneric *well_ptr = nullptr; std::string debug_info; @@ -345,12 +348,13 @@ getCurrentWellRates_(const std::string &well_name, const std::string &group_name well_ptr = &well; GasLiftWellState &state = *(this->well_state_map_.at(well_name).get()); std::tie(oil_rate, gas_rate) = state.getRates(); + water_rate = state.waterRate(); success = true; if ( this->debug) debug_info = "(A)"; } else if (this->prod_wells_.count(well_name) == 1) { well_ptr = this->prod_wells_.at(well_name); - std::tie(oil_rate, gas_rate) = getWellRates_(*well_ptr); + std::tie(oil_rate, gas_rate, water_rate) = getWellRates_(*well_ptr); success = true; if ( this->debug) debug_info = "(B)"; } @@ -368,8 +372,8 @@ getCurrentWellRates_(const std::string &well_name, const std::string &group_name alq = this->well_state_.getALQ(well_name); if (this->debug) { const std::string msg = fmt::format( - "Rates {} for well {} : oil: {}, gas: {}, alq: {}", - debug_info, well_name, oil_rate, gas_rate, alq); + "Rates {} for well {} : oil: {}, gas: {}, water: {}, alq: {}", + debug_info, well_name, oil_rate, gas_rate, water_rate, alq); displayDebugMessage_(msg, group_name); } // If wells have efficiency factors to take account of regular @@ -383,11 +387,12 @@ getCurrentWellRates_(const std::string &well_name, const std::string &group_name double factor = well_ecl.getEfficiencyFactor(); oil_rate *= factor; gas_rate *= factor; + water_rate *= factor; alq *= factor; if (this->debug && (factor != 1)) { const std::string msg = fmt::format( - "Well {} : efficiency factor {}. New rates : oil: {}, gas: {}, alq: {}", - well_name, factor, oil_rate, gas_rate, alq); + "Well {} : efficiency factor {}. New rates : oil: {}, gas: {}, water: {}, alq: {}", + well_name, factor, oil_rate, gas_rate, water_rate, alq); displayDebugMessage_(msg, group_name); } } @@ -398,9 +403,9 @@ getCurrentWellRates_(const std::string &well_name, const std::string &group_name "well {}: (not active or injector)", well_name); displayDebugMessage_(msg, group_name); } - oil_rate = 0.0; gas_rate = 0.0; alq = 0.0; + oil_rate = 0.0; gas_rate = 0.0; water_rate = 0.0; alq = 0.0; } - return std::make_tuple(oil_rate, gas_rate, alq); + return std::make_tuple(oil_rate, gas_rate, water_rate, alq); } std::optional @@ -423,7 +428,7 @@ GasLiftStage2::getGroupMaxTotalGas_(const Group &group) return std::nullopt; // If GLIFTOPT is missing from schedule, assume unlimited alq } -std::pair +std::tuple GasLiftStage2:: getWellRates_(const WellInterfaceGeneric &well) { @@ -431,13 +436,14 @@ getWellRates_(const WellInterfaceGeneric &well) const auto& ws = this->well_state_.well(well_index); const auto& pu = well.phaseUsage(); auto oil_rate = ws.well_potentials[pu.phase_pos[Oil]]; + auto water_rate = ws.well_potentials[pu.phase_pos[Water]]; double gas_rate = 0.0; // See comment for setupPhaseVariables_() in GasLiftSingleWell_impl.hpp // about the two-phase oil-water case. if (pu.phase_used[BlackoilPhases::Vapour]) { gas_rate = ws.well_potentials[pu.phase_pos[Gas]]; } - return {oil_rate, gas_rate}; + return {oil_rate, gas_rate, water_rate}; } // Find all subordinate wells of a given group. @@ -539,7 +545,7 @@ optimizeGroup_(const Group &group) { const auto max_glift = getGroupMaxALQ_(group); const auto max_total_gas = getGroupMaxTotalGas_(group); - if (group.has_control(Group::ProductionCMode::ORAT) + if (group.has_control(Group::ProductionCMode::ORAT) || group.has_control(Group::ProductionCMode::LRAT) || max_glift || max_total_gas) { displayDebugMessage_("optimizing", group.name()); @@ -731,7 +737,7 @@ removeSurplusALQ_(const Group &group, const auto max_glift = getGroupMaxALQ_(group); const auto controls = group.productionControls(this->summary_state_); //const auto &max_total_gas = gl_group.max_total_gas(); - auto [oil_rate, gas_rate, alq] = getCurrentGroupRates_(group); + auto [oil_rate, gas_rate, water_rate, alq] = getCurrentGroupRates_(group); auto min_eco_grad = this->glo_.min_eco_gradient(); bool stop_iteration = false; if (this->debug) { @@ -739,12 +745,15 @@ removeSurplusALQ_(const Group &group, if (max_glift) max_glift_str = fmt::format("{}", *max_glift); const std::string msg = fmt::format("Starting iteration for group: {}. " "oil_rate = {}, oil_target = {}, gas_rate = {}, gas_target = {}, " - "alq = {}, max_alq = {}", group.name(), oil_rate, controls.oil_target, - gas_rate, controls.gas_target, alq, max_glift_str); + "water_rate = {}, liquid_target = {}, alq = {}, max_alq = {}", + group.name(), oil_rate, controls.oil_target, + gas_rate, controls.gas_target, water_rate, controls.liquid_target, + alq, max_glift_str); displayDebugMessage_(msg); } - SurplusState state {*this, group, oil_rate, gas_rate, alq, - min_eco_grad, controls.oil_target, controls.gas_target, max_glift }; + SurplusState state {*this, group, oil_rate, gas_rate, water_rate, alq, + min_eco_grad, controls.oil_target, controls.gas_target, + controls.liquid_target, max_glift }; while (!stop_iteration) { if (dec_grads.size() >= 2) { @@ -754,7 +763,9 @@ removeSurplusALQ_(const Group &group, const auto well_name = dec_grad_itr->first; auto eco_grad = dec_grad_itr->second; bool remove = false; - if (state.checkOilTarget() || state.checkGasTarget() || state.checkALQlimit()) { + if (state.checkOilTarget() || state.checkGasTarget() + || state.checkLiquidTarget() || state.checkALQlimit()) + { remove = true; } else { @@ -786,11 +797,11 @@ removeSurplusALQ_(const Group &group, } if (state.it >= 1) { if (this->debug) { - auto [oil_rate2, gas_rate2, alq2] = getCurrentGroupRates_(group); + auto [oil_rate2, gas_rate2, water_rate2, alq2] = getCurrentGroupRates_(group); const std::string msg = fmt::format( "Finished after {} iterations for group: {}." - " oil_rate = {}, gas_rate = {}, alq = {}", state.it, - group.name(), oil_rate2, gas_rate2, alq2); + " oil_rate = {}, gas_rate = {}, water_rate = {}, alq = {}", state.it, + group.name(), oil_rate2, gas_rate2, water_rate2, alq2); displayDebugMessage_(msg); } } @@ -1084,6 +1095,24 @@ checkGasTarget() } return false; } +bool +GasLiftStage2::SurplusState:: +checkLiquidTarget() +{ + if (this->group.has_control(Group::ProductionCMode::LRAT)) { + auto liquid_rate = this->oil_rate + this->water_rate; + if (this->liquid_target < liquid_rate ) { + if (this->parent.debug) { + const std::string msg = fmt::format("group: {} : " + "liquid rate {} is greater than liquid target {}", this->group.name(), + liquid_rate, this->liquid_target); + this->parent.displayDebugMessage_(msg); + } + return true; + } + } + return false; +} bool GasLiftStage2::SurplusState:: @@ -1107,7 +1136,7 @@ void GasLiftStage2::SurplusState:: updateRates(const std::string &well_name) { - std::array delta = {0.0,0.0,0.0}; + std::array delta = {0.0, 0.0, 0.0, 0.0}; // compute the delta on wells on own rank if (this->parent.well_state_map_.count(well_name) > 0) { const GradInfo &gi = this->parent.dec_grads_.at(well_name); @@ -1118,10 +1147,11 @@ updateRates(const std::string &well_name) if (this->parent.well_state_.wellIsOwned(well.indexOfWell(), well_name)) { const auto &well_ecl = well.wellEcl(); double factor = well_ecl.getEfficiencyFactor(); - auto& [delta_oil, delta_gas, delta_alq] = delta; - delta_oil = factor * (gi.new_oil_rate - state.oilRate()); - delta_gas = factor * (gi.new_gas_rate - state.gasRate()); - delta_alq = factor * (gi.alq - state.alq()); + auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta; + delta_oil = factor * (gi.new_oil_rate - state.oilRate()); + delta_gas = factor * (gi.new_gas_rate - state.gasRate()); + delta_water = factor * (gi.new_water_rate - state.waterRate()); + delta_alq = factor * (gi.alq - state.alq()); } } @@ -1129,9 +1159,10 @@ updateRates(const std::string &well_name) this->parent.comm_.sum(delta.data(), delta.size()); // and update - const auto& [delta_oil, delta_gas, delta_alq] = delta; + const auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta; this->oil_rate += delta_oil; this->gas_rate += delta_gas; + this->water_rate += delta_water; this->alq += delta_alq; } diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index 660af32b7..ba86770d6 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -86,11 +86,9 @@ protected: void displayDebugMessage_(const std::string& msg, const std::string& group_name); void displayWarning_(const std::string& msg, const std::string& group_name); void displayWarning_(const std::string& msg); - std::tuple getCurrentGroupRates_( - const Group& group); - std::array getCurrentGroupRatesRecursive_( - const Group& group); - std::tuple getCurrentWellRates_( + std::tuple getCurrentGroupRates_(const Group& group); + std::array getCurrentGroupRatesRecursive_(const Group& group); + std::tuple getCurrentWellRates_( const std::string& well_name, const std::string& group_name); std::optional getGroupMaxALQ_(const Group &group); std::optional getGroupMaxTotalGas_(const Group &group); @@ -98,7 +96,7 @@ protected: const Group& group); void getGroupGliftWellsRecursive_( const Group& group, std::vector& wells); - std::pair getWellRates_(const WellInterfaceGeneric& well); + std::tuple getWellRates_(const WellInterfaceGeneric& well); void optimizeGroup_(const Group& group); void optimizeGroupsRecursive_(const Group& group); void recalculateGradientAndUpdateData_( @@ -171,17 +169,20 @@ protected: struct SurplusState { SurplusState( GasLiftStage2& parent_, const Group& group_, - double oil_rate_, double gas_rate_, double alq_, double min_eco_grad_, - double oil_target_, double gas_target_, - std::optional max_glift_) : + double oil_rate_, double gas_rate_, double water_rate_, double alq_, + double min_eco_grad_, + double oil_target_, double gas_target_, double liquid_target_, + std::optional max_glift_) : parent{parent_}, group{group_}, oil_rate{oil_rate_}, gas_rate{gas_rate_}, + water_rate{water_rate_}, alq{alq_}, min_eco_grad{min_eco_grad_}, oil_target{oil_target_}, gas_target{gas_target_}, + liquid_target{liquid_target_}, max_glift{max_glift_}, it{0} {} @@ -189,10 +190,12 @@ protected: const Group &group; double oil_rate; double gas_rate; + double water_rate; double alq; const double min_eco_grad; const double oil_target; const double gas_target; + const double liquid_target; std::optional max_glift; int it; @@ -201,6 +204,7 @@ protected: bool checkALQlimit(); bool checkEcoGradient(const std::string& well_name, double eco_grad); bool checkGasTarget(); + bool checkLiquidTarget(); bool checkOilTarget(); void updateRates(const std::string& name); }; diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index 51f07f1ad..7fd02ad39 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -346,7 +346,6 @@ namespace Opm deferred_logger.debug(msg); return; } - std::vector potentials; try { computeWellPotentials(simulator, well_state_copy, potentials, deferred_logger); From 9c61262329a783899adaa6539aad684e02d9ece0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Mon, 17 Oct 2022 22:02:06 +0200 Subject: [PATCH 03/11] Changed formatting. --- .../wells/BlackoilWellModelGeneric.hpp | 2 +- .../wells/GasLiftSingleWellGeneric.cpp | 1013 ++++++++--------- 2 files changed, 475 insertions(+), 540 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 7ca81aafc..48fd43362 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -380,7 +380,7 @@ protected: WGState last_valid_wgstate_; WGState nupcol_wgstate_; - bool glift_debug = true; + bool glift_debug = false; double last_glift_opt_time_ = -1.0; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index bced1e3a8..3e734bba2 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -25,8 +25,8 @@ #include #include -#include #include +#include #include @@ -37,29 +37,27 @@ namespace Opm { -GasLiftSingleWellGeneric::GasLiftSingleWellGeneric( - DeferredLogger& deferred_logger, - WellState& well_state, - const GroupState& group_state, - const Well& ecl_well, - const SummaryState& summary_state, - GasLiftGroupInfo& group_info, - const PhaseUsage& phase_usage, - const Schedule& schedule, - const int report_step_idx, - GLiftSyncGroups& sync_groups, - const Parallel::Communication& comm, - bool glift_debug -) : - GasLiftCommon(well_state, deferred_logger, comm, glift_debug) - , group_state_{group_state} - , ecl_well_{ecl_well} - , summary_state_{summary_state} - , group_info_{group_info} - , phase_usage_{phase_usage} - , sync_groups_{sync_groups} - , controls_{ecl_well_.productionControls(summary_state_)} - , debug_limit_increase_decrease_{false} +GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logger, + WellState& well_state, + const GroupState& group_state, + const Well& ecl_well, + const SummaryState& summary_state, + GasLiftGroupInfo& group_info, + const PhaseUsage& phase_usage, + const Schedule& schedule, + const int report_step_idx, + GLiftSyncGroups& sync_groups, + const Parallel::Communication& comm, + bool glift_debug) + : GasLiftCommon(well_state, deferred_logger, comm, glift_debug) + , group_state_ {group_state} + , ecl_well_ {ecl_well} + , summary_state_ {summary_state} + , group_info_ {group_info} + , phase_usage_ {phase_usage} + , sync_groups_ {sync_groups} + , controls_ {ecl_well_.productionControls(summary_state_)} + , debug_limit_increase_decrease_ {false} { this->well_name_ = ecl_well_.name(); const GasLiftOpt& glo = schedule.glo(report_step_idx); @@ -71,7 +69,7 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric( // NOTE: This condition was checked in doGasLiftOptimize() in StandardWell // so it can be assumed that increment_ > 0 this->increment_ = glo.gaslift_increment(); - assert( this->increment_ > 0); + assert(this->increment_ > 0); // NOTE: The manual (see LIFTOPT, item 2) does not mention // any default value or restrictions on the economic gradient. // TODO: The value of the gradient would most likely be a positive @@ -120,33 +118,31 @@ calcIncOrDecGradient(double oil_rate, double gas_rate, double alq, bool increase } std::unique_ptr -GasLiftSingleWellGeneric:: -runOptimize(const int iteration_idx) +GasLiftSingleWellGeneric::runOptimize(const int iteration_idx) { std::unique_ptr state; if (this->optimize_) { if (this->debug_limit_increase_decrease_) { state = runOptimize1_(); - } - else { + } else { state = runOptimize2_(); } if (state) { // NOTE: that state->increase() returns a std::optional, if // this is std::nullopt it means that we was not able to change ALQ // (either increase or decrease) - if (state->increase()) { // ALQ changed.. + if (state->increase()) { // ALQ changed.. double alq = state->alq(); if (this->debug) logSuccess_(alq, iteration_idx); this->well_state_.setALQ(this->well_name_, alq); const auto& pu = this->phase_usage_; std::vector well_pot(pu.num_phases, 0.0); - if(pu.phase_used[BlackoilPhases::PhaseIndex::Liquid]) + if (pu.phase_used[BlackoilPhases::PhaseIndex::Liquid]) well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Liquid]] = state->oilRate(); - if(pu.phase_used[BlackoilPhases::PhaseIndex::Aqua]) + if (pu.phase_used[BlackoilPhases::PhaseIndex::Aqua]) well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Aqua]] = state->waterRate(); - if(pu.phase_used[BlackoilPhases::PhaseIndex::Vapour]) + if (pu.phase_used[BlackoilPhases::PhaseIndex::Vapour]) well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Vapour]] = state->gasRate(); this->well_state_[this->well_name_].well_potentials = well_pot; @@ -161,8 +157,7 @@ runOptimize(const int iteration_idx) ****************************************/ std::pair, bool> -GasLiftSingleWellGeneric:: -addOrSubtractAlqIncrement_(double alq, bool increase) const +GasLiftSingleWellGeneric::addOrSubtractAlqIncrement_(double alq, bool increase) const { bool limited = false; double orig_alq = alq; @@ -175,8 +170,7 @@ addOrSubtractAlqIncrement_(double alq, bool increase) const alq = this->max_alq_; limited = true; } - } - else { // we are decreasing ALQ + } else { // we are decreasing ALQ alq -= this->increment_; if (this->min_alq_ > 0) { // According to WLIFTOPT item 5: If a positive value is @@ -189,8 +183,7 @@ addOrSubtractAlqIncrement_(double alq, bool increase) const alq = this->min_alq_; limited = true; } - } - else { + } else { if (alq < 0) { alq = 0.0; limited = true; @@ -200,16 +193,15 @@ addOrSubtractAlqIncrement_(double alq, bool increase) const std::optional alq_opt {alq}; // If we were not able to change ALQ (to within rounding error), we // return std::nullopt - if (limited && checkALQequal_(orig_alq,alq)) + if (limited && checkALQequal_(orig_alq, alq)) alq_opt = std::nullopt; return {alq_opt, limited}; } double -GasLiftSingleWellGeneric:: -calcEcoGradient_(double oil_rate, double new_oil_rate, double gas_rate, - double new_gas_rate, bool increase) const +GasLiftSingleWellGeneric::calcEcoGradient_( + double oil_rate, double new_oil_rate, double gas_rate, double new_gas_rate, bool increase) const { auto dqo = new_oil_rate - oil_rate; auto dqg = new_gas_rate - gas_rate; @@ -218,41 +210,39 @@ calcEcoGradient_(double oil_rate, double new_oil_rate, double gas_rate, // alpha_g_ * dqg >= 0.0 // // ? - auto gradient = (this->alpha_w_ * dqo) / (this->increment_ + this->alpha_g_*dqg); + auto gradient = (this->alpha_w_ * dqo) / (this->increment_ + this->alpha_g_ * dqg); // TODO: Should we do any error checks on the calculation of the // gradient? - if (!increase) gradient = -gradient; + if (!increase) + gradient = -gradient; return gradient; } bool -GasLiftSingleWellGeneric:: -checkALQequal_(double alq1, double alq2) const +GasLiftSingleWellGeneric::checkALQequal_(double alq1, double alq2) const { - return std::fabs(alq1-alq2) < (this->increment_*ALQ_EPSILON); + return std::fabs(alq1 - alq2) < (this->increment_ * ALQ_EPSILON); } bool -GasLiftSingleWellGeneric:: -checkGroupTargetsViolated( - const BasicRates& rates, const BasicRates& new_rates) const +GasLiftSingleWellGeneric::checkGroupTargetsViolated(const BasicRates& rates, const BasicRates& new_rates) const { - const auto &pairs = - this->group_info_.getWellGroups(this->well_name_); - for (const auto &[group_name, efficiency] : pairs) { + const auto& pairs = this->group_info_.getWellGroups(this->well_name_); + for (const auto& [group_name, efficiency] : pairs) { for (const auto rate_type : {Rate::oil, Rate::gas, Rate::water, Rate::liquid}) { auto target_opt = this->group_info_.getTarget(rate_type, group_name); if (target_opt) { auto delta_rate = new_rates[rate_type] - rates[rate_type]; - auto new_group_rate = this->group_info_.getRate(rate_type, group_name) - + efficiency * delta_rate; + auto new_group_rate = this->group_info_.getRate(rate_type, group_name) + efficiency * delta_rate; if (new_group_rate > *target_opt) { if (this->debug) { - const std::string msg = fmt::format( - "Group {} : {} rate {} exceeds target {}. Stopping iteration", - group_name, GasLiftGroupInfo::rateToString(rate_type), - new_group_rate, *target_opt); + const std::string msg + = fmt::format("Group {} : {} rate {} exceeds target {}. Stopping iteration", + group_name, + GasLiftGroupInfo::rateToString(rate_type), + new_group_rate, + *target_opt); displayDebugMessage_(msg); } return true; @@ -264,15 +254,15 @@ checkGroupTargetsViolated( } bool -GasLiftSingleWellGeneric:: -checkInitialALQmodified_(double alq, double initial_alq) const +GasLiftSingleWellGeneric::checkInitialALQmodified_(double alq, double initial_alq) const { - if (checkALQequal_(alq,initial_alq)) { + if (checkALQequal_(alq, initial_alq)) { return false; - } - else { + } else { const std::string msg = fmt::format("initial ALQ changed from {} " - "to {} before iteration starts..", initial_alq, alq); + "to {} before iteration starts..", + initial_alq, + alq); displayDebugMessage_(msg); return true; } @@ -295,40 +285,37 @@ computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_() const return {bhp, new_alq}; } -std::pair,double> -GasLiftSingleWellGeneric:: -computeInitialWellRates_() const +std::pair, double> +GasLiftSingleWellGeneric::computeInitialWellRates_() const { std::optional rates; double initial_alq = this->orig_alq_; - //auto alq = initial_alq; - //if (auto bhp = computeBhpAtThpLimit_(this->orig_alq_); bhp) { + // auto alq = initial_alq; + // if (auto bhp = computeBhpAtThpLimit_(this->orig_alq_); bhp) { if (auto [bhp, alq] = computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_(); bhp) { { - const std::string msg = fmt::format( - "computed initial bhp {} given thp limit and given alq {}", *bhp, alq); + const std::string msg = fmt::format("computed initial bhp {} given thp limit and given alq {}", *bhp, alq); displayDebugMessage_(msg); } initial_alq = alq; auto [new_bhp, bhp_is_limited] = getBhpWithLimit_(*bhp); rates = computeWellRates_(new_bhp, bhp_is_limited); if (rates) { - const std::string msg = fmt::format( - "computed initial well potentials given bhp, " - "oil: {}, gas: {}, water: {}", - rates->oil, rates->gas, rates->water); + const std::string msg = fmt::format("computed initial well potentials given bhp, " + "oil: {}, gas: {}, water: {}", + rates->oil, + rates->gas, + rates->water); displayDebugMessage_(msg); } - } - else { + } else { displayDebugMessage_("Aborting optimization."); } return {rates, initial_alq}; } std::optional -GasLiftSingleWellGeneric:: -computeLimitedWellRatesWithALQ_(double alq) const +GasLiftSingleWellGeneric::computeLimitedWellRatesWithALQ_(double alq) const { std::optional limited_rates; if (auto rates = computeWellRatesWithALQ_(alq); rates) { @@ -338,8 +325,7 @@ computeLimitedWellRatesWithALQ_(double alq) const } std::optional -GasLiftSingleWellGeneric:: -computeWellRatesWithALQ_(double alq) const +GasLiftSingleWellGeneric::computeWellRatesWithALQ_(double alq) const { std::optional rates; auto bhp_opt = computeBhpAtThpLimit_(alq); @@ -351,40 +337,50 @@ computeWellRatesWithALQ_(double alq) const } 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 +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 { { const std::string msg = fmt::format("calculating gradient: " - "new_oil_rate = {}, oil_rate = {}, grad = {}", new_oil_rate, oil_rate, grad); + "new_oil_rate = {}, oil_rate = {}, grad = {}", + new_oil_rate, + oil_rate, + grad); displayDebugMessage_(msg); } - if (grad < 0 ) { + if (grad < 0) { const std::string msg = fmt::format("negative {} gradient detected ({}) : " - "alq: {}, new_alq: {}, " - "oil_rate: {}, new_oil_rate: {}, gas_rate: {}, new_gas_rate: {}", - (increase ? "incremental" : "decremental"), - grad, alq, new_alq, oil_rate, new_oil_rate, gas_rate, new_gas_rate); + "alq: {}, new_alq: {}, " + "oil_rate: {}, new_oil_rate: {}, gas_rate: {}, new_gas_rate: {}", + (increase ? "incremental" : "decremental"), + grad, + alq, + new_alq, + oil_rate, + new_oil_rate, + gas_rate, + new_gas_rate); displayDebugMessage_(msg); } } void -GasLiftSingleWellGeneric:: -debugShowAlqIncreaseDecreaseCounts_() +GasLiftSingleWellGeneric::debugShowAlqIncreaseDecreaseCounts_() { auto inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_); auto dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_); - const std::string msg = - fmt::format("ALQ increase/decrease count : {}/{}", inc_count, dec_count); + const std::string msg = fmt::format("ALQ increase/decrease count : {}/{}", inc_count, dec_count); displayDebugMessage_(msg); } void -GasLiftSingleWellGeneric:: -debugShowBhpAlqTable_() +GasLiftSingleWellGeneric::debugShowBhpAlqTable_() { double alq = 0.0; const std::string fmt_fmt1 {"{:^12s} {:^12s} {:^12s} {:^12s}"}; @@ -393,24 +389,22 @@ debugShowBhpAlqTable_() displayDebugMessage_(header); auto max_it = 50; auto it = 1; - while (alq <= (this->max_alq_+this->increment_)) { + while (alq <= (this->max_alq_ + this->increment_)) { auto bhp_at_thp_limit = computeBhpAtThpLimit_(alq); if (!bhp_at_thp_limit) { const std::string msg = fmt::format("Failed to get converged potentials " - "for ALQ = {}. Skipping.", alq ); + "for ALQ = {}. Skipping.", + alq); displayDebugMessage_(msg); - } - else { + } else { auto [bhp, bhp_is_limited] = getBhpWithLimit_(*bhp_at_thp_limit); auto rates = computeWellRates_(bhp, bhp_is_limited, /*debug_out=*/false); - const std::string msg = fmt::format( - fmt_fmt2, alq, bhp, rates.oil, rates.gas); + const std::string msg = fmt::format(fmt_fmt2, alq, bhp, rates.oil, rates.gas); displayDebugMessage_(msg); } alq += this->increment_; if (it > max_it) { - const std::string msg = fmt::format( - "ALQ table : max iterations {} reached. Stopping iteration.", max_it); + const std::string msg = fmt::format("ALQ table : max iterations {} reached. Stopping iteration.", max_it); displayDebugMessage_(msg); break; } @@ -419,62 +413,49 @@ debugShowBhpAlqTable_() } void -GasLiftSingleWellGeneric:: -debugShowLimitingTargets_(const LimitedRates& rates) const +GasLiftSingleWellGeneric::debugShowLimitingTargets_(const LimitedRates& rates) const { if (rates.limited()) { if (rates.oil_is_limited) { - const std::string msg = fmt::format( - "oil rate {} is limited by {} target", - rates.oil, - GasLiftGroupInfo::rateToString(*(rates.oil_limiting_target))); + const std::string msg = fmt::format("oil rate {} is limited by {} target", + rates.oil, + GasLiftGroupInfo::rateToString(*(rates.oil_limiting_target))); displayDebugMessage_(msg); } if (rates.gas_is_limited) { - const std::string msg = fmt::format( - "gas rate {} is limited by GRAT target", - rates.gas); + const std::string msg = fmt::format("gas rate {} is limited by GRAT target", rates.gas); displayDebugMessage_(msg); } if (rates.water_is_limited) { - const std::string msg = fmt::format( - "water rate {} is limited by {} target", - rates.water, - GasLiftGroupInfo::rateToString(*(rates.water_limiting_target))); + const std::string msg = fmt::format("water rate {} is limited by {} target", + rates.water, + GasLiftGroupInfo::rateToString(*(rates.water_limiting_target))); displayDebugMessage_(msg); } - } - else { + } else { displayDebugMessage_("no rates are currently limited by a target"); } } void -GasLiftSingleWellGeneric:: -debugShowProducerControlMode() const +GasLiftSingleWellGeneric::debugShowProducerControlMode() const { const int well_index = this->well_state_.index(this->well_name_).value(); - const Well::ProducerCMode& control_mode = - this->well_state_.well(well_index).production_cmode; - const std::string msg = fmt::format("Current control mode is: {}", - Well::ProducerCMode2String(control_mode)); + const Well::ProducerCMode& control_mode = this->well_state_.well(well_index).production_cmode; + const std::string msg = fmt::format("Current control mode is: {}", Well::ProducerCMode2String(control_mode)); displayDebugMessage_(msg); } void -GasLiftSingleWellGeneric:: -debugShowStartIteration_(double alq, bool increase, double oil_rate) +GasLiftSingleWellGeneric::debugShowStartIteration_(double alq, bool increase, double oil_rate) { - const std::string msg = - fmt::format("starting {} iteration, ALQ = {}, oilrate = {}", - (increase ? "increase" : "decrease"), - alq, oil_rate); + const std::string msg = fmt::format( + "starting {} iteration, ALQ = {}, oilrate = {}", (increase ? "increase" : "decrease"), alq, oil_rate); displayDebugMessage_(msg); } void -GasLiftSingleWellGeneric:: -debugShowTargets_() +GasLiftSingleWellGeneric::debugShowTargets_() { if (this->controls_.hasControl(Well::ProducerCMode::ORAT)) { auto target = this->controls_.oil_rate; @@ -494,8 +475,7 @@ debugShowTargets_() } void -GasLiftSingleWellGeneric:: -displayDebugMessage_(const std::string& msg) const +GasLiftSingleWellGeneric::displayDebugMessage_(const std::string& msg) const { if (this->debug) { @@ -505,16 +485,14 @@ displayDebugMessage_(const std::string& msg) const } void -GasLiftSingleWellGeneric:: -displayWarning_(const std::string& msg) +GasLiftSingleWellGeneric::displayWarning_(const std::string& msg) { const std::string message = fmt::format("WELL {} : {}", this->well_name_, msg); logMessage_(/*prefix=*/"GLIFT", msg, MessageType::WARNING); } std::pair -GasLiftSingleWellGeneric:: -getBhpWithLimit_(double bhp) const +GasLiftSingleWellGeneric::getBhpWithLimit_(double bhp) const { bool limited = false; if (this->controls_.hasControl(Well::ProducerCMode::BHP)) { @@ -541,8 +519,7 @@ getBhpWithLimit_(double bhp) const // computation of the economic gradient making the gradient // smaller than it should be since the term appears in the denominator. std::pair -GasLiftSingleWellGeneric:: -getGasRateWithLimit_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getGasRateWithLimit_(const BasicRates& rates) const { auto [rate, target_type] = getRateWithLimit_(Rate::gas, rates); bool limited = target_type.has_value(); @@ -559,8 +536,7 @@ getGasRateWithLimit_(const BasicRates& rates) const // also since we also reduced the rate. This might involve // some sort of iteration though.. std::pair -GasLiftSingleWellGeneric:: -getOilRateWithLimit_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getOilRateWithLimit_(const BasicRates& rates) const { auto [rate, target_type] = getRateWithLimit_(Rate::oil, rates); bool limited = target_type.has_value(); @@ -568,15 +544,13 @@ getOilRateWithLimit_(const BasicRates& rates) const } std::pair> -GasLiftSingleWellGeneric:: -getOilRateWithLimit2_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getOilRateWithLimit2_(const BasicRates& rates) const { return getRateWithLimit_(Rate::oil, rates); } std::pair -GasLiftSingleWellGeneric:: -getWaterRateWithLimit_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getWaterRateWithLimit_(const BasicRates& rates) const { auto [rate, target_type] = getRateWithLimit_(Rate::water, rates); bool limited = target_type.has_value(); @@ -584,15 +558,13 @@ getWaterRateWithLimit_(const BasicRates& rates) const } std::pair> -GasLiftSingleWellGeneric:: -getWaterRateWithLimit2_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getWaterRateWithLimit2_(const BasicRates& rates) const { return getRateWithLimit_(Rate::water, rates); } double -GasLiftSingleWellGeneric:: -getRate_(Rate rate, const BasicRates& rates) const +GasLiftSingleWellGeneric::getRate_(Rate rate, const BasicRates& rates) const { switch (rate) { case Rate::oil: @@ -610,8 +582,7 @@ getRate_(Rate rate, const BasicRates& rates) const } double -GasLiftSingleWellGeneric:: -getProductionTarget_(Rate rate) const +GasLiftSingleWellGeneric::getProductionTarget_(Rate rate) const { switch (rate) { case Rate::oil: @@ -629,8 +600,7 @@ getProductionTarget_(Rate rate) const } std::pair> -GasLiftSingleWellGeneric:: -getRateWithLimit_(Rate rate_type, const BasicRates &rates) const +GasLiftSingleWellGeneric::getRateWithLimit_(Rate rate_type, const BasicRates& rates) const { double new_rate = getRate_(rate_type, rates); // If "target_type" is empty at the end of this method, it means the rate @@ -643,20 +613,19 @@ getRateWithLimit_(Rate rate_type, const BasicRates &rates) const if (new_rate > target) { const std::string msg = fmt::format("limiting {} rate to target: " "computed rate: {}, target: {}", - GasLiftGroupInfo::rateToString(rate_type), new_rate, target); + GasLiftGroupInfo::rateToString(rate_type), + new_rate, + target); displayDebugMessage_(msg); new_rate = target; target_type = rate_type; } } - if (((rate_type == Rate::oil) || (rate_type == Rate::water)) - && hasProductionControl_(Rate::liquid)) - { + if (((rate_type == Rate::oil) || (rate_type == Rate::water)) && hasProductionControl_(Rate::liquid)) { double rate2; if (rate_type == Rate::oil) { rate2 = getRate_(Rate::water, rates); - } - else { + } else { rate2 = getRate_(Rate::oil, rates); } // Note: Since "new_rate" was first updated for ORAT or WRAT, see first "if" @@ -677,52 +646,48 @@ getRateWithLimit_(Rate rate_type, const BasicRates &rates) const // limited = true. new_rate = fraction * liq_target; target_type = Rate::liquid; - const std::string msg = fmt::format( - "limiting {} rate to {} due to LRAT target: " - "computed LRAT: {}, target LRAT: {}", - GasLiftGroupInfo::rateToString(rate_type), new_rate, - liq_rate, liq_target); + const std::string msg = fmt::format("limiting {} rate to {} due to LRAT target: " + "computed LRAT: {}, target LRAT: {}", + GasLiftGroupInfo::rateToString(rate_type), + new_rate, + liq_rate, + liq_target); displayDebugMessage_(msg); } } // TODO: Also check RESV target? - return { new_rate, target_type}; + return {new_rate, target_type}; } std::pair -GasLiftSingleWellGeneric:: -getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate) const +GasLiftSingleWellGeneric::getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] - = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric:: -getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate) const +GasLiftSingleWellGeneric::getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] - = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric:: -getWaterRateWithGroupLimit_(double new_water_rate, double water_rate) const +GasLiftSingleWellGeneric::getWaterRateWithGroupLimit_(double new_water_rate, double water_rate) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_( - Rate::water, new_water_rate, water_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::water, new_water_rate, water_rate); bool limited = gr_name != nullptr; return {rate, limited}; } std::tuple -GasLiftSingleWellGeneric:: -getLiquidRateWithGroupLimit_(const double new_oil_rate, const double oil_rate, - const double new_water_rate, const double water_rate) const +GasLiftSingleWellGeneric::getLiquidRateWithGroupLimit_(const double new_oil_rate, + const double oil_rate, + const double new_water_rate, + const double water_rate) const { auto liquid_rate = oil_rate + water_rate; auto new_liquid_rate = new_oil_rate + new_water_rate; @@ -758,80 +723,74 @@ getLiquidRateWithGroupLimit_(const double new_oil_rate, const double oil_rate, } std::tuple -GasLiftSingleWellGeneric:: -getRateWithGroupLimit_( - Rate rate_type, const double new_rate, const double old_rate) const +GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double new_rate, const double old_rate) const { const double delta_rate = new_rate - old_rate; if (delta_rate > 0) { - // It is required that the production rate for a given group is - // is less than or equal to its target rate. - // Then it only makes sense to check if the group target is exceeded - // if delta_rate > 0 - const auto &pairs = - this->group_info_.getWellGroups(this->well_name_); - double limited_rate = new_rate; - double gr_target, new_gr_rate, efficiency; - const std::string *group_name = nullptr; - for (const auto& [group_name_temp, efficiency_temp] : pairs) { - auto gr_target_opt = this->group_info_.getTarget(rate_type, group_name_temp); - if (gr_target_opt) { - double gr_target_temp = *gr_target_opt; - double gr_rate_temp = - this->group_info_.getRate(rate_type, group_name_temp); - if (gr_rate_temp > gr_target_temp) { - if (this->debug) { - debugInfoGroupRatesExceedTarget( - rate_type, group_name_temp, gr_rate_temp, gr_target_temp); - } - group_name = &group_name_temp; - efficiency = efficiency_temp; - limited_rate = old_rate; - gr_target = gr_target_temp; - new_gr_rate = gr_rate_temp; - break; - } - double new_gr_rate_temp = gr_rate_temp + efficiency_temp * delta_rate; - if (new_gr_rate_temp > gr_target_temp) { - double limited_rate_temp = - old_rate + (gr_target_temp - gr_rate_temp) / efficiency_temp; - if (limited_rate_temp < limited_rate) { + // It is required that the production rate for a given group is + // is less than or equal to its target rate. + // Then it only makes sense to check if the group target is exceeded + // if delta_rate > 0 + const auto& pairs = this->group_info_.getWellGroups(this->well_name_); + double limited_rate = new_rate; + double gr_target, new_gr_rate, efficiency; + const std::string* group_name = nullptr; + for (const auto& [group_name_temp, efficiency_temp] : pairs) { + auto gr_target_opt = this->group_info_.getTarget(rate_type, group_name_temp); + if (gr_target_opt) { + double gr_target_temp = *gr_target_opt; + double gr_rate_temp = this->group_info_.getRate(rate_type, group_name_temp); + if (gr_rate_temp > gr_target_temp) { + if (this->debug) { + debugInfoGroupRatesExceedTarget(rate_type, group_name_temp, gr_rate_temp, gr_target_temp); + } group_name = &group_name_temp; efficiency = efficiency_temp; - limited_rate = limited_rate_temp; + limited_rate = old_rate; gr_target = gr_target_temp; - new_gr_rate = new_gr_rate_temp; + new_gr_rate = gr_rate_temp; + break; + } + double new_gr_rate_temp = gr_rate_temp + efficiency_temp * delta_rate; + if (new_gr_rate_temp > gr_target_temp) { + double limited_rate_temp = old_rate + (gr_target_temp - gr_rate_temp) / efficiency_temp; + if (limited_rate_temp < limited_rate) { + group_name = &group_name_temp; + efficiency = efficiency_temp; + limited_rate = limited_rate_temp; + gr_target = gr_target_temp; + new_gr_rate = new_gr_rate_temp; + } } } - } - } - if (group_name) { - if (this->debug) { - const std::string msg = fmt::format( - "limiting {} rate from {} to {} to meet group target {} " - "for group {}. Computed group rate was: {}", - GasLiftGroupInfo::rateToString(rate_type), - new_rate, limited_rate, gr_target, - *group_name, new_gr_rate); - displayDebugMessage_(msg); - } - return { limited_rate, group_name, efficiency }; - } + } + if (group_name) { + if (this->debug) { + const std::string msg = fmt::format("limiting {} rate from {} to {} to meet group target {} " + "for group {}. Computed group rate was: {}", + GasLiftGroupInfo::rateToString(rate_type), + new_rate, + limited_rate, + gr_target, + *group_name, + new_gr_rate); + displayDebugMessage_(msg); + } + return {limited_rate, group_name, efficiency}; + } } - return { new_rate, /*group_name =*/nullptr, /*efficiency dummy value*/0.0 }; + return {new_rate, /*group_name =*/nullptr, /*efficiency dummy value*/ 0.0}; } std::pair, double> -GasLiftSingleWellGeneric:: -getInitialRatesWithLimit_() const +GasLiftSingleWellGeneric::getInitialRatesWithLimit_() const { std::optional limited_rates; double initial_alq = this->orig_alq_; if (auto [rates, alq] = computeInitialWellRates_(); rates) { if (this->debug) { - displayDebugMessage_( - "Maybe limiting initial rates before optimize loop.."); + displayDebugMessage_("Maybe limiting initial rates before optimize loop.."); } auto temp_rates = getLimitedRatesFromRates_(*rates); BasicRates old_rates = getWellStateRates_(); @@ -842,52 +801,51 @@ getInitialRatesWithLimit_() const } GasLiftSingleWellGeneric::LimitedRates -GasLiftSingleWellGeneric:: -getLimitedRatesFromRates_(const BasicRates& rates) const +GasLiftSingleWellGeneric::getLimitedRatesFromRates_(const BasicRates& rates) const { auto [oil_rate, oil_limiting_target] = getOilRateWithLimit2_(rates); auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(rates); auto [water_rate, water_limiting_target] = getWaterRateWithLimit2_(rates); bool oil_is_limited = oil_limiting_target.has_value(); bool water_is_limited = water_limiting_target.has_value(); - return LimitedRates{ - oil_rate, gas_rate, water_rate, - oil_is_limited, gas_is_limited, water_is_limited, rates.bhp_is_limited, - oil_limiting_target, water_limiting_target}; + return LimitedRates {oil_rate, + gas_rate, + water_rate, + oil_is_limited, + gas_is_limited, + water_is_limited, + rates.bhp_is_limited, + oil_limiting_target, + water_limiting_target}; } GasLiftSingleWellGeneric::BasicRates -GasLiftSingleWellGeneric:: -getWellStateRates_() const +GasLiftSingleWellGeneric::getWellStateRates_() const { const int well_index = this->well_state_.index(this->well_name_).value(); const auto& pu = this->phase_usage_; - const auto& ws= this->well_state_.well(well_index); + const auto& ws = this->well_state_.well(well_index); const auto& wrate = ws.well_potentials; - const auto oil_rate = pu.phase_used[Oil] - ? wrate[pu.phase_pos[Oil]] - : 0.0; + const auto oil_rate = pu.phase_used[Oil] ? wrate[pu.phase_pos[Oil]] : 0.0; - const auto gas_rate = pu.phase_used[Gas] - ? wrate[pu.phase_pos[Gas]] - : 0.0; + const auto gas_rate = pu.phase_used[Gas] ? wrate[pu.phase_pos[Gas]] : 0.0; - const auto water_rate = pu.phase_used[Water] - ? wrate[pu.phase_pos[Water]] - : 0.0; + const auto water_rate = pu.phase_used[Water] ? wrate[pu.phase_pos[Water]] : 0.0; if (this->debug) { const std::string msg = fmt::format("Initial surface rates: oil : {}, " - "gas : {}, water : {}", oil_rate, gas_rate, water_rate); + "gas : {}, water : {}", + oil_rate, + gas_rate, + water_rate); displayDebugMessage_(msg); } - return BasicRates{oil_rate, water_rate, gas_rate, /*bhp_is_limited=*/false}; + return BasicRates {oil_rate, water_rate, gas_rate, /*bhp_is_limited=*/false}; } bool -GasLiftSingleWellGeneric:: -hasProductionControl_(Rate rate) const +GasLiftSingleWellGeneric::hasProductionControl_(Rate rate) const { switch (rate) { case Rate::oil: @@ -906,29 +864,30 @@ hasProductionControl_(Rate rate) const std::pair -GasLiftSingleWellGeneric:: -increaseALQtoPositiveOilRate_(double alq, const LimitedRates& orig_rates) const +GasLiftSingleWellGeneric::increaseALQtoPositiveOilRate_(double alq, const LimitedRates& orig_rates) const { bool stop_iteration = false; double temp_alq = alq; // use the copy constructor to only copy the rates BasicRates rates = orig_rates; - while(!stop_iteration) { + while (!stop_iteration) { temp_alq += this->increment_; - if (temp_alq > this->max_alq_) break; + if (temp_alq > this->max_alq_) + break; auto temp_rates = computeWellRatesWithALQ_(temp_alq); - if (!temp_rates) break; + if (!temp_rates) + break; alq = temp_alq; rates = *temp_rates; - if (rates.oil > 0) break; + if (rates.oil > 0) + break; } // TODO: what about group limits? return {getLimitedRatesFromRates_(rates), alq}; } std::pair -GasLiftSingleWellGeneric:: -increaseALQtoMinALQ_(const double orig_alq, const LimitedRates& orig_rates) const +GasLiftSingleWellGeneric::increaseALQtoMinALQ_(const double orig_alq, const LimitedRates& orig_rates) const { auto min_alq = this->min_alq_; assert(min_alq >= 0); @@ -937,35 +896,37 @@ increaseALQtoMinALQ_(const double orig_alq, const LimitedRates& orig_rates) cons bool stop_iteration = false; double alq = orig_alq; LimitedRates rates = orig_rates; - while(!stop_iteration) { + while (!stop_iteration) { double temp_alq = alq + this->increment_; - if (temp_alq >= min_alq) break; + if (temp_alq >= min_alq) + break; auto temp_rates = computeLimitedWellRatesWithALQ_(temp_alq); - if (!temp_rates) break; + if (!temp_rates) + break; alq = temp_alq; rates = *temp_rates; - if (rates.limited()) break; + if (rates.limited()) + break; } return std::make_pair(rates, alq); } void -GasLiftSingleWellGeneric:: -logSuccess_(double alq, const int iteration_idx) +GasLiftSingleWellGeneric::logSuccess_(double alq, const int iteration_idx) { - const std::string message = fmt::format( - "GLIFT, IT={}, WELL {} : {} ALQ from {} to {}", - iteration_idx, - this->well_name_, - ((alq > this->orig_alq_) ? "increased" : "decreased"), - this->orig_alq_, alq); + const std::string message = fmt::format("GLIFT, IT={}, WELL {} : {} ALQ from {} to {}", + iteration_idx, + this->well_name_, + ((alq > this->orig_alq_) ? "increased" : "decreased"), + this->orig_alq_, + alq); this->deferred_logger_.info(message); } std::pair -GasLiftSingleWellGeneric:: -maybeAdjustALQbeforeOptimizeLoop_( - const LimitedRates& orig_rates, const double orig_alq, const bool increase) const +GasLiftSingleWellGeneric::maybeAdjustALQbeforeOptimizeLoop_(const LimitedRates& orig_rates, + const double orig_alq, + const bool increase) const { double alq = orig_alq; LimitedRates rates = orig_rates; @@ -978,7 +939,7 @@ maybeAdjustALQbeforeOptimizeLoop_( // NOTE: Try to decrease ALQ down to a value where the groups // maximum alq target and the total gas + alq target is not violated std::tie(rates, alq) = reduceALQtoGroupAlqLimits_(alq, orig_rates); - if(orig_rates.limited()) { + if (orig_rates.limited()) { // NOTE: Try to decrease ALQ down to a value where the well target is // not exceeded. // NOTE: This may reduce ALQ below the minimum value set in WLIFTOPT @@ -989,8 +950,7 @@ maybeAdjustALQbeforeOptimizeLoop_( if (alq1 < alq2) { alq = alq1; rates = rates1; - } - else { + } else { alq = alq2; rates = rates2; } @@ -1000,7 +960,7 @@ maybeAdjustALQbeforeOptimizeLoop_( // Try to increase ALQ up to a value where oil_rate is positive std::tie(rates, alq) = increaseALQtoPositiveOilRate_(alq, rates); } - if ((this->min_alq_> 0) && (alq < this->min_alq_)) { + if ((this->min_alq_ > 0) && (alq < this->min_alq_)) { // Try to increase ALQ up to the minimum limit without checking // the economic gradient.. std::tie(rates, alq) = increaseALQtoMinALQ_(alq, rates); @@ -1017,7 +977,9 @@ maybeAdjustALQbeforeOptimizeLoop_( return {rates, alq}; } -bool has_control(int controls, Group::InjectionCMode cmode) { +bool +has_control(int controls, Group::InjectionCMode cmode) +{ return ((controls & static_cast(cmode)) != 0); } @@ -1025,19 +987,21 @@ bool has_control(int controls, Group::InjectionCMode cmode) { // least one rate limited w.r.t. group targets, or reduce ALQ to zero if // such positive ALQ value cannot be found. std::pair -GasLiftSingleWellGeneric:: -reduceALQtoGroupAlqLimits_(const double orig_alq, const LimitedRates& orig_rates) const +GasLiftSingleWellGeneric::reduceALQtoGroupAlqLimits_(const double orig_alq, const LimitedRates& orig_rates) const { bool stop_this_iteration = false; double alq = orig_alq; - BasicRates rates{ orig_rates }; + BasicRates rates {orig_rates}; double temp_alq = orig_alq; - while(!stop_this_iteration) { - if (temp_alq == 0) break; + while (!stop_this_iteration) { + if (temp_alq == 0) + break; temp_alq -= this->increment_; - if (temp_alq < 0) temp_alq = 0; + if (temp_alq < 0) + temp_alq = 0; auto new_rates = computeWellRatesWithALQ_(temp_alq); - if (!new_rates) break; + if (!new_rates) + break; auto delta_alq = temp_alq - orig_alq; auto delta_gas_rate = new_rates->gas - orig_rates.gas; if (!checkGroupTotalRateExceeded(delta_alq, delta_gas_rate)) { @@ -1048,8 +1012,7 @@ reduceALQtoGroupAlqLimits_(const double orig_alq, const LimitedRates& orig_rates } if (alq == orig_alq) { return {orig_rates, orig_alq}; - } - else { + } else { LimitedRates limited_rates = getLimitedRatesFromRates_(rates); return {limited_rates, alq}; } @@ -1058,32 +1021,32 @@ reduceALQtoGroupAlqLimits_(const double orig_alq, const LimitedRates& orig_rates // least one rate limited w.r.t. group targets, or reduce ALQ to zero if // such positive ALQ value cannot be found. std::pair -GasLiftSingleWellGeneric:: -reduceALQtoGroupTarget(const double orig_alq, const LimitedRates& orig_rates) const +GasLiftSingleWellGeneric::reduceALQtoGroupTarget(const double orig_alq, const LimitedRates& orig_rates) const { bool stop_this_iteration = true; - const std::vector>& pairs = - this->group_info_.getWellGroups(this->well_name_); - for (const auto &pair /**/ : pairs) { + const std::vector>& pairs = this->group_info_.getWellGroups(this->well_name_); + for (const auto& pair /**/ : pairs) { const auto& group_name = pair.first; if (!this->group_state_.has_production_control(group_name)) continue; if (this->group_info_.hasAnyTarget(group_name)) { stop_this_iteration = false; - displayDebugMessage_( - "Reducing ALQ to meet group target(s) before iteration starts."); + displayDebugMessage_("Reducing ALQ to meet group target(s) before iteration starts."); break; } } double alq = orig_alq; - BasicRates rates{ orig_rates }; + BasicRates rates {orig_rates}; double temp_alq = orig_alq; - while(!stop_this_iteration) { - if (temp_alq == 0) break; + while (!stop_this_iteration) { + if (temp_alq == 0) + break; temp_alq -= this->increment_; - if (temp_alq < 0) temp_alq = 0; + if (temp_alq < 0) + temp_alq = 0; auto new_rates = computeWellRatesWithALQ_(temp_alq); - if (!new_rates) break; + if (!new_rates) + break; if (!checkGroupTargetsViolated(rates, *new_rates)) { break; } @@ -1092,8 +1055,7 @@ reduceALQtoGroupTarget(const double orig_alq, const LimitedRates& orig_rates) co } if (alq == orig_alq) { return {orig_rates, orig_alq}; - } - else { + } else { LimitedRates limited_rates = getLimitedRatesFromRates_(rates); return {limited_rates, alq}; } @@ -1103,55 +1065,57 @@ reduceALQtoGroupTarget(const double orig_alq, const LimitedRates& orig_rates) co // least one rate limited w.r.t. well targets, or reduce ALQ to zero if // such positive ALQ value cannot be found. std::pair -GasLiftSingleWellGeneric:: -reduceALQtoWellTarget_(const double orig_alq, const LimitedRates& rates) const +GasLiftSingleWellGeneric::reduceALQtoWellTarget_(const double orig_alq, const LimitedRates& rates) const { // this method should only be called if "rates" is limited assert(rates.limited()); if (this->debug) { - displayDebugMessage_( - "Reducing ALQ to meet well targets before iteration starts.."); + displayDebugMessage_("Reducing ALQ to meet well targets before iteration starts.."); debugShowLimitingTargets_(rates); } double alq = orig_alq; double temp_alq = alq; std::optional new_rates; bool stop_iteration = false; - while(!stop_iteration) { - if (temp_alq == 0) break; + while (!stop_iteration) { + if (temp_alq == 0) + break; temp_alq -= this->increment_; - if (temp_alq < 0) temp_alq = 0; + if (temp_alq < 0) + temp_alq = 0; auto temp_rates = computeLimitedWellRatesWithALQ_(temp_alq); - if (!temp_rates) break; // failed to compute BHP given THP limit and ALQ + if (!temp_rates) + break; // failed to compute BHP given THP limit and ALQ // keep iterating until no rate is limited - if (!temp_rates->limited()) break; + if (!temp_rates->limited()) + break; alq = temp_alq; new_rates = temp_rates; } - assert( alq <= orig_alq ); + assert(alq <= orig_alq); if (this->debug) { if (alq < orig_alq) { // NOTE: ALQ may drop below zero before we are able to meet the target - const std::string msg = fmt::format( - "Reduced ALQ from {} to {} to meet rate targets. Rates (new, old) : " - "oil(({}, {}), gas({}, {}), water({}, {})", - orig_alq, alq, - new_rates->oil, rates.oil, - new_rates->gas, rates.gas, - new_rates->water, rates.water); + const std::string msg = fmt::format("Reduced ALQ from {} to {} to meet rate targets. Rates (new, old) : " + "oil(({}, {}), gas({}, {}), water({}, {})", + orig_alq, + alq, + new_rates->oil, + rates.oil, + new_rates->gas, + rates.gas, + new_rates->water, + rates.water); displayDebugMessage_(msg); - } - else if (alq == orig_alq) { + } else if (alq == orig_alq) { // We might not be able to reduce ALQ, for example if ALQ starts out at zero. - const std::string msg = fmt::format( - "Not able to reduce ALQ {} further. ", orig_alq); + const std::string msg = fmt::format("Not able to reduce ALQ {} further. ", orig_alq); displayDebugMessage_(msg); } } if (new_rates) { return {*new_rates, alq}; - } - else { + } else { return {rates, orig_alq}; } } @@ -1166,21 +1130,23 @@ reduceALQtoWellTarget_(const double orig_alq, const LimitedRates& rates) const // - return value: a new GasLiftWellState or nullptr // std::unique_ptr -GasLiftSingleWellGeneric:: -runOptimizeLoop_(bool increase) +GasLiftSingleWellGeneric::runOptimizeLoop_(bool increase) { - if (this->debug) debugShowProducerControlMode(); + if (this->debug) + debugShowProducerControlMode(); std::unique_ptr ret_value; // nullptr initially auto [rates, cur_alq] = getInitialRatesWithLimit_(); - if (!rates) return ret_value; + if (!rates) + return ret_value; // if (this->debug) debugShowBhpAlqTable_(); - if (this->debug) debugShowAlqIncreaseDecreaseCounts_(); - if (this->debug) debugShowTargets_(); - bool success = false; // did we succeed to increase alq? + if (this->debug) + debugShowAlqIncreaseDecreaseCounts_(); + if (this->debug) + debugShowTargets_(); + bool success = false; // did we succeed to increase alq? bool alq_is_limited = false; LimitedRates new_rates = *rates; - auto [temp_rates2, new_alq] = maybeAdjustALQbeforeOptimizeLoop_( - *rates, cur_alq, increase); + auto [temp_rates2, new_alq] = maybeAdjustALQbeforeOptimizeLoop_(*rates, cur_alq, increase); if (checkInitialALQmodified_(new_alq, this->orig_alq_)) { auto delta_alq = new_alq - cur_alq; new_rates = temp_rates2; @@ -1192,9 +1158,9 @@ runOptimizeLoop_(bool increase) OptimizeState state {*this, increase}; auto temp_alq = cur_alq; if (checkThpControl_()) { - if (this->debug) debugShowStartIteration_(temp_alq, increase, new_rates.oil); - } - else { + if (this->debug) + debugShowStartIteration_(temp_alq, increase, new_rates.oil); + } else { // If the well is not under THP control, we can still use the previous // initial adjustment of ALQ by using the well's THP limit to calculate // BHP and then well rates from that. @@ -1204,42 +1170,48 @@ runOptimizeLoop_(bool increase) state.stop_iteration = true; } while (!state.stop_iteration && (++state.it <= this->max_iterations_)) { - if (state.checkRatesViolated(new_rates)) break; - if (state.checkAlqOutsideLimits(temp_alq, new_rates.oil)) break; + if (state.checkRatesViolated(new_rates)) + break; + if (state.checkAlqOutsideLimits(temp_alq, new_rates.oil)) + break; std::optional alq_opt; std::tie(alq_opt, alq_is_limited) = state.addOrSubtractAlqIncrement(temp_alq); - if (!alq_opt) break; + if (!alq_opt) + break; auto delta_alq = *alq_opt - temp_alq; - if (checkGroupALQrateExceeded(delta_alq)) break; + if (checkGroupALQrateExceeded(delta_alq)) + break; temp_alq = *alq_opt; - if (this->debug) state.debugShowIterationInfo(temp_alq); + if (this->debug) + state.debugShowIterationInfo(temp_alq); rates = new_rates; auto temp_rates = computeLimitedWellRatesWithALQ_(temp_alq); - if (!temp_rates) break; + if (!temp_rates) + break; if (temp_rates->bhp_is_limited) state.stop_iteration = true; temp_rates = updateRatesToGroupLimits_(*rates, *temp_rates); auto delta_gas_rate = temp_rates->gas - rates->gas; - if (checkGroupTotalRateExceeded(delta_alq, delta_gas_rate)) break; + if (checkGroupTotalRateExceeded(delta_alq, delta_gas_rate)) + break; -/* 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 - displayDebugMessage_( - "increasing ALQ and gas is limited -> aborting iteration"); - break; - } - } -*/ - auto gradient = state.calcEcoGradient( - rates->oil, temp_rates->oil, rates->gas, temp_rates->gas); + /* 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 + displayDebugMessage_( + "increasing ALQ and gas is limited -> aborting iteration"); + break; + } + } + */ + auto gradient = state.calcEcoGradient(rates->oil, temp_rates->oil, rates->gas, temp_rates->gas); if (this->debug) debugCheckNegativeGradient_( - gradient, cur_alq, temp_alq, rates->oil, temp_rates->oil, - rates->gas, temp_rates->gas, increase); - if (state.checkEcoGradient(gradient)) break; + gradient, cur_alq, temp_alq, rates->oil, temp_rates->oil, rates->gas, temp_rates->gas, increase); + if (state.checkEcoGradient(gradient)) + break; cur_alq = temp_alq; success = true; new_rates = *temp_rates; @@ -1252,20 +1224,22 @@ runOptimizeLoop_(bool increase) if (success) { this->well_state_.gliftUpdateAlqIncreaseCount(this->well_name_, increase); increase_opt = increase; - } - else { + } else { increase_opt = std::nullopt; } - ret_value = std::make_unique( - new_rates.oil, new_rates.oil_is_limited, - new_rates.gas, new_rates.gas_is_limited, - cur_alq, alq_is_limited, new_rates.water, increase_opt); + ret_value = std::make_unique(new_rates.oil, + new_rates.oil_is_limited, + new_rates.gas, + new_rates.gas_is_limited, + cur_alq, + alq_is_limited, + new_rates.water, + increase_opt); return ret_value; } std::unique_ptr -GasLiftSingleWellGeneric:: -runOptimize1_() +GasLiftSingleWellGeneric::runOptimize1_() { std::unique_ptr state; int inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_); @@ -1275,12 +1249,10 @@ runOptimize1_() if (!state || !(state->alqChanged())) { state = tryDecreaseLiftGas_(); } - } - else if (dec_count == 0) { + } else if (dec_count == 0) { assert(inc_count > 0); state = tryIncreaseLiftGas_(); - } - else if (inc_count == 0) { + } else if (inc_count == 0) { assert(dec_count > 0); state = tryDecreaseLiftGas_(); } @@ -1288,8 +1260,7 @@ runOptimize1_() } std::unique_ptr -GasLiftSingleWellGeneric:: -runOptimize2_() +GasLiftSingleWellGeneric::runOptimize2_() { std::unique_ptr state; state = tryIncreaseLiftGas_(); @@ -1300,22 +1271,19 @@ runOptimize2_() } std::unique_ptr -GasLiftSingleWellGeneric:: -tryDecreaseLiftGas_() +GasLiftSingleWellGeneric::tryDecreaseLiftGas_() { - return runOptimizeLoop_(/*increase=*/ false); + return runOptimizeLoop_(/*increase=*/false); } std::unique_ptr -GasLiftSingleWellGeneric:: -tryIncreaseLiftGas_() +GasLiftSingleWellGeneric::tryIncreaseLiftGas_() { - return runOptimizeLoop_(/*increase=*/ true); + return runOptimizeLoop_(/*increase=*/true); } void -GasLiftSingleWellGeneric:: -setAlqMinRate_(const GasLiftOpt::Well& well) +GasLiftSingleWellGeneric::setAlqMinRate_(const GasLiftOpt::Well& well) { // NOTE: According to WLIFTOPT item 5 : // if min_rate() is negative, it means: allocate at least enough lift gas @@ -1342,56 +1310,49 @@ setAlqMinRate_(const GasLiftOpt::Well& well) // TODO: Consider other options for resetting the value.. this->min_alq_ = -1; displayWarning_("Minimum ALQ value is larger than maximum ALQ value!" - " Resetting value."); + " Resetting value."); } } } void -GasLiftSingleWellGeneric:: -updateGroupRates_( - const LimitedRates& rates, const LimitedRates& new_rates, double delta_alq) const +GasLiftSingleWellGeneric::updateGroupRates_(const LimitedRates& rates, + const LimitedRates& new_rates, + double delta_alq) const { double delta_oil = new_rates.oil - rates.oil; double delta_gas = new_rates.gas - rates.gas; double delta_water = new_rates.water - rates.water; - const auto &pairs = - this->group_info_.getWellGroups(this->well_name_); - for (const auto &[group_name, efficiency] : pairs) { + const auto& pairs = this->group_info_.getWellGroups(this->well_name_); + for (const auto& [group_name, efficiency] : pairs) { int idx = this->group_info_.getGroupIdx(group_name); // This will notify the optimize loop in BlackoilWellModel, see // gasLiftOptimizationStage1() in BlackoilWellModel_impl.hpp // that this group_info needs to be synchronized to the other MPI ranks this->sync_groups_.insert(idx); this->group_info_.update(group_name, - efficiency * delta_oil, - efficiency * delta_gas, - efficiency * delta_water, - efficiency * delta_alq); + efficiency * delta_oil, + efficiency * delta_gas, + efficiency * delta_water, + efficiency * delta_alq); } } GasLiftSingleWellGeneric::LimitedRates -GasLiftSingleWellGeneric:: -updateRatesToGroupLimits_( - const BasicRates& old_rates, const LimitedRates& rates) const +GasLiftSingleWellGeneric::updateRatesToGroupLimits_(const BasicRates& old_rates, const LimitedRates& rates) const { LimitedRates new_rates = rates; - auto [new_oil_rate, oil_is_limited] = getOilRateWithGroupLimit_( - new_rates.oil, old_rates.oil); + auto [new_oil_rate, oil_is_limited] = getOilRateWithGroupLimit_(new_rates.oil, old_rates.oil); if (oil_is_limited) { new_rates.oil_limiting_target = Rate::oil; } - auto [new_gas_rate, gas_is_limited] = getGasRateWithGroupLimit_( - new_rates.gas, old_rates.gas); - auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_( - new_rates.water, old_rates.water); + auto [new_gas_rate, gas_is_limited] = getGasRateWithGroupLimit_(new_rates.gas, old_rates.gas); + auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_(new_rates.water, old_rates.water); if (water_is_limited) { new_rates.water_limiting_target = Rate::water; } auto [new_oil_rate2, new_water_rate2, oil_is_limited2, water_is_limited2] - = getLiquidRateWithGroupLimit_( - new_oil_rate, old_rates.oil, new_water_rate, old_rates.water); + = getLiquidRateWithGroupLimit_(new_oil_rate, old_rates.oil, new_water_rate, old_rates.water); if (oil_is_limited2) { new_rates.oil_limiting_target = Rate::liquid; } @@ -1403,10 +1364,8 @@ updateRatesToGroupLimits_( new_rates.water = new_water_rate2; new_rates.oil_is_limited = rates.oil_is_limited || oil_is_limited || oil_is_limited2; new_rates.gas_is_limited = rates.gas_is_limited || gas_is_limited; - new_rates.water_is_limited = - rates.water_is_limited || water_is_limited || water_is_limited2; - if (oil_is_limited || oil_is_limited2 || gas_is_limited - || water_is_limited || water_is_limited2) { + new_rates.water_is_limited = rates.water_is_limited || water_is_limited || water_is_limited2; + if (oil_is_limited || oil_is_limited2 || gas_is_limited || water_is_limited || water_is_limited2) { new_rates.limit_type = LimitedRates::LimitType::group; } return new_rates; @@ -1414,8 +1373,7 @@ updateRatesToGroupLimits_( // Called when we should use a fixed ALQ value void -GasLiftSingleWellGeneric:: -updateWellStateAlqFixedValue_(const GasLiftOpt::Well& well) +GasLiftSingleWellGeneric::updateWellStateAlqFixedValue_(const GasLiftOpt::Well& well) { auto& max_alq_optional = well.max_rate(); if (max_alq_optional) { @@ -1429,7 +1387,6 @@ updateWellStateAlqFixedValue_(const GasLiftOpt::Well& well) // // If item 3 is defaulted, the lift gas rate remains // // unchanged at its current value. //} - } // Determine if we should use a fixed ALQ value. @@ -1443,47 +1400,46 @@ updateWellStateAlqFixedValue_(const GasLiftOpt::Well& well) // value that can be set either in Item 3 of this keyword, or in // Item 12 of keyword WCONPROD, or with keyword WELTARG. bool -GasLiftSingleWellGeneric:: -useFixedAlq_(const GasLiftOpt::Well& well) +GasLiftSingleWellGeneric::useFixedAlq_(const GasLiftOpt::Well& well) { auto wliftopt_item2 = well.use_glo(); if (wliftopt_item2) { return false; - } - else { + } else { displayDebugMessage_("WLIFTOPT item2 = NO. Skipping optimization."); // auto& max_alq_optional = well.max_rate(); // if (max_alq_optional) { - // According to WLIFTOPT, item 3: - // If item 2 is NO, then item 3 is regarded as the fixed - // lift gas injection rate for the well. + // According to WLIFTOPT, item 3: + // If item 2 is NO, then item 3 is regarded as the fixed + // lift gas injection rate for the well. // } // else { - // If item 3 is defaulted, the lift gas rate remains - // unchanged at its current value. + // If item 3 is defaulted, the lift gas rate remains + // unchanged at its current value. // } return true; } } void -GasLiftSingleWellGeneric:: -debugInfoGroupRatesExceedTarget( - Rate rate_type, const std::string& gr_name, double rate, double target) const +GasLiftSingleWellGeneric::debugInfoGroupRatesExceedTarget(Rate rate_type, + const std::string& gr_name, + double rate, + double target) const { const std::string msg = fmt::format("{} rate for group {} exceeds target: " - "rate = {}, target = {}, the old rate is kept.", - GasLiftGroupInfo::rateToString(rate_type), - gr_name, rate, target); + "rate = {}, target = {}, the old rate is kept.", + GasLiftGroupInfo::rateToString(rate_type), + gr_name, + rate, + target); displayDebugMessage_(msg); } void -GasLiftSingleWellGeneric:: -warnMaxIterationsExceeded_() +GasLiftSingleWellGeneric::warnMaxIterationsExceeded_() { - const std::string msg = fmt::format( - "Max iterations ({}) exceeded", this->max_iterations_); + const std::string msg = fmt::format("Max iterations ({}) exceeded", this->max_iterations_); displayWarning_(msg); } @@ -1492,26 +1448,25 @@ warnMaxIterationsExceeded_() ****************************************/ std::pair, bool> -GasLiftSingleWellGeneric::OptimizeState:: -addOrSubtractAlqIncrement(double alq) +GasLiftSingleWellGeneric::OptimizeState::addOrSubtractAlqIncrement(double alq) { - auto [alq_opt, limited] - = this->parent.addOrSubtractAlqIncrement_(alq, this->increase); + auto [alq_opt, limited] = this->parent.addOrSubtractAlqIncrement_(alq, this->increase); if (!alq_opt) { - const std::string msg = fmt::format( - "iteration {}, alq = {} : not able to {} ALQ increment", - this->it, alq, (this->increase ? "add" : "subtract")); + const std::string msg = fmt::format("iteration {}, alq = {} : not able to {} ALQ increment", + this->it, + alq, + (this->increase ? "add" : "subtract")); } return {alq_opt, limited}; } double -GasLiftSingleWellGeneric::OptimizeState:: -calcEcoGradient(double oil_rate, double new_oil_rate, - double gas_rate, double new_gas_rate) +GasLiftSingleWellGeneric::OptimizeState::calcEcoGradient(double oil_rate, + double new_oil_rate, + double gas_rate, + double new_gas_rate) { - return this->parent.calcEcoGradient_(oil_rate, new_oil_rate, - gas_rate, new_gas_rate, this->increase); + return this->parent.calcEcoGradient_(oil_rate, new_oil_rate, gas_rate, new_gas_rate, this->increase); } // NOTE: According to WLIFTOPT item 5 : @@ -1521,8 +1476,7 @@ calcEcoGradient(double oil_rate, double new_oil_rate, // in this file): Allocate at least the amount of lift gas needed to // get a positive oil production rate. bool -GasLiftSingleWellGeneric::OptimizeState:: -checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) +GasLiftSingleWellGeneric::OptimizeState::checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) { std::ostringstream ss; bool result = false; @@ -1532,8 +1486,7 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) ss << "ALQ >= " << this->parent.max_alq_ << " (max limit), " << "stopping iteration"; result = true; - } - else { // checking the minimum limit... + } else { // checking the minimum limit... // NOTE: A negative min_alq_ means: allocate at least enough lift gas // to enable the well to flow, see WLIFTOPT item 5. if (this->parent.min_alq_ < 0) { @@ -1543,23 +1496,20 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) // - else if oil rate is already positive, there is no minimum // limit for ALQ in this case result = false; - } - else { + } else { // NOTE: checking for a lower limit is not necessary // when increasing alq. If ALQ was smaller than the minimum when // we entered the runOptimizeLoop_() method, // increaseALQtoMinALQ_() will ensure that ALQ >= min_alq - assert(alq >= this->parent.min_alq_ ); + assert(alq >= this->parent.min_alq_); result = false; } } - } - else { // we are decreasing lift gas - if ( alq == 0 ) { + } else { // we are decreasing lift gas + if (alq == 0) { ss << "ALQ is zero, cannot decrease further. Stopping iteration."; result = true; - } - else if ( alq < 0 ) { + } else if (alq < 0) { ss << "Negative ALQ: " << alq << ". Stopping iteration."; result = true; } @@ -1570,9 +1520,8 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) // already checked in runOptimizeLoop_() by calling checkNegativeOilRate() assert(oil_rate >= 0); result = false; - } - else { - if (alq <= this->parent.min_alq_ ) { + } else { + if (alq <= this->parent.min_alq_) { // According to WLIFTOPT item 5: // "If a positive value is specified, the well is // allocated at least that amount of lift gas, @@ -1586,24 +1535,21 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) // checkRatesViolated(). // - We also know that the rate limit was not exceeded since that was // checked by checkRatesViolated() - assert( oil_rate >= 0); + assert(oil_rate >= 0); ss << "ALQ <= " << this->parent.min_alq_ << " (min limit), " - << "stopping iteration"; + << "stopping iteration"; result = true; - } - else { + } else { // NOTE: checking for an upper limit should not be necessary // when decreasing alq.. so this is just to catch an // illegal state at an early point. if (this->parent.checkALQequal_(alq, this->parent.max_alq_)) { return false; - } - else if (alq > this->parent.max_alq_) { - warn_( "unexpected: alq above upper limit when trying to " - "decrease lift gas. aborting iteration."); + } else if (alq > this->parent.max_alq_) { + warn_("unexpected: alq above upper limit when trying to " + "decrease lift gas. aborting iteration."); result = true; - } - else { + } else { result = false; } } @@ -1618,21 +1564,17 @@ checkAlqOutsideLimits(double alq, [[maybe_unused]] double oil_rate) } bool -GasLiftSingleWellGeneric:: -checkGroupALQrateExceeded(double delta_alq) const +GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq) const { - const auto &pairs = - group_info_.getWellGroups(well_name_); - for (const auto &[group_name, efficiency] : pairs) { + const auto& pairs = group_info_.getWellGroups(well_name_); + for (const auto& [group_name, efficiency] : pairs) { auto max_alq_opt = group_info_.maxAlq(group_name); if (max_alq_opt) { - double alq = - group_info_.alqRate(group_name) + efficiency * delta_alq; + double alq = group_info_.alqRate(group_name) + efficiency * delta_alq; if (alq > *max_alq_opt) { if (debug) { const std::string msg = fmt::format( - "Group {} : alq {} exceeds max_alq {}. Stopping iteration", - group_name, alq, *max_alq_opt); + "Group {} : alq {} exceeds max_alq {}. Stopping iteration", group_name, alq, *max_alq_opt); displayDebugMessage_(msg); } return true; @@ -1643,24 +1585,22 @@ checkGroupALQrateExceeded(double delta_alq) const } bool -GasLiftSingleWellGeneric:: -checkGroupTotalRateExceeded(double delta_alq, double delta_gas_rate) const +GasLiftSingleWellGeneric::checkGroupTotalRateExceeded(double delta_alq, double delta_gas_rate) const { - const auto &pairs = - group_info_.getWellGroups(well_name_); - for (const auto &[group_name, efficiency] : pairs) { + const auto& pairs = group_info_.getWellGroups(well_name_); + for (const auto& [group_name, efficiency] : pairs) { auto max_total_rate_opt = group_info_.maxTotalGasRate(group_name); if (max_total_rate_opt) { - double alq = - group_info_.alqRate(group_name) + efficiency * delta_alq; - double gas_rate = - group_info_.gasRate(group_name) + efficiency * delta_gas_rate; + double alq = group_info_.alqRate(group_name) + efficiency * delta_alq; + double gas_rate = group_info_.gasRate(group_name) + efficiency * delta_gas_rate; - if ( (alq + gas_rate) > *max_total_rate_opt) { + if ((alq + gas_rate) > *max_total_rate_opt) { if (debug) { - const std::string msg = fmt::format( - "Group {} : total gas rate {} exceeds max_total_gas_rate {}. Stopping iteration", - group_name, alq + gas_rate, *max_total_rate_opt); + const std::string msg + = fmt::format("Group {} : total gas rate {} exceeds max_total_gas_rate {}. Stopping iteration", + group_name, + alq + gas_rate, + *max_total_rate_opt); displayDebugMessage_(msg); } return true; @@ -1683,8 +1623,7 @@ checkGroupTotalRateExceeded(double delta_alq, double delta_gas_rate) const // lift gas until the gradient increases and reaches the economic gradient..) // bool -GasLiftSingleWellGeneric::OptimizeState:: -checkEcoGradient(double gradient) +GasLiftSingleWellGeneric::OptimizeState::checkEcoGradient(double gradient) { std::ostringstream ss; bool result = false; @@ -1693,68 +1632,67 @@ checkEcoGradient(double gradient) ss << "checking gradient: " << gradient; } if (this->increase) { - if (this->parent.debug) ss << " <= " << this->parent.eco_grad_ << " --> "; + if (this->parent.debug) + ss << " <= " << this->parent.eco_grad_ << " --> "; if (gradient <= this->parent.eco_grad_) { - if (this->parent.debug) ss << "yes, stopping"; + if (this->parent.debug) + ss << "yes, stopping"; result = true; + } else { + if (this->parent.debug) + ss << "no, continue"; } - else { - if (this->parent.debug) ss << "no, continue"; - } - } - else { // decreasing lift gas - if (this->parent.debug) ss << " >= " << this->parent.eco_grad_ << " --> "; + } else { // decreasing lift gas + if (this->parent.debug) + ss << " >= " << this->parent.eco_grad_ << " --> "; if (gradient >= this->parent.eco_grad_) { - if (this->parent.debug) ss << "yes, stopping"; + if (this->parent.debug) + ss << "yes, stopping"; result = true; - } - else { - if (this->parent.debug) ss << "no, continue"; + } else { + if (this->parent.debug) + ss << "no, continue"; } } - if (this->parent.debug) this->parent.displayDebugMessage_(ss.str()); + if (this->parent.debug) + this->parent.displayDebugMessage_(ss.str()); return result; } bool -GasLiftSingleWellGeneric::OptimizeState:: -checkRatesViolated(const LimitedRates& rates) const +GasLiftSingleWellGeneric::OptimizeState::checkRatesViolated(const LimitedRates& rates) const { if (!this->increase) { if (rates.oil < 0) { // The well is not flowing, and it will(?) not help to reduce lift // gas further. Note that this assumes that the oil rates drops with // decreasing lift gas. - this->parent.displayDebugMessage_( - "Negative oil rate detected while descreasing " - "lift gas. Stopping iteration."); + this->parent.displayDebugMessage_("Negative oil rate detected while descreasing " + "lift gas. Stopping iteration."); return true; } } if (rates.limited()) { if (this->parent.debug) { - const std::string well_or_group - = rates.limit_type == LimitedRates::LimitType::well ? "well" : "group"; + const std::string well_or_group = rates.limit_type == LimitedRates::LimitType::well ? "well" : "group"; std::string target_type; std::string rate_type; if (rates.oil_is_limited) { - target_type = GasLiftGroupInfo::rateToString( - *(rates.oil_limiting_target)); + target_type = GasLiftGroupInfo::rateToString(*(rates.oil_limiting_target)); rate_type = "oil"; - } - else if (rates.gas_is_limited) { + } else if (rates.gas_is_limited) { target_type = "gas"; rate_type = "gas"; - } - else if (rates.water_is_limited) { - target_type = GasLiftGroupInfo::rateToString( - *(rates.water_limiting_target)); + } else if (rates.water_is_limited) { + target_type = GasLiftGroupInfo::rateToString(*(rates.water_limiting_target)); rate_type = "water"; } - const std::string msg = fmt::format( - "iteration {} : {} rate was limited due to {} {} target. " - "Stopping iteration", - this->it, rate_type, well_or_group, target_type); + const std::string msg = fmt::format("iteration {} : {} rate was limited due to {} {} target. " + "Stopping iteration", + this->it, + rate_type, + well_or_group, + target_type); this->parent.displayDebugMessage_(msg); } return true; @@ -1763,8 +1701,7 @@ checkRatesViolated(const LimitedRates& rates) const } void -GasLiftSingleWellGeneric::OptimizeState:: -debugShowIterationInfo(double alq) +GasLiftSingleWellGeneric::OptimizeState::debugShowIterationInfo(double alq) { const std::string msg = fmt::format("iteration {}, ALQ = {}", this->it, alq); this->parent.displayDebugMessage_(msg); @@ -1782,8 +1719,7 @@ debugShowIterationInfo(double alq) // BHP limit? // double -GasLiftSingleWellGeneric::OptimizeState:: -getBhpWithLimit() +GasLiftSingleWellGeneric::OptimizeState::getBhpWithLimit() { auto [new_bhp, limited] = this->parent.getBhpWithLimit_(this->bhp); if (limited) { @@ -1804,8 +1740,7 @@ getBhpWithLimit() * Methods declared in BasicRates ****************************************/ -GasLiftSingleWellGeneric::BasicRates:: -BasicRates(const LimitedRates& rates) +GasLiftSingleWellGeneric::BasicRates::BasicRates(const LimitedRates& rates) { oil = rates.oil; gas = rates.gas; From 686a6a969d2d188e981ffb734ff836258843d469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Mon, 17 Oct 2022 22:05:35 +0200 Subject: [PATCH 04/11] Calculate gradients with group limits. Take into account group limits when calculating gradients for individual wells in stage 2 of gas lift optimization. --- .../wells/GasLiftSingleWellGeneric.cpp | 38 +++++++++++-------- .../wells/GasLiftSingleWellGeneric.hpp | 1 + opm/simulators/wells/GasLiftStage2.cpp | 2 +- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 3e734bba2..cbc6a33c4 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -86,8 +86,8 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logg ****************************************/ // NOTE: Used from GasLiftStage2 std::optional -GasLiftSingleWellGeneric:: -calcIncOrDecGradient(double oil_rate, double gas_rate, double alq, bool increase) const +GasLiftSingleWellGeneric::calcIncOrDecGradient( + double oil_rate, double gas_rate, double water_rate, double alq, bool increase) const { auto [new_alq_opt, alq_is_limited] = addOrSubtractAlqIncrement_(alq, increase); // TODO: What to do if ALQ is limited and new_alq != alq? @@ -98,21 +98,29 @@ calcIncOrDecGradient(double oil_rate, double gas_rate, double alq, bool increase auto [new_bhp, bhp_is_limited] = getBhpWithLimit_(*bhp); // TODO: What to do if BHP is limited? auto rates = computeWellRates_(new_bhp, bhp_is_limited); - double new_oil_rate, new_gas_rate, new_water_rate; - bool oil_is_limited, gas_is_limited, water_is_limited; - std::tie(new_oil_rate, oil_is_limited) = getOilRateWithLimit_(rates); - std::tie(new_gas_rate, gas_is_limited) = getGasRateWithLimit_(rates); - std::tie(new_water_rate, water_is_limited) = getWaterRateWithLimit_(rates); - if (!increase && new_oil_rate < 0 ) { + // double new_oil_rate, new_gas_rate, new_water_rate; + // bool oil_is_limited, gas_is_limited, water_is_limited; + // std::tie(new_oil_rate, oil_is_limited) = getOilRateWithLimit_(rates); + // std::tie(new_gas_rate, gas_is_limited) = getGasRateWithLimit_(rates); + // std::tie(new_water_rate, water_is_limited) = getWaterRateWithLimit_(rates); + const auto ratesLimited = getLimitedRatesFromRates_(rates); + BasicRates oldrates = {oil_rate, gas_rate, water_rate, false}; + const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited); + + if (!increase && new_rates.oil < 0) { return std::nullopt; } - auto grad = calcEcoGradient_( - oil_rate, new_oil_rate, gas_rate, new_gas_rate, increase); - return GradInfo(grad, new_oil_rate, oil_is_limited, - new_gas_rate, gas_is_limited, new_water_rate, water_is_limited, - new_alq, alq_is_limited); - } - else { + auto grad = calcEcoGradient_(oil_rate, new_rates.oil, gas_rate, new_rates.gas, increase); + return GradInfo(grad, + new_rates.oil, + new_rates.oil_is_limited, + new_rates.gas, + new_rates.gas_is_limited, + new_rates.water, + new_rates.water_is_limited, + new_alq, + alq_is_limited); + } else { return std::nullopt; } } diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp index 82613fb0e..62631e350 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp @@ -93,6 +93,7 @@ public: const std::string& name() const { return well_name_; } std::optional calcIncOrDecGradient(double oil_rate, double gas_rate, + double water_rate, double alq, bool increase) const; std::unique_ptr runOptimize(const int iteration_idx); diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 415eaf741..1ec7e2d14 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -157,7 +157,7 @@ calcIncOrDecGrad_( else { auto [oil_rate, gas_rate] = state.getRates(); auto alq = state.alq(); - auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, alq, increase); + auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, increase); if (grad) { const std::string msg = fmt::format( "well {} : adding {} gradient = {}", From 43244c21322ad3de9ccdf8a55b7f6b79d487880d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Thu, 20 Oct 2022 12:58:42 +0200 Subject: [PATCH 05/11] Change condition under which stage 2 is done. It only makes sense to try to optimize the distribution of lift gas if the amount of lift gas is constrained either by the maximum allowed gaslift or total gas or the group is under individual control. --- .../wells/BlackoilWellModelGeneric.cpp | 1 + opm/simulators/wells/BlackoilWellModel_impl.hpp | 1 + opm/simulators/wells/GasLiftCommon.cpp | 2 ++ opm/simulators/wells/GasLiftCommon.hpp | 3 +++ opm/simulators/wells/GasLiftGroupInfo.cpp | 3 ++- opm/simulators/wells/GasLiftGroupInfo.hpp | 2 ++ .../wells/GasLiftSingleWellGeneric.cpp | 3 +-- .../wells/GasLiftSingleWellGeneric.hpp | 2 +- opm/simulators/wells/GasLiftStage2.cpp | 17 ++++++++++++----- opm/simulators/wells/GasLiftStage2.hpp | 2 ++ tests/test_glift1.cpp | 1 + 11 files changed, 28 insertions(+), 9 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index 94bfc6f90..ac0b46874 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -1053,6 +1053,7 @@ gasLiftOptimizationStage2(DeferredLogger& deferred_logger, summaryState_, deferred_logger, this->wellState(), + this->groupState(), prod_wells, glift_wells, glift_well_state_map, diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index ff0fdfaac..d2c11a5e5 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -986,6 +986,7 @@ namespace Opm { phase_usage_, deferred_logger, this->wellState(), + this->groupState(), ebosSimulator_.vanguard().grid().comm(), this->glift_debug }; diff --git a/opm/simulators/wells/GasLiftCommon.cpp b/opm/simulators/wells/GasLiftCommon.cpp index b9cf16c25..a2298178c 100644 --- a/opm/simulators/wells/GasLiftCommon.cpp +++ b/opm/simulators/wells/GasLiftCommon.cpp @@ -25,11 +25,13 @@ namespace Opm { GasLiftCommon:: GasLiftCommon( WellState &well_state, + const GroupState &group_state, DeferredLogger &deferred_logger, const Parallel::Communication& comm, bool glift_debug ) : well_state_{well_state}, + group_state_{group_state}, deferred_logger_{deferred_logger}, comm_{comm}, debug{glift_debug} diff --git a/opm/simulators/wells/GasLiftCommon.hpp b/opm/simulators/wells/GasLiftCommon.hpp index deb74b8ff..308f7adc4 100644 --- a/opm/simulators/wells/GasLiftCommon.hpp +++ b/opm/simulators/wells/GasLiftCommon.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ public: protected: GasLiftCommon( WellState &well_state, + const GroupState &group_state, DeferredLogger &deferred_logger, const Parallel::Communication& comm, bool debug @@ -51,6 +53,7 @@ protected: MessageType msg_type = MessageType::INFO) const; WellState &well_state_; + const GroupState& group_state_; DeferredLogger &deferred_logger_; const Parallel::Communication& comm_; bool debug; diff --git a/opm/simulators/wells/GasLiftGroupInfo.cpp b/opm/simulators/wells/GasLiftGroupInfo.cpp index 9a50025dd..2fb8d3521 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.cpp +++ b/opm/simulators/wells/GasLiftGroupInfo.cpp @@ -32,10 +32,11 @@ GasLiftGroupInfo( const PhaseUsage &phase_usage, DeferredLogger &deferred_logger, WellState &well_state, + const GroupState &group_state, const Communication &comm, bool glift_debug ) : - GasLiftCommon(well_state, deferred_logger, comm, glift_debug) + GasLiftCommon(well_state, group_state, deferred_logger, comm, glift_debug) , ecl_wells_{ecl_wells} , schedule_{schedule} , summary_state_{summary_state} diff --git a/opm/simulators/wells/GasLiftGroupInfo.hpp b/opm/simulators/wells/GasLiftGroupInfo.hpp index 910108c8f..cfe3762a2 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.hpp +++ b/opm/simulators/wells/GasLiftGroupInfo.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,7 @@ public: const PhaseUsage& phase_usage, DeferredLogger& deferred_logger, WellState& well_state, + const GroupState& group_state, const Parallel::Communication& comm, bool glift_debug ); diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index cbc6a33c4..34bb7bc28 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -49,8 +49,7 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logg GLiftSyncGroups& sync_groups, const Parallel::Communication& comm, bool glift_debug) - : GasLiftCommon(well_state, deferred_logger, comm, glift_debug) - , group_state_ {group_state} + : GasLiftCommon(well_state, group_state, deferred_logger, comm, glift_debug) , ecl_well_ {ecl_well} , summary_state_ {summary_state} , group_info_ {group_info} diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp index 62631e350..c015b2c4c 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -329,7 +330,6 @@ protected: Rate rate_type, const std::string& gr_name, double rate, double target) const; void warnMaxIterationsExceeded_(); - const GroupState& group_state_; const Well& ecl_well_; const SummaryState& summary_state_; GasLiftGroupInfo& group_info_; diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 1ec7e2d14..8958e525f 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -44,12 +44,13 @@ GasLiftStage2::GasLiftStage2( const SummaryState& summary_state, DeferredLogger &deferred_logger, WellState &well_state, + const GroupState &group_state, GLiftProdWells &prod_wells, GLiftOptWells &glift_wells, GLiftWellStateMap &state_map, bool glift_debug ) : - GasLiftCommon(well_state, deferred_logger, comm, glift_debug) + GasLiftCommon(well_state, group_state, deferred_logger, comm, glift_debug) , prod_wells_{prod_wells} , stage1_wells_{glift_wells} , well_state_map_{state_map} @@ -545,10 +546,16 @@ optimizeGroup_(const Group &group) { const auto max_glift = getGroupMaxALQ_(group); const auto max_total_gas = getGroupMaxTotalGas_(group); - if (group.has_control(Group::ProductionCMode::ORAT) || group.has_control(Group::ProductionCMode::LRAT) - || max_glift || max_total_gas) + const auto& group_name = group.name(); + const auto prod_control = this->group_state_.production_control(group_name); + //if (group.has_control(Group::ProductionCMode::ORAT) || group.has_control(Group::ProductionCMode::LRAT) + // || max_glift || max_total_gas) + // NOTE: it only makes sense to try to optimize the distribution of the gaslift if the amount + // of gaslift is constrained either by the maximum allowed gaslift or total gas + // or the group is under individual control + if ((prod_control != Group::ProductionCMode::NONE) && (prod_control != Group::ProductionCMode::FLD)) { - displayDebugMessage_("optimizing", group.name()); + displayDebugMessage_("optimizing", group_name); auto wells = getGroupGliftWells_(group); std::vector inc_grads; std::vector dec_grads; @@ -556,7 +563,7 @@ optimizeGroup_(const Group &group) removeSurplusALQ_(group, inc_grads, dec_grads); } else { - displayDebugMessage_("skipping", group.name()); + displayDebugMessage_("skipping", group_name); } } diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index ba86770d6..0c30bafad 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -66,6 +67,7 @@ public: const SummaryState& summary_state, DeferredLogger& deferred_logger, WellState& well_state, + const GroupState& group_state, GLiftProdWells& prod_wells, GLiftOptWells& glift_wells, GLiftWellStateMap& state_map, diff --git a/tests/test_glift1.cpp b/tests/test_glift1.cpp index bc59097a6..31de21fe5 100644 --- a/tests/test_glift1.cpp +++ b/tests/test_glift1.cpp @@ -181,6 +181,7 @@ BOOST_AUTO_TEST_CASE(G1) well_model.phaseUsage(), deferred_logger, well_state, + group_state, comm, /*glift_debug=*/false }; From c313a0a4b257532624febd4707a4cde892ab549f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Thu, 20 Oct 2022 22:12:34 +0200 Subject: [PATCH 06/11] Remove unused variables --- opm/simulators/wells/GasLiftStage2.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 8958e525f..6a97b47b4 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -544,8 +544,6 @@ void GasLiftStage2:: optimizeGroup_(const Group &group) { - const auto max_glift = getGroupMaxALQ_(group); - const auto max_total_gas = getGroupMaxTotalGas_(group); const auto& group_name = group.name(); const auto prod_control = this->group_state_.production_control(group_name); //if (group.has_control(Group::ProductionCMode::ORAT) || group.has_control(Group::ProductionCMode::LRAT) From cd09c130b31328c5257d73af7143a232340b1403 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Wed, 26 Oct 2022 08:51:38 +0200 Subject: [PATCH 07/11] pass group name to getRateWithGroupLimit to avoid checking for that --- .../wells/GasLiftSingleWellGeneric.cpp | 46 ++++++++++++------- .../wells/GasLiftSingleWellGeneric.hpp | 17 +++---- opm/simulators/wells/GasLiftStage2.cpp | 18 ++++---- opm/simulators/wells/GasLiftStage2.hpp | 4 +- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 34bb7bc28..2683153ca 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -86,13 +86,19 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logg // NOTE: Used from GasLiftStage2 std::optional GasLiftSingleWellGeneric::calcIncOrDecGradient( - double oil_rate, double gas_rate, double water_rate, double alq, bool increase) const + double oil_rate, double gas_rate, double water_rate, double alq, const Group& group, bool increase) const { auto [new_alq_opt, alq_is_limited] = addOrSubtractAlqIncrement_(alq, increase); // TODO: What to do if ALQ is limited and new_alq != alq? if (!new_alq_opt) return std::nullopt; + double new_alq = *new_alq_opt; + + auto delta_alq = new_alq - alq; + if (checkGroupALQrateExceeded(delta_alq, group.name())) + return std::nullopt; + if (auto bhp = computeBhpAtThpLimit_(new_alq)) { auto [new_bhp, bhp_is_limited] = getBhpWithLimit_(*bhp); // TODO: What to do if BHP is limited? @@ -104,7 +110,7 @@ GasLiftSingleWellGeneric::calcIncOrDecGradient( // std::tie(new_water_rate, water_is_limited) = getWaterRateWithLimit_(rates); const auto ratesLimited = getLimitedRatesFromRates_(rates); BasicRates oldrates = {oil_rate, gas_rate, water_rate, false}; - const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited); + const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited, group.name()); if (!increase && new_rates.oil < 0) { return std::nullopt; @@ -667,25 +673,25 @@ GasLiftSingleWellGeneric::getRateWithLimit_(Rate rate_type, const BasicRates& ra } std::pair -GasLiftSingleWellGeneric::getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate) const +GasLiftSingleWellGeneric::getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate, const std::string& gr_name_no_check) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate, gr_name_no_check); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric::getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate) const +GasLiftSingleWellGeneric::getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate, const std::string& gr_name_no_check) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate, gr_name_no_check); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric::getWaterRateWithGroupLimit_(double new_water_rate, double water_rate) const +GasLiftSingleWellGeneric::getWaterRateWithGroupLimit_(double new_water_rate, double water_rate, const std::string& gr_name_no_check) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::water, new_water_rate, water_rate); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::water, new_water_rate, water_rate, gr_name_no_check); bool limited = gr_name != nullptr; return {rate, limited}; } @@ -694,12 +700,13 @@ 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 water_rate, + const std::string& gr_name_no_check) const { auto liquid_rate = oil_rate + water_rate; auto new_liquid_rate = new_oil_rate + new_water_rate; auto [liquid_rate_limited, group_name, efficiency] - = getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate); + = getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate, gr_name_no_check); bool limited = group_name != nullptr; if (limited) { // the oil, gas, and water cases can be handled directly by @@ -730,7 +737,7 @@ GasLiftSingleWellGeneric::getLiquidRateWithGroupLimit_(const double new_oil_rate } std::tuple -GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double new_rate, const double old_rate) const +GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_no_check) const { const double delta_rate = new_rate - old_rate; if (delta_rate > 0) { @@ -743,6 +750,9 @@ GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double ne double gr_target, new_gr_rate, efficiency; const std::string* group_name = nullptr; for (const auto& [group_name_temp, efficiency_temp] : pairs) { + if (gr_name_no_check == group_name_temp) + continue; + auto gr_target_opt = this->group_info_.getTarget(rate_type, group_name_temp); if (gr_target_opt) { double gr_target_temp = *gr_target_opt; @@ -1346,20 +1356,20 @@ GasLiftSingleWellGeneric::updateGroupRates_(const LimitedRates& rates, } GasLiftSingleWellGeneric::LimitedRates -GasLiftSingleWellGeneric::updateRatesToGroupLimits_(const BasicRates& old_rates, const LimitedRates& rates) const +GasLiftSingleWellGeneric::updateRatesToGroupLimits_(const BasicRates& old_rates, const LimitedRates& rates, const std::string& gr_name) const { LimitedRates new_rates = rates; - auto [new_oil_rate, oil_is_limited] = getOilRateWithGroupLimit_(new_rates.oil, old_rates.oil); + auto [new_oil_rate, oil_is_limited] = getOilRateWithGroupLimit_(new_rates.oil, old_rates.oil, gr_name); if (oil_is_limited) { new_rates.oil_limiting_target = Rate::oil; } - auto [new_gas_rate, gas_is_limited] = getGasRateWithGroupLimit_(new_rates.gas, old_rates.gas); - auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_(new_rates.water, old_rates.water); + auto [new_gas_rate, gas_is_limited] = getGasRateWithGroupLimit_(new_rates.gas, old_rates.gas, gr_name); + auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_(new_rates.water, old_rates.water, gr_name); if (water_is_limited) { new_rates.water_limiting_target = Rate::water; } auto [new_oil_rate2, new_water_rate2, oil_is_limited2, water_is_limited2] - = getLiquidRateWithGroupLimit_(new_oil_rate, old_rates.oil, new_water_rate, old_rates.water); + = getLiquidRateWithGroupLimit_(new_oil_rate, old_rates.oil, new_water_rate, old_rates.water, gr_name); if (oil_is_limited2) { new_rates.oil_limiting_target = Rate::liquid; } @@ -1571,10 +1581,12 @@ GasLiftSingleWellGeneric::OptimizeState::checkAlqOutsideLimits(double alq, [[may } bool -GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq) const +GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_no_check) const { const auto& pairs = group_info_.getWellGroups(well_name_); for (const auto& [group_name, efficiency] : pairs) { + if (gr_name_no_check == group_name) + continue; auto max_alq_opt = group_info_.maxAlq(group_name); if (max_alq_opt) { double alq = group_info_.alqRate(group_name) + efficiency * delta_alq; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp index c015b2c4c..24853cdb8 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp @@ -95,7 +95,8 @@ public: std::optional calcIncOrDecGradient(double oil_rate, double gas_rate, double water_rate, - double alq, bool increase) const; + double alq, + const Group& group, bool increase) const; std::unique_ptr runOptimize(const int iteration_idx); @@ -239,7 +240,7 @@ protected: double getBhpWithLimit(); void warn_(std::string msg) {parent.displayWarning_(msg);} }; - bool checkGroupALQrateExceeded(double delta_alq) const; + bool checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_no_check = "") const; bool checkGroupTotalRateExceeded(double delta_alq, double delta_gas_rate) const; std::pair, bool> addOrSubtractAlqIncrement_( @@ -274,14 +275,14 @@ protected: std::pair getGasRateWithLimit_( const BasicRates& rates) const; std::pair getGasRateWithGroupLimit_( - double new_gas_rate, double gas_rate) const; + double new_gas_rate, double gas_rate, const std::string& gr_name_no_check) const; std::pair,double> getInitialRatesWithLimit_() const; LimitedRates getLimitedRatesFromRates_(const BasicRates& rates) const; std::tuple getLiquidRateWithGroupLimit_( const double new_oil_rate, const double oil_rate, - const double new_water_rate, const double water_rate) const; + const double new_water_rate, const double water_rate, const std::string& gr_name_no_check) const; std::pair getOilRateWithGroupLimit_( - double new_oil_rate, double oil_rate) const; + double new_oil_rate, double oil_rate, const std::string& gr_name_no_check) const; std::pair getOilRateWithLimit_(const BasicRates& rates) const; std::pair> getOilRateWithLimit2_( const BasicRates& rates) const; @@ -290,9 +291,9 @@ protected: std::pair> getRateWithLimit_( Rate rate_type, const BasicRates& rates) const; std::tuple getRateWithGroupLimit_( - Rate rate_type, const double new_rate, const double old_rate) const; + Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_no_check) const; std::pair getWaterRateWithGroupLimit_( - double new_water_rate, double water_rate) const; + double new_water_rate, double water_rate, const std::string& gr_name_no_check) const; std::pair getWaterRateWithLimit_(const BasicRates& rates) const; std::pair> getWaterRateWithLimit2_( const BasicRates& rates) const; @@ -323,7 +324,7 @@ protected: const LimitedRates& new_rates, double delta_alq) const; LimitedRates updateRatesToGroupLimits_( - const BasicRates& rates, const LimitedRates& new_rates) const; + const BasicRates& rates, const LimitedRates& new_rates, const std::string& gr_name = "") const; void updateWellStateAlqFixedValue_(const GasLiftOpt::Well& well); bool useFixedAlq_(const GasLiftOpt::Well& well); void debugInfoGroupRatesExceedTarget( diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 6a97b47b4..82eb4370a 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -132,7 +132,7 @@ addOrRemoveALQincrement_(GradMap &grad_map, const std::string& well_name, bool a std::optional GasLiftStage2:: calcIncOrDecGrad_( - const std::string well_name, const GasLiftSingleWell &gs_well, bool increase) + const std::string well_name, const GasLiftSingleWell &gs_well, const Group& group, bool increase) { // only applies to wells in the well_state_map (i.e. wells on this rank) @@ -158,7 +158,7 @@ calcIncOrDecGrad_( else { auto [oil_rate, gas_rate] = state.getRates(); auto alq = state.alq(); - auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, increase); + auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, group, increase); if (grad) { const std::string msg = fmt::format( "well {} : adding {} gradient = {}", @@ -582,7 +582,7 @@ optimizeGroupsRecursive_(const Group &group) void GasLiftStage2:: recalculateGradientAndUpdateData_( - GradPairItr &grad_itr, bool increase, + GradPairItr &grad_itr, const Group& group, bool increase, //incremental and decremental gradients, if 'grads' are incremental, then // 'other_grads' are decremental, or conversely, if 'grads' are decremental, then @@ -598,7 +598,7 @@ recalculateGradientAndUpdateData_( // the grads and other grads are synchronized later if(this->stage1_wells_.count(name) > 0) { GasLiftSingleWell &gs_well = *(this->stage1_wells_.at(name).get()); - auto grad = calcIncOrDecGrad_(name, gs_well, increase); + auto grad = calcIncOrDecGrad_(name, gs_well, group, increase); if (grad) { grad_itr->second = grad->grad; old_grad = updateGrad_(name, *grad, increase); @@ -785,7 +785,7 @@ removeSurplusALQ_(const Group &group, state.updateRates(well_name); state.addOrRemoveALQincrement( this->dec_grads_, well_name, /*add=*/false); recalculateGradientAndUpdateData_( - dec_grad_itr, /*increase=*/false, dec_grads, inc_grads); + dec_grad_itr, group, /*increase=*/false, dec_grads, inc_grads); // The dec_grads and inc_grads needs to be syncronized across ranks mpiSyncGlobalGradVector_(dec_grads); @@ -892,12 +892,12 @@ calculateEcoGradients(std::vector &wells, for (auto well_ptr : wells) { const auto &gs_well = *well_ptr; // gs = GasLiftSingleWell const auto &name = gs_well.name(); - auto inc_grad = this->parent.calcIncOrDecGrad_(name, gs_well, /*increase=*/true); + auto inc_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group, /*increase=*/true); if (inc_grad) { inc_grads.emplace_back(std::make_pair(name, inc_grad->grad)); this->parent.saveIncGrad_(name, *inc_grad); } - auto dec_grad = this->parent.calcIncOrDecGrad_(name, gs_well, /*increase=*/false); + auto dec_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group, /*increase=*/false); if (dec_grad) { dec_grads.emplace_back(std::make_pair(name, dec_grad->grad)); this->parent.saveDecGrad_(name, *dec_grad); @@ -984,9 +984,9 @@ recalculateGradients( GradPairItr &min_dec_grad_itr, GradPairItr &max_inc_grad_itr) { this->parent.recalculateGradientAndUpdateData_( - max_inc_grad_itr, /*increase=*/true, inc_grads, dec_grads); + max_inc_grad_itr, this->group, /*increase=*/true, inc_grads, dec_grads); this->parent.recalculateGradientAndUpdateData_( - min_dec_grad_itr, /*increase=*/false, dec_grads, inc_grads); + min_dec_grad_itr, this->group, /*increase=*/false, dec_grads, inc_grads); // The dec_grads and inc_grads needs to be syncronized across ranks this->parent.mpiSyncGlobalGradVector_(dec_grads); diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index 0c30bafad..a1321d0dc 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -78,7 +78,7 @@ protected: void addOrRemoveALQincrement_( GradMap& grad_map, const std::string& well_name, bool add); std::optional calcIncOrDecGrad_( - const std::string name, const GasLiftSingleWell& gs_well, bool increase); + const std::string name, const GasLiftSingleWell& gs_well, const Group& group, bool increase); bool checkRateAlreadyLimited_(GasLiftWellState& state, bool increase); GradInfo deleteDecGradItem_(const std::string& name); GradInfo deleteIncGradItem_(const std::string& name); @@ -102,7 +102,7 @@ protected: void optimizeGroup_(const Group& group); void optimizeGroupsRecursive_(const Group& group); void recalculateGradientAndUpdateData_( - GradPairItr& grad_itr, bool increase, + GradPairItr& grad_itr, const Group& group, bool increase, std::vector& grads, std::vector& other_grads); void redistributeALQ_( std::vector& wells, const Group& group, From 1a09608263ce65624bc082dd471e2174f451d344 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Thu, 27 Oct 2022 15:52:12 +0200 Subject: [PATCH 08/11] Fix removeSurplus alq Add water rate target limit Add the gradient to the checkXXXTarget so that surplus alq is removed until it would go below the target. I.e. the group still want to produce it target --- .../wells/GasLiftSingleWellGeneric.cpp | 4 +- opm/simulators/wells/GasLiftStage2.cpp | 61 ++++++++++++------- opm/simulators/wells/GasLiftStage2.hpp | 11 ++-- opm/simulators/wells/GasLiftWellState.hpp | 7 ++- 4 files changed, 56 insertions(+), 27 deletions(-) diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 2683153ca..e204939e9 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -750,8 +750,9 @@ GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double ne double gr_target, new_gr_rate, efficiency; const std::string* group_name = nullptr; for (const auto& [group_name_temp, efficiency_temp] : pairs) { - if (gr_name_no_check == group_name_temp) + if (gr_name_no_check == group_name_temp) { continue; + } auto gr_target_opt = this->group_info_.getTarget(rate_type, group_name_temp); if (gr_target_opt) { @@ -1251,6 +1252,7 @@ GasLiftSingleWellGeneric::runOptimizeLoop_(bool increase) cur_alq, alq_is_limited, new_rates.water, + new_rates.water_is_limited, increase_opt); return ret_value; } diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 82eb4370a..526bf6f93 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -115,18 +115,19 @@ addOrRemoveALQincrement_(GradMap &grad_map, const std::string& well_name, bool a } state.update(gi.new_oil_rate, gi.oil_is_limited, gi.new_gas_rate, gi.gas_is_limited, - gi.alq, gi.alq_is_limited, gi.new_water_rate, add); - this->well_state_.setALQ(well_name, gi.alq); - const auto& pu = this->well_state_.phaseUsage(); - std::vector well_pot(pu.num_phases, 0.0); - if(pu.phase_used[BlackoilPhases::PhaseIndex::Liquid]) - well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Liquid]] = gi.new_oil_rate; - if(pu.phase_used[BlackoilPhases::PhaseIndex::Aqua]) - well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Aqua]] = gi.new_water_rate; - if(pu.phase_used[BlackoilPhases::PhaseIndex::Vapour]) - well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Vapour]] = gi.new_gas_rate; + gi.alq, gi.alq_is_limited, gi.new_water_rate, gi.water_is_limited, add); - this->well_state_[well_name].well_potentials = well_pot; + this->well_state_.setALQ(well_name, gi.alq); + const auto& pu = this->well_state_.phaseUsage(); + std::vector well_pot(pu.num_phases, 0.0); + if(pu.phase_used[BlackoilPhases::PhaseIndex::Liquid]) + well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Liquid]] = gi.new_oil_rate; + if(pu.phase_used[BlackoilPhases::PhaseIndex::Aqua]) + well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Aqua]] = gi.new_water_rate; + if(pu.phase_used[BlackoilPhases::PhaseIndex::Vapour]) + well_pot[pu.phase_pos[BlackoilPhases::PhaseIndex::Vapour]] = gi.new_gas_rate; + + this->well_state_[well_name].well_potentials = well_pot; } std::optional @@ -192,7 +193,7 @@ checkRateAlreadyLimited_(GasLiftWellState &state, bool increase) if (increase) do_check = true; } if (do_check) { - if (state.gasIsLimited() || state.oilIsLimited() || state.alqIsLimited()) { + if (state.gasIsLimited() || state.oilIsLimited() || state.alqIsLimited() || state.waterIsLimited()) { const std::string msg = fmt::format( "{} gradient : skipping since {} was limited in previous step", (increase ? "incremental" : "decremental"), @@ -757,7 +758,7 @@ removeSurplusALQ_(const Group &group, displayDebugMessage_(msg); } SurplusState state {*this, group, oil_rate, gas_rate, water_rate, alq, - min_eco_grad, controls.oil_target, controls.gas_target, + min_eco_grad, controls.oil_target, controls.gas_target, controls.water_target, controls.liquid_target, max_glift }; while (!stop_iteration) { @@ -768,8 +769,8 @@ removeSurplusALQ_(const Group &group, const auto well_name = dec_grad_itr->first; auto eco_grad = dec_grad_itr->second; bool remove = false; - if (state.checkOilTarget() || state.checkGasTarget() - || state.checkLiquidTarget() || state.checkALQlimit()) + if (state.checkOilTarget(eco_grad) || state.checkGasTarget(eco_grad) + || state.checkLiquidTarget(eco_grad) || state.checkWaterTarget(eco_grad) || state.checkALQlimit()) { remove = true; } @@ -1085,10 +1086,10 @@ checkEcoGradient(const std::string &well_name, double eco_grad) bool GasLiftStage2::SurplusState:: -checkGasTarget() +checkGasTarget(double eco_grad) { if (this->group.has_control(Group::ProductionCMode::GRAT)) { - if (this->gas_target < this->gas_rate ) { + if (this->gas_target < (this->gas_rate - eco_grad) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "gas rate {} is greater than gas target {}", this->group.name(), @@ -1102,11 +1103,11 @@ checkGasTarget() } bool GasLiftStage2::SurplusState:: -checkLiquidTarget() +checkLiquidTarget(double eco_grad) { if (this->group.has_control(Group::ProductionCMode::LRAT)) { auto liquid_rate = this->oil_rate + this->water_rate; - if (this->liquid_target < liquid_rate ) { + if (this->liquid_target < (liquid_rate - eco_grad) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "liquid rate {} is greater than liquid target {}", this->group.name(), @@ -1121,10 +1122,10 @@ checkLiquidTarget() bool GasLiftStage2::SurplusState:: -checkOilTarget() +checkOilTarget(double eco_grad) { if (this->group.has_control(Group::ProductionCMode::ORAT)) { - if (this->oil_target < this->oil_rate ) { + if (this->oil_target < (this->oil_rate - eco_grad) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "oil rate {} is greater than oil target {}", this->group.name(), @@ -1137,6 +1138,24 @@ checkOilTarget() return false; } +bool +GasLiftStage2::SurplusState:: +checkWaterTarget(double eco_grad) +{ + if (this->group.has_control(Group::ProductionCMode::WRAT)) { + if (this->water_target < (this->water_rate - eco_grad) ) { + if (this->parent.debug) { + const std::string msg = fmt::format("group: {} : " + "water rate {} is greater than oil target {}", this->group.name(), + this->water_rate, this->water_target); + this->parent.displayDebugMessage_(msg); + } + return true; + } + } + return false; +} + void GasLiftStage2::SurplusState:: updateRates(const std::string &well_name) diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index a1321d0dc..d1ffa6294 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -173,7 +173,7 @@ protected: SurplusState( GasLiftStage2& parent_, const Group& group_, double oil_rate_, double gas_rate_, double water_rate_, double alq_, double min_eco_grad_, - double oil_target_, double gas_target_, double liquid_target_, + double oil_target_, double gas_target_, double water_target_, double liquid_target_, std::optional max_glift_) : parent{parent_}, group{group_}, @@ -184,6 +184,7 @@ protected: min_eco_grad{min_eco_grad_}, oil_target{oil_target_}, gas_target{gas_target_}, + water_target(water_target_), liquid_target{liquid_target_}, max_glift{max_glift_}, it{0} @@ -197,6 +198,7 @@ protected: const double min_eco_grad; const double oil_target; const double gas_target; + const double water_target; const double liquid_target; std::optional max_glift; int it; @@ -205,9 +207,10 @@ protected: GradMap &grad_map, const std::string& well_name, bool add); bool checkALQlimit(); bool checkEcoGradient(const std::string& well_name, double eco_grad); - bool checkGasTarget(); - bool checkLiquidTarget(); - bool checkOilTarget(); + bool checkGasTarget(double eco_grad); + bool checkLiquidTarget(double eco_grad); + bool checkOilTarget(double eco_grad); + bool checkWaterTarget(double eco_grad); void updateRates(const std::string& name); }; }; diff --git a/opm/simulators/wells/GasLiftWellState.hpp b/opm/simulators/wells/GasLiftWellState.hpp index 204ed7534..3bda6db71 100644 --- a/opm/simulators/wells/GasLiftWellState.hpp +++ b/opm/simulators/wells/GasLiftWellState.hpp @@ -31,7 +31,7 @@ namespace Opm //GasLiftWellState() { } GasLiftWellState(double oil_rate, bool oil_is_limited, double gas_rate, bool gas_is_limited, - double alq, bool alq_is_limited, double water_rate, std::optional increase) : + double alq, bool alq_is_limited, double water_rate, bool water_is_limited, std::optional increase) : oil_rate_{oil_rate}, oil_is_limited_{oil_is_limited}, gas_rate_{gas_rate}, @@ -39,6 +39,7 @@ namespace Opm alq_{alq}, alq_is_limited_{alq_is_limited}, water_rate_{water_rate}, + water_is_limited_{water_is_limited}, increase_{increase} {} double alq() const { return alq_; } @@ -51,9 +52,11 @@ namespace Opm bool oilIsLimited() const { return oil_is_limited_; } double oilRate() const { return oil_rate_; } double waterRate() const { return water_rate_; } + bool waterIsLimited() const { return water_is_limited_; } void update(double oil_rate, bool oil_is_limited, double gas_rate, bool gas_is_limited, double alq, bool alq_is_limited, double water_rate, + double water_is_limited, bool increase) { oil_rate_ = oil_rate; @@ -63,6 +66,7 @@ namespace Opm alq_ = alq; alq_is_limited_ = alq_is_limited; water_rate_ = water_rate; + water_is_limited_ = water_is_limited; increase_ = increase; } private: @@ -73,6 +77,7 @@ namespace Opm double alq_; bool alq_is_limited_; double water_rate_; + bool water_is_limited_; std::optional increase_; }; From 9c8f7784958fa2009199bc0c541ff17746382720 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Thu, 3 Nov 2022 09:02:41 +0100 Subject: [PATCH 09/11] Compute the group rates that takes into account limitation on the sublevels --- .../wells/BlackoilWellModelGeneric.cpp | 2 + .../wells/BlackoilWellModelGeneric.hpp | 2 + .../wells/BlackoilWellModel_impl.hpp | 2 +- opm/simulators/wells/GasLiftGroupInfo.cpp | 111 +++++++++++-- opm/simulators/wells/GasLiftGroupInfo.hpp | 19 ++- .../wells/GasLiftSingleWellGeneric.cpp | 2 +- opm/simulators/wells/GasLiftStage2.cpp | 156 +----------------- opm/simulators/wells/GasLiftStage2.hpp | 6 +- 8 files changed, 129 insertions(+), 171 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index ac0b46874..232a2cde4 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -1044,6 +1044,7 @@ BlackoilWellModelGeneric:: gasLiftOptimizationStage2(DeferredLogger& deferred_logger, GLiftProdWells& prod_wells, GLiftOptWells& glift_wells, + GasLiftGroupInfo& group_info, GLiftWellStateMap& glift_well_state_map, const int episodeIndex) { @@ -1056,6 +1057,7 @@ gasLiftOptimizationStage2(DeferredLogger& deferred_logger, this->groupState(), prod_wells, glift_wells, + group_info, glift_well_state_map, this->glift_debug }; diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 48fd43362..9f90d9ca9 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -47,6 +47,7 @@ namespace Opm { class EclipseState; class GasLiftSingleWellGeneric; class GasLiftWellState; + class GasLiftGroupInfo; class Group; class GuideRateConfig; class ParallelWellInfo; @@ -305,6 +306,7 @@ protected: void gasLiftOptimizationStage2(DeferredLogger& deferred_logger, GLiftProdWells& prod_wells, GLiftOptWells& glift_wells, + GasLiftGroupInfo& group_info, GLiftWellStateMap& map, const int episodeIndex); diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index d2c11a5e5..2de06057a 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -994,7 +994,7 @@ namespace Opm { gasLiftOptimizationStage1( deferred_logger, prod_wells, glift_wells, group_info, state_map); gasLiftOptimizationStage2( - deferred_logger, prod_wells, glift_wells, state_map, + deferred_logger, prod_wells, glift_wells, group_info, state_map, ebosSimulator_.episodeIndex()); if (this->glift_debug) gliftDebugShowALQ(deferred_logger); num_wells_changed = glift_wells.size(); diff --git a/opm/simulators/wells/GasLiftGroupInfo.cpp b/opm/simulators/wells/GasLiftGroupInfo.cpp index 2fb8d3521..2c5eb1b70 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.cpp +++ b/opm/simulators/wells/GasLiftGroupInfo.cpp @@ -75,6 +75,28 @@ gasRate(const std::string& group_name) const return group_rate.gasRate(); } +double +GasLiftGroupInfo:: +gasPotential(const std::string& group_name) const +{ + auto& group_rate = this->group_rate_map_.at(group_name); + return group_rate.gasPotential(); +} +double +GasLiftGroupInfo:: +waterPotential(const std::string& group_name) const +{ + auto& group_rate = this->group_rate_map_.at(group_name); + return group_rate.waterPotential(); +} +double +GasLiftGroupInfo:: +oilPotential(const std::string& group_name) const +{ + auto& group_rate = this->group_rate_map_.at(group_name); + return group_rate.oilPotential(); +} + std::optional GasLiftGroupInfo:: gasTarget(const std::string& group_name) const @@ -101,6 +123,24 @@ getRate(Rate rate_type, const std::string& group_name) const throw std::runtime_error("This should not happen"); } } +double +GasLiftGroupInfo:: +getPotential(Rate rate_type, const std::string& group_name) const +{ + switch (rate_type) { + case Rate::oil: + return oilPotential(group_name); + case Rate::gas: + return gasPotential(group_name); + case Rate::water: + return waterPotential(group_name); + case Rate::liquid: + return oilPotential(group_name) + waterPotential(group_name); + default: + // Need this to avoid compiler warning : control reaches end of non-void function + throw std::runtime_error("This should not happen"); + } +} std::tuple GasLiftGroupInfo:: @@ -438,36 +478,56 @@ displayDebugMessage_(const std::string &msg, const std::string &well_name) } -std::tuple +std::tuple GasLiftGroupInfo:: -getProducerWellRates_(int well_index) +getProducerWellRates_(const Well* well, int well_index) { const auto& pu = this->phase_usage_; const auto& ws= this->well_state_.well(well_index); const auto& wrate = ws.well_potentials; - const auto oil_rate = pu.phase_used[Oil] + const auto oil_pot = pu.phase_used[Oil] ? wrate[pu.phase_pos[Oil]] : 0.0; - const auto gas_rate = pu.phase_used[Gas] + const auto gas_pot = pu.phase_used[Gas] ? wrate[pu.phase_pos[Gas]] : 0.0; - const auto water_rate = pu.phase_used[Water] + const auto water_pot = pu.phase_used[Water] ? wrate[pu.phase_pos[Water]] : 0.0; - return {oil_rate, gas_rate, water_rate}; + const auto controls = well->productionControls(this->summary_state_); + double oil_rate = oil_pot; + if (controls.hasControl(Well::ProducerCMode::ORAT)) { + oil_rate = std::min(controls.oil_rate, oil_rate); + } + double gas_rate = gas_pot; + if (controls.hasControl(Well::ProducerCMode::GRAT)) { + gas_rate = std::min(controls.gas_rate, gas_rate); + } + double water_rate = water_pot; + if (controls.hasControl(Well::ProducerCMode::WRAT)) { + water_rate = std::min(controls.water_rate, water_rate); + } + if (controls.hasControl(Well::ProducerCMode::LRAT)) { + double liquid_rate = oil_rate + water_rate; + double liquid_rate_lim = std::min(controls.liquid_rate, liquid_rate); + water_rate = water_rate / liquid_rate * liquid_rate_lim; + oil_rate = oil_rate / liquid_rate * liquid_rate_lim; + } + + return {oil_rate, gas_rate, water_rate, oil_pot, gas_pot, water_pot}; } -std::tuple +std::tuple GasLiftGroupInfo:: initializeGroupRatesRecursive_(const Group &group) { - std::array rates{}; + std::array rates{}; if (this->debug) debugStartInitializeGroup(group.name()); - auto& [oil_rate, water_rate, gas_rate, alq] = rates; + auto& [oil_rate, water_rate, gas_rate, oil_potential, water_potential, gas_potential, alq] = rates; if (group.wellgroup()) { for (const std::string& well_name : group.wells()) { // NOTE: we cannot simply use: @@ -482,17 +542,21 @@ 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, sw_water_rate] = getProducerWellRates_(index); + auto [sw_oil_rate, sw_gas_rate, sw_water_rate, sw_oil_pot, sw_gas_pot, sw_water_pot] = getProducerWellRates_(well, 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); + oil_potential += (factor * sw_oil_pot); + gas_potential += (factor * sw_gas_pot); + water_potential += (factor * sw_water_pot); + alq += (factor * sw_alq); if (this->debug) { debugDisplayWellContribution_( group.name(), well_name, factor, - sw_oil_rate, sw_gas_rate, sw_water_rate, sw_alq, + sw_oil_pot, sw_gas_pot, sw_water_pot, sw_alq, oil_rate, gas_rate, water_rate, alq ); } @@ -507,12 +571,16 @@ 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_water_rate, sg_alq] + auto [sg_oil_rate, sg_gas_rate, sg_water_rate, + sg_oil_pot, sg_gas_pot, sg_water_pot, 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); + oil_potential += (gefac * sg_oil_pot); + gas_potential += (gefac * sg_gas_pot); + water_potential += (gefac * sg_water_pot); alq += (gefac * sg_alq); } } @@ -538,14 +606,29 @@ initializeGroupRatesRecursive_(const Group &group) } if (oil_target || liquid_target || water_target || gas_target || max_total_gas || max_alq) { updateGroupIdxMap_(group.name()); + if(oil_target) + oil_rate = std::min(oil_rate, *oil_target); + if(gas_target) + gas_rate = std::min(gas_rate, *gas_target); + if(water_target) + water_rate = std::min(water_rate, *water_target); + if(liquid_target) { + double liquid_rate = oil_rate + water_rate; + double liquid_rate_limited = std::min(liquid_rate, *liquid_target); + oil_rate = oil_rate / liquid_rate * liquid_rate_limited; + water_rate = water_rate / liquid_rate * liquid_rate_limited; + } + this->group_rate_map_.try_emplace(group.name(), - oil_rate, gas_rate, water_rate, alq, oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq); + oil_rate, gas_rate, water_rate, alq, + oil_potential, gas_potential, water_potential, + oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq); if (this->debug) { debugDisplayUpdatedGroupRates( group.name(), oil_rate, gas_rate, water_rate, alq); } } - return std::make_tuple(oil_rate, gas_rate, water_rate, alq); + return std::make_tuple(oil_rate, gas_rate, water_rate, oil_potential, gas_potential, water_potential, alq); } void diff --git a/opm/simulators/wells/GasLiftGroupInfo.hpp b/opm/simulators/wells/GasLiftGroupInfo.hpp index cfe3762a2..351d21870 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.hpp +++ b/opm/simulators/wells/GasLiftGroupInfo.hpp @@ -91,8 +91,12 @@ public: double alqRate(const std::string& group_name); double gasRate(const std::string& group_name) const; + double gasPotential(const std::string& group_name) const; + double waterPotential(const std::string& group_name) const; + double oilPotential(const std::string& group_name) const; int getGroupIdx(const std::string& group_name); double getRate(Rate rate_type, const std::string& group_name) const; + double getPotential(Rate rate_type, const std::string& group_name) const; std::tuple getRates(const int group_idx) const; std::optional gasTarget(const std::string& group_name) const; std::optional getTarget( @@ -130,8 +134,9 @@ protected: void debugStartInitializeGroup(const std::string& name) const; void displayDebugMessage_(const std::string& msg) const override; void displayDebugMessage_(const std::string& msg, const std::string& well_name); - std::tuple getProducerWellRates_(const int index); - std::tuple + std::tuple + getProducerWellRates_(const Well* well, const int index); + std::tuple initializeGroupRatesRecursive_(const Group &group); void initializeWell2GroupMapRecursive_( const Group& group, std::vector& group_names, @@ -142,6 +147,7 @@ protected: class GroupRates { public: GroupRates( double oil_rate, double gas_rate, double water_rate, double alq, + double oil_potential, double gas_potential, double water_potential, std::optional oil_target, std::optional gas_target, std::optional water_target, @@ -153,6 +159,9 @@ protected: gas_rate_{gas_rate}, water_rate_{water_rate}, alq_{alq}, + oil_potential_{oil_potential}, + gas_potential_{gas_potential}, + water_potential_{water_potential}, oil_target_{oil_target}, gas_target_{gas_target}, water_target_{water_target}, @@ -177,6 +186,9 @@ protected: double oilRate() const { return oil_rate_; } std::optional oilTarget() const { return oil_target_; } std::optional liquidTarget() const { return liquid_target_; } + double oilPotential() const { return oil_potential_; } + double gasPotential() const { return gas_potential_; } + double waterPotential() const { return water_potential_; } void update(double delta_oil, double delta_gas, double delta_water, double delta_alq) { @@ -190,6 +202,9 @@ protected: double gas_rate_; double water_rate_; double alq_; + double oil_potential_; + double gas_potential_; + double water_potential_; std::optional oil_target_; std::optional gas_target_; std::optional water_target_; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index e204939e9..1dee331b6 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -247,7 +247,7 @@ GasLiftSingleWellGeneric::checkGroupTargetsViolated(const BasicRates& rates, con auto target_opt = this->group_info_.getTarget(rate_type, group_name); if (target_opt) { auto delta_rate = new_rates[rate_type] - rates[rate_type]; - auto new_group_rate = this->group_info_.getRate(rate_type, group_name) + efficiency * delta_rate; + auto new_group_rate = this->group_info_.getPotential(rate_type, group_name) + efficiency * delta_rate; if (new_group_rate > *target_opt) { if (this->debug) { const std::string msg diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 526bf6f93..2a9527051 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -28,7 +28,7 @@ #include #include #include - +#include #include #include #include @@ -47,12 +47,14 @@ GasLiftStage2::GasLiftStage2( const GroupState &group_state, GLiftProdWells &prod_wells, GLiftOptWells &glift_wells, + GasLiftGroupInfo& group_info, GLiftWellStateMap &state_map, bool glift_debug ) : GasLiftCommon(well_state, group_state, deferred_logger, comm, glift_debug) , prod_wells_{prod_wells} , stage1_wells_{glift_wells} + , group_info_{group_info} , well_state_map_{state_map} , report_step_idx_{report_step_idx} , summary_state_{summary_state} @@ -278,136 +280,10 @@ std::tuple GasLiftStage2:: getCurrentGroupRates_(const Group &group) { - auto rates = getCurrentGroupRatesRecursive_(group); - this->comm_.sum(rates.data(), rates.size()); - auto [oil_rate, gas_rate, water_rate, alq] = rates; - if (this->debug) { - const std::string msg = fmt::format( - "Current group rates for {} : oil: {}, gas: {}, water: {}, alq: {}", - group.name(), oil_rate, gas_rate, water_rate, alq); - displayDebugMessageOnRank0_(msg); - } - - return {oil_rate, gas_rate, water_rate, alq}; -} - - -std::array -GasLiftStage2:: -getCurrentGroupRatesRecursive_(const Group &group) -{ - double oil_rate = 0.0; - double gas_rate = 0.0; - double water_rate = 0.0; - double alq = 0.0; - // NOTE: A group can either contain wells or groups, but not both - if (group.wellgroup()) { - for (const std::string& well_name : group.wells()) { - auto [sw_oil_rate, sw_gas_rate, sw_water_rate, sw_alq] = - getCurrentWellRates_(well_name, group.name()); - oil_rate += sw_oil_rate; - gas_rate += sw_gas_rate; - water_rate += sw_water_rate; - alq += sw_alq; - } - - } - else { - for (const std::string& group_name : group.groups()) { - if(this->schedule_.back().groups.has(group_name)) { - const Group& sub_group = - this->schedule_.getGroup(group_name, this->report_step_idx_); - // If groups have efficiency factors to model - // synchronized downtime of their subordinate wells - // (see keyword GEFAC), their lift gas injection rates - // are multiplied by their efficiency factors when - // they are added to the lift gas supply rate of the - // parent group. - const auto gefac = sub_group.getGroupEfficiencyFactor(); - auto rates = getCurrentGroupRatesRecursive_(sub_group); - auto [sg_oil_rate, sg_gas_rate, sg_water_rate, sg_alq] = rates; - oil_rate += (gefac * sg_oil_rate); - gas_rate += (gefac * sg_gas_rate); - water_rate += (gefac * sg_water_rate); - alq += (gefac * sg_alq); - } - } - } - return {oil_rate, gas_rate, water_rate, alq}; -} - -std::tuple -GasLiftStage2:: -getCurrentWellRates_(const std::string &well_name, const std::string &group_name) -{ - double oil_rate, gas_rate, water_rate, alq; - bool success = false; - const WellInterfaceGeneric *well_ptr = nullptr; - std::string debug_info; - if (this->stage1_wells_.count(well_name) == 1) { - GasLiftSingleWell &gs_well = *(this->stage1_wells_.at(well_name).get()); - const WellInterfaceGeneric &well = gs_well.getWell(); - well_ptr = &well; - GasLiftWellState &state = *(this->well_state_map_.at(well_name).get()); - std::tie(oil_rate, gas_rate) = state.getRates(); - water_rate = state.waterRate(); - success = true; - if ( this->debug) debug_info = "(A)"; - } - else if (this->prod_wells_.count(well_name) == 1) { - well_ptr = this->prod_wells_.at(well_name); - std::tie(oil_rate, gas_rate, water_rate) = getWellRates_(*well_ptr); - success = true; - if ( this->debug) debug_info = "(B)"; - } - - if (well_ptr) { - // we only want rates from wells owned by the rank - if (!well_state_.wellIsOwned(well_ptr->indexOfWell(), well_name)) { - success = false; - } - } - - if (success) { - assert(well_ptr); - assert(well_ptr->isProducer()); - alq = this->well_state_.getALQ(well_name); - if (this->debug) { - const std::string msg = fmt::format( - "Rates {} for well {} : oil: {}, gas: {}, water: {}, alq: {}", - debug_info, well_name, oil_rate, gas_rate, water_rate, alq); - displayDebugMessage_(msg, group_name); - } - // If wells have efficiency factors to take account of regular - // downtime (see keyword WEFAC), their lift gas injection - // rates are multiplied by their efficiency factors when they - // are added to the group lift gas supply rate. This is - // consistent with the summation of flow rates for wells with - // downtime, and preserves the ratio of production rate to - // lift gas injection rate. - const auto &well_ecl = well_ptr->wellEcl(); - double factor = well_ecl.getEfficiencyFactor(); - oil_rate *= factor; - gas_rate *= factor; - water_rate *= factor; - alq *= factor; - if (this->debug && (factor != 1)) { - const std::string msg = fmt::format( - "Well {} : efficiency factor {}. New rates : oil: {}, gas: {}, water: {}, alq: {}", - well_name, factor, oil_rate, gas_rate, water_rate, alq); - displayDebugMessage_(msg, group_name); - } - } - else { - // NOTE: This happens for wells that are not producers, or not active. - if (this->debug) { - const std::string msg = fmt::format("Could not determine current rates for " - "well {}: (not active or injector)", well_name); - displayDebugMessage_(msg, group_name); - } - oil_rate = 0.0; gas_rate = 0.0; water_rate = 0.0; alq = 0.0; - } - return std::make_tuple(oil_rate, gas_rate, water_rate, alq); + return {this->group_info_.oilRate(group.name()), + this->group_info_.gasRate(group.name()), + this->group_info_.waterRate(group.name()), + this->group_info_.alqRate(group.name())}; } std::optional @@ -430,24 +306,6 @@ GasLiftStage2::getGroupMaxTotalGas_(const Group &group) return std::nullopt; // If GLIFTOPT is missing from schedule, assume unlimited alq } -std::tuple -GasLiftStage2:: -getWellRates_(const WellInterfaceGeneric &well) -{ - const int well_index = well.indexOfWell(); - const auto& ws = this->well_state_.well(well_index); - const auto& pu = well.phaseUsage(); - auto oil_rate = ws.well_potentials[pu.phase_pos[Oil]]; - auto water_rate = ws.well_potentials[pu.phase_pos[Water]]; - double gas_rate = 0.0; - // See comment for setupPhaseVariables_() in GasLiftSingleWell_impl.hpp - // about the two-phase oil-water case. - if (pu.phase_used[BlackoilPhases::Vapour]) { - gas_rate = ws.well_potentials[pu.phase_pos[Gas]]; - } - return {oil_rate, gas_rate, water_rate}; -} - // Find all subordinate wells of a given group. // // NOTE: A group can either contain wells or groups, not both. diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index d1ffa6294..c999fecf2 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -70,6 +70,7 @@ public: const GroupState& group_state, GLiftProdWells& prod_wells, GLiftOptWells& glift_wells, + GasLiftGroupInfo& group_info, GLiftWellStateMap& state_map, bool glift_debug ); @@ -89,16 +90,12 @@ protected: void displayWarning_(const std::string& msg, const std::string& group_name); void displayWarning_(const std::string& msg); std::tuple getCurrentGroupRates_(const Group& group); - std::array getCurrentGroupRatesRecursive_(const Group& group); - std::tuple getCurrentWellRates_( - const std::string& well_name, const std::string& group_name); std::optional getGroupMaxALQ_(const Group &group); std::optional getGroupMaxTotalGas_(const Group &group); std::vector getGroupGliftWells_( const Group& group); void getGroupGliftWellsRecursive_( const Group& group, std::vector& wells); - std::tuple getWellRates_(const WellInterfaceGeneric& well); void optimizeGroup_(const Group& group); void optimizeGroupsRecursive_(const Group& group); void recalculateGradientAndUpdateData_( @@ -126,6 +123,7 @@ protected: GLiftProdWells& prod_wells_; GLiftOptWells& stage1_wells_; + GasLiftGroupInfo& group_info_; GLiftWellStateMap& well_state_map_; int report_step_idx_; From 7d7b2803a550cfbd3b1651cc8f54dbe86174ccf4 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Wed, 16 Nov 2022 09:18:35 +0100 Subject: [PATCH 10/11] renaming and adding more comments based on review --- opm/simulators/wells/GasLiftGroupInfo.hpp | 2 + .../wells/GasLiftSingleWellGeneric.cpp | 36 ++++++++++-------- .../wells/GasLiftSingleWellGeneric.hpp | 15 ++++---- opm/simulators/wells/GasLiftStage2.cpp | 38 +++++++++++-------- opm/simulators/wells/GasLiftStage2.hpp | 8 ++-- 5 files changed, 57 insertions(+), 42 deletions(-) diff --git a/opm/simulators/wells/GasLiftGroupInfo.hpp b/opm/simulators/wells/GasLiftGroupInfo.hpp index 351d21870..d4322ec5b 100644 --- a/opm/simulators/wells/GasLiftGroupInfo.hpp +++ b/opm/simulators/wells/GasLiftGroupInfo.hpp @@ -196,6 +196,8 @@ protected: gas_rate_ += delta_gas; water_rate_ += delta_water; alq_ += delta_alq; + // Note. We don't updata the potentials at this point. They + // are only needed initially. } private: double oil_rate_; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp index 1dee331b6..c14ccb9e4 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.cpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.cpp @@ -86,7 +86,7 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logg // NOTE: Used from GasLiftStage2 std::optional GasLiftSingleWellGeneric::calcIncOrDecGradient( - double oil_rate, double gas_rate, double water_rate, double alq, const Group& group, bool increase) const + double oil_rate, double gas_rate, double water_rate, double alq, const std::string& gr_name_dont_limit, bool increase) const { auto [new_alq_opt, alq_is_limited] = addOrSubtractAlqIncrement_(alq, increase); // TODO: What to do if ALQ is limited and new_alq != alq? @@ -96,7 +96,7 @@ GasLiftSingleWellGeneric::calcIncOrDecGradient( double new_alq = *new_alq_opt; auto delta_alq = new_alq - alq; - if (checkGroupALQrateExceeded(delta_alq, group.name())) + if (checkGroupALQrateExceeded(delta_alq, gr_name_dont_limit)) return std::nullopt; if (auto bhp = computeBhpAtThpLimit_(new_alq)) { @@ -110,7 +110,7 @@ GasLiftSingleWellGeneric::calcIncOrDecGradient( // std::tie(new_water_rate, water_is_limited) = getWaterRateWithLimit_(rates); const auto ratesLimited = getLimitedRatesFromRates_(rates); BasicRates oldrates = {oil_rate, gas_rate, water_rate, false}; - const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited, group.name()); + const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited, gr_name_dont_limit); if (!increase && new_rates.oil < 0) { return std::nullopt; @@ -673,25 +673,25 @@ GasLiftSingleWellGeneric::getRateWithLimit_(Rate rate_type, const BasicRates& ra } std::pair -GasLiftSingleWellGeneric::getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate, const std::string& gr_name_no_check) const +GasLiftSingleWellGeneric::getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate, const std::string& gr_name_dont_limit) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate, gr_name_no_check); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate, gr_name_dont_limit); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric::getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate, const std::string& gr_name_no_check) const +GasLiftSingleWellGeneric::getGasRateWithGroupLimit_(double new_gas_rate, double gas_rate, const std::string& gr_name_dont_limit) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate, gr_name_no_check); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate, gr_name_dont_limit); bool limited = gr_name != nullptr; return {rate, limited}; } std::pair -GasLiftSingleWellGeneric::getWaterRateWithGroupLimit_(double new_water_rate, double water_rate, const std::string& gr_name_no_check) const +GasLiftSingleWellGeneric::getWaterRateWithGroupLimit_(double new_water_rate, double water_rate, const std::string& gr_name_dont_limit) const { - [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::water, new_water_rate, water_rate, gr_name_no_check); + [[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(Rate::water, new_water_rate, water_rate, gr_name_dont_limit); bool limited = gr_name != nullptr; return {rate, limited}; } @@ -701,12 +701,12 @@ GasLiftSingleWellGeneric::getLiquidRateWithGroupLimit_(const double new_oil_rate const double oil_rate, const double new_water_rate, const double water_rate, - const std::string& gr_name_no_check) const + const std::string& gr_name_dont_limit) const { auto liquid_rate = oil_rate + water_rate; auto new_liquid_rate = new_oil_rate + new_water_rate; auto [liquid_rate_limited, group_name, efficiency] - = getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate, gr_name_no_check); + = getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate, gr_name_dont_limit); bool limited = group_name != nullptr; if (limited) { // the oil, gas, and water cases can be handled directly by @@ -737,7 +737,7 @@ GasLiftSingleWellGeneric::getLiquidRateWithGroupLimit_(const double new_oil_rate } std::tuple -GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_no_check) const +GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_dont_limit) const { const double delta_rate = new_rate - old_rate; if (delta_rate > 0) { @@ -750,7 +750,9 @@ GasLiftSingleWellGeneric::getRateWithGroupLimit_(Rate rate_type, const double ne double gr_target, new_gr_rate, efficiency; const std::string* group_name = nullptr; for (const auto& [group_name_temp, efficiency_temp] : pairs) { - if (gr_name_no_check == group_name_temp) { + // in stage 2 we don't want to limit the rate to the group + // target we are trying to redistribute the gaslift within + if (gr_name_dont_limit == group_name_temp) { continue; } @@ -1583,12 +1585,14 @@ GasLiftSingleWellGeneric::OptimizeState::checkAlqOutsideLimits(double alq, [[may } bool -GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_no_check) const +GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_dont_limit) const { const auto& pairs = group_info_.getWellGroups(well_name_); for (const auto& [group_name, efficiency] : pairs) { - if (gr_name_no_check == group_name) - continue; + // in stage 2 we don't want to limit the rate to the group + // target we are trying to redistribute the gaslift within + if (gr_name_dont_limit == group_name) + continue; auto max_alq_opt = group_info_.maxAlq(group_name); if (max_alq_opt) { double alq = group_info_.alqRate(group_name) + efficiency * delta_alq; diff --git a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp index 24853cdb8..b958bda81 100644 --- a/opm/simulators/wells/GasLiftSingleWellGeneric.hpp +++ b/opm/simulators/wells/GasLiftSingleWellGeneric.hpp @@ -96,7 +96,8 @@ public: std::optional calcIncOrDecGradient(double oil_rate, double gas_rate, double water_rate, double alq, - const Group& group, bool increase) const; + const std::string& gr_name_dont_limit, + bool increase) const; std::unique_ptr runOptimize(const int iteration_idx); @@ -240,7 +241,7 @@ protected: double getBhpWithLimit(); void warn_(std::string msg) {parent.displayWarning_(msg);} }; - bool checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_no_check = "") const; + bool checkGroupALQrateExceeded(double delta_alq, const std::string& gr_name_dont_limit = "") const; bool checkGroupTotalRateExceeded(double delta_alq, double delta_gas_rate) const; std::pair, bool> addOrSubtractAlqIncrement_( @@ -275,14 +276,14 @@ protected: std::pair getGasRateWithLimit_( const BasicRates& rates) const; std::pair getGasRateWithGroupLimit_( - double new_gas_rate, double gas_rate, const std::string& gr_name_no_check) const; + double new_gas_rate, double gas_rate, const std::string& gr_name_dont_limit) const; std::pair,double> getInitialRatesWithLimit_() const; LimitedRates getLimitedRatesFromRates_(const BasicRates& rates) const; std::tuple getLiquidRateWithGroupLimit_( const double new_oil_rate, const double oil_rate, - const double new_water_rate, const double water_rate, const std::string& gr_name_no_check) const; + const double new_water_rate, const double water_rate, const std::string& gr_name_dont_limit) const; std::pair getOilRateWithGroupLimit_( - double new_oil_rate, double oil_rate, const std::string& gr_name_no_check) const; + double new_oil_rate, double oil_rate, const std::string& gr_name_dont_limit) const; std::pair getOilRateWithLimit_(const BasicRates& rates) const; std::pair> getOilRateWithLimit2_( const BasicRates& rates) const; @@ -291,9 +292,9 @@ protected: std::pair> getRateWithLimit_( Rate rate_type, const BasicRates& rates) const; std::tuple getRateWithGroupLimit_( - Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_no_check) const; + Rate rate_type, const double new_rate, const double old_rate, const std::string& gr_name_dont_limit) const; std::pair getWaterRateWithGroupLimit_( - double new_water_rate, double water_rate, const std::string& gr_name_no_check) const; + double new_water_rate, double water_rate, const std::string& gr_name_dont_limit) const; std::pair getWaterRateWithLimit_(const BasicRates& rates) const; std::pair> getWaterRateWithLimit2_( const BasicRates& rates) const; diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index 2a9527051..c6f89bc6b 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -135,7 +135,7 @@ addOrRemoveALQincrement_(GradMap &grad_map, const std::string& well_name, bool a std::optional GasLiftStage2:: calcIncOrDecGrad_( - const std::string well_name, const GasLiftSingleWell &gs_well, const Group& group, bool increase) + const std::string well_name, const GasLiftSingleWell &gs_well, const std::string& gr_name_dont_limit, bool increase) { // only applies to wells in the well_state_map (i.e. wells on this rank) @@ -161,7 +161,7 @@ calcIncOrDecGrad_( else { auto [oil_rate, gas_rate] = state.getRates(); auto alq = state.alq(); - auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, group, increase); + auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, gr_name_dont_limit, increase); if (grad) { const std::string msg = fmt::format( "well {} : adding {} gradient = {}", @@ -441,7 +441,7 @@ optimizeGroupsRecursive_(const Group &group) void GasLiftStage2:: recalculateGradientAndUpdateData_( - GradPairItr &grad_itr, const Group& group, bool increase, + GradPairItr &grad_itr, const std::string& gr_name_dont_limit, bool increase, //incremental and decremental gradients, if 'grads' are incremental, then // 'other_grads' are decremental, or conversely, if 'grads' are decremental, then @@ -457,7 +457,7 @@ recalculateGradientAndUpdateData_( // the grads and other grads are synchronized later if(this->stage1_wells_.count(name) > 0) { GasLiftSingleWell &gs_well = *(this->stage1_wells_.at(name).get()); - auto grad = calcIncOrDecGrad_(name, gs_well, group, increase); + auto grad = calcIncOrDecGrad_(name, gs_well, gr_name_dont_limit, increase); if (grad) { grad_itr->second = grad->grad; old_grad = updateGrad_(name, *grad, increase); @@ -627,8 +627,8 @@ removeSurplusALQ_(const Group &group, const auto well_name = dec_grad_itr->first; auto eco_grad = dec_grad_itr->second; bool remove = false; - if (state.checkOilTarget(eco_grad) || state.checkGasTarget(eco_grad) - || state.checkLiquidTarget(eco_grad) || state.checkWaterTarget(eco_grad) || state.checkALQlimit()) + if (state.checkOilTarget(eco_grad) || state.checkGasTarget() + || state.checkLiquidTarget(eco_grad) || state.checkWaterTarget() || state.checkALQlimit()) { remove = true; } @@ -643,8 +643,12 @@ removeSurplusALQ_(const Group &group, if (remove) { state.updateRates(well_name); state.addOrRemoveALQincrement( this->dec_grads_, well_name, /*add=*/false); + // We pass the current group rate in order to avoid limiting the rates + // and gaslift based on the current group limits. In other words we want to reduce + // the gasslift as much as possible as long as we are able to produce the group + // targets recalculateGradientAndUpdateData_( - dec_grad_itr, group, /*increase=*/false, dec_grads, inc_grads); + dec_grad_itr, group.name(), /*increase=*/false, dec_grads, inc_grads); // The dec_grads and inc_grads needs to be syncronized across ranks mpiSyncGlobalGradVector_(dec_grads); @@ -751,12 +755,12 @@ calculateEcoGradients(std::vector &wells, for (auto well_ptr : wells) { const auto &gs_well = *well_ptr; // gs = GasLiftSingleWell const auto &name = gs_well.name(); - auto inc_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group, /*increase=*/true); + auto inc_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group.name(), /*increase=*/true); if (inc_grad) { inc_grads.emplace_back(std::make_pair(name, inc_grad->grad)); this->parent.saveIncGrad_(name, *inc_grad); } - auto dec_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group, /*increase=*/false); + auto dec_grad = this->parent.calcIncOrDecGrad_(name, gs_well, group.name(), /*increase=*/false); if (dec_grad) { dec_grads.emplace_back(std::make_pair(name, dec_grad->grad)); this->parent.saveDecGrad_(name, *dec_grad); @@ -843,9 +847,9 @@ recalculateGradients( GradPairItr &min_dec_grad_itr, GradPairItr &max_inc_grad_itr) { this->parent.recalculateGradientAndUpdateData_( - max_inc_grad_itr, this->group, /*increase=*/true, inc_grads, dec_grads); + max_inc_grad_itr, this->group.name(), /*increase=*/true, inc_grads, dec_grads); this->parent.recalculateGradientAndUpdateData_( - min_dec_grad_itr, this->group, /*increase=*/false, dec_grads, inc_grads); + min_dec_grad_itr, this->group.name(), /*increase=*/false, dec_grads, inc_grads); // The dec_grads and inc_grads needs to be syncronized across ranks this->parent.mpiSyncGlobalGradVector_(dec_grads); @@ -944,10 +948,10 @@ checkEcoGradient(const std::string &well_name, double eco_grad) bool GasLiftStage2::SurplusState:: -checkGasTarget(double eco_grad) +checkGasTarget() { if (this->group.has_control(Group::ProductionCMode::GRAT)) { - if (this->gas_target < (this->gas_rate - eco_grad) ) { + if (this->gas_target < (this->gas_rate) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "gas rate {} is greater than gas target {}", this->group.name(), @@ -965,6 +969,8 @@ checkLiquidTarget(double eco_grad) { if (this->group.has_control(Group::ProductionCMode::LRAT)) { auto liquid_rate = this->oil_rate + this->water_rate; + // the eco_grad is subtracted from the rate to make sure the + // group still can produce its target if (this->liquid_target < (liquid_rate - eco_grad) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " @@ -983,6 +989,8 @@ GasLiftStage2::SurplusState:: checkOilTarget(double eco_grad) { if (this->group.has_control(Group::ProductionCMode::ORAT)) { + // the eco_grad is subtracted from the rate to make sure the + // group still can produce its target if (this->oil_target < (this->oil_rate - eco_grad) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " @@ -998,10 +1006,10 @@ checkOilTarget(double eco_grad) bool GasLiftStage2::SurplusState:: -checkWaterTarget(double eco_grad) +checkWaterTarget() { if (this->group.has_control(Group::ProductionCMode::WRAT)) { - if (this->water_target < (this->water_rate - eco_grad) ) { + if (this->water_target < (this->water_rate) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "water rate {} is greater than oil target {}", this->group.name(), diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index c999fecf2..f3321d65e 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -79,7 +79,7 @@ protected: void addOrRemoveALQincrement_( GradMap& grad_map, const std::string& well_name, bool add); std::optional calcIncOrDecGrad_( - const std::string name, const GasLiftSingleWell& gs_well, const Group& group, bool increase); + const std::string name, const GasLiftSingleWell& gs_well, const std::string& gr_name_dont_limit, bool increase); bool checkRateAlreadyLimited_(GasLiftWellState& state, bool increase); GradInfo deleteDecGradItem_(const std::string& name); GradInfo deleteIncGradItem_(const std::string& name); @@ -99,7 +99,7 @@ protected: void optimizeGroup_(const Group& group); void optimizeGroupsRecursive_(const Group& group); void recalculateGradientAndUpdateData_( - GradPairItr& grad_itr, const Group& group, bool increase, + GradPairItr& grad_itr, const std::string& gr_name_dont_limit, bool increase, std::vector& grads, std::vector& other_grads); void redistributeALQ_( std::vector& wells, const Group& group, @@ -205,10 +205,10 @@ protected: GradMap &grad_map, const std::string& well_name, bool add); bool checkALQlimit(); bool checkEcoGradient(const std::string& well_name, double eco_grad); - bool checkGasTarget(double eco_grad); + bool checkGasTarget(); bool checkLiquidTarget(double eco_grad); bool checkOilTarget(double eco_grad); - bool checkWaterTarget(double eco_grad); + bool checkWaterTarget(); void updateRates(const std::string& name); }; }; From c45d90650ebad8596803e42967aee175daba48c7 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Wed, 16 Nov 2022 15:41:29 +0100 Subject: [PATCH 11/11] fix checking of group target - use the actual delta rate in checkOilTarget etc - add check for total gas rate = gas rate + alq --- opm/simulators/wells/GasLiftStage2.cpp | 68 +++++++++++++++++--------- opm/simulators/wells/GasLiftStage2.hpp | 17 ++++--- 2 files changed, 55 insertions(+), 30 deletions(-) diff --git a/opm/simulators/wells/GasLiftStage2.cpp b/opm/simulators/wells/GasLiftStage2.cpp index c6f89bc6b..d4f15f69f 100644 --- a/opm/simulators/wells/GasLiftStage2.cpp +++ b/opm/simulators/wells/GasLiftStage2.cpp @@ -599,6 +599,7 @@ removeSurplusALQ_(const Group &group, } assert(!dec_grads.empty()); const auto max_glift = getGroupMaxALQ_(group); + const auto max_totalgas = getGroupMaxTotalGas_(group); const auto controls = group.productionControls(this->summary_state_); //const auto &max_total_gas = gl_group.max_total_gas(); auto [oil_rate, gas_rate, water_rate, alq] = getCurrentGroupRates_(group); @@ -617,7 +618,7 @@ removeSurplusALQ_(const Group &group, } SurplusState state {*this, group, oil_rate, gas_rate, water_rate, alq, min_eco_grad, controls.oil_target, controls.gas_target, controls.water_target, - controls.liquid_target, max_glift }; + controls.liquid_target, max_glift, max_totalgas }; while (!stop_iteration) { if (dec_grads.size() >= 2) { @@ -627,8 +628,11 @@ removeSurplusALQ_(const Group &group, const auto well_name = dec_grad_itr->first; auto eco_grad = dec_grad_itr->second; bool remove = false; - if (state.checkOilTarget(eco_grad) || state.checkGasTarget() - || state.checkLiquidTarget(eco_grad) || state.checkWaterTarget() || state.checkALQlimit()) + const auto delta = state.computeDelta(well_name); + const auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta; + if (state.checkOilTarget(delta_oil) || state.checkGasTarget(delta_gas) + || state.checkLiquidTarget(delta_oil + delta_water) || state.checkWaterTarget(delta_water) + || state.checkALQlimit(delta_alq, delta_gas)) { remove = true; } @@ -641,7 +645,7 @@ removeSurplusALQ_(const Group &group, if (state.checkEcoGradient(well_name, eco_grad)) remove = true; } if (remove) { - state.updateRates(well_name); + state.updateRates(delta); state.addOrRemoveALQincrement( this->dec_grads_, well_name, /*add=*/false); // We pass the current group rate in order to avoid limiting the rates // and gaslift based on the current group limits. In other words we want to reduce @@ -909,13 +913,11 @@ addOrRemoveALQincrement(GradMap &grad_map, const std::string& well_name, bool ad bool GasLiftStage2::SurplusState:: -checkALQlimit() +checkALQlimit(double delta_alq, double delta_gas) { if (this->max_glift) { double max_alq = *(this->max_glift); - double increment = this->parent.glo_.gaslift_increment(); - double epsilon = 1e-6 * increment; - if ((max_alq+epsilon) < this->alq ) { + if ((max_alq) < (this->alq + delta_alq) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "ALQ rate {} is greater than ALQ limit {}", this->group.name(), @@ -925,6 +927,19 @@ checkALQlimit() return true; } } + if (this->max_total_gas) { + double max_total = *(this->max_total_gas); + double total_gas_rate = (this->alq + delta_alq + this->gas_rate + delta_gas); + if ((max_total) < total_gas_rate ) { + if (this->parent.debug) { + const std::string msg = fmt::format("group: {} : " + "Total gas rate {} is greater than Total gas limit {}", this->group.name(), + total_gas_rate, max_total); + this->parent.displayDebugMessage_(msg); + } + return true; + } + } return false; } @@ -948,10 +963,10 @@ checkEcoGradient(const std::string &well_name, double eco_grad) bool GasLiftStage2::SurplusState:: -checkGasTarget() +checkGasTarget(double delta_gas) { if (this->group.has_control(Group::ProductionCMode::GRAT)) { - if (this->gas_target < (this->gas_rate) ) { + if (this->gas_target < (this->gas_rate + delta_gas) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "gas rate {} is greater than gas target {}", this->group.name(), @@ -965,13 +980,13 @@ checkGasTarget() } bool GasLiftStage2::SurplusState:: -checkLiquidTarget(double eco_grad) +checkLiquidTarget(double delta_liquid) { if (this->group.has_control(Group::ProductionCMode::LRAT)) { - auto liquid_rate = this->oil_rate + this->water_rate; - // the eco_grad is subtracted from the rate to make sure the + // the change in liquid rate from the is subtracted from the rate to make sure the // group still can produce its target - if (this->liquid_target < (liquid_rate - eco_grad) ) { + auto liquid_rate = this->oil_rate + this->water_rate + delta_liquid; + if (this->liquid_target < (liquid_rate) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "liquid rate {} is greater than liquid target {}", this->group.name(), @@ -986,16 +1001,16 @@ checkLiquidTarget(double eco_grad) bool GasLiftStage2::SurplusState:: -checkOilTarget(double eco_grad) +checkOilTarget(double delta_oil) { if (this->group.has_control(Group::ProductionCMode::ORAT)) { - // the eco_grad is subtracted from the rate to make sure the + // the change in oil rate from the eco_grad is subtracted from the rate to make sure the // group still can produce its target - if (this->oil_target < (this->oil_rate - eco_grad) ) { + if (this->oil_target < (this->oil_rate + delta_oil) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "oil rate {} is greater than oil target {}", this->group.name(), - this->oil_rate, this->oil_target); + this->oil_rate - delta_oil, this->oil_target); this->parent.displayDebugMessage_(msg); } return true; @@ -1006,10 +1021,10 @@ checkOilTarget(double eco_grad) bool GasLiftStage2::SurplusState:: -checkWaterTarget() +checkWaterTarget(double delta_water) { if (this->group.has_control(Group::ProductionCMode::WRAT)) { - if (this->water_target < (this->water_rate) ) { + if (this->water_target < (this->water_rate + delta_water) ) { if (this->parent.debug) { const std::string msg = fmt::format("group: {} : " "water rate {} is greater than oil target {}", this->group.name(), @@ -1022,9 +1037,9 @@ checkWaterTarget() return false; } -void +std::array GasLiftStage2::SurplusState:: -updateRates(const std::string &well_name) +computeDelta(const std::string &well_name) { std::array delta = {0.0, 0.0, 0.0, 0.0}; // compute the delta on wells on own rank @@ -1048,7 +1063,13 @@ updateRates(const std::string &well_name) // and communicate the results this->parent.comm_.sum(delta.data(), delta.size()); - // and update + return delta; +} + +void +GasLiftStage2::SurplusState:: +updateRates(const std::array& delta) +{ const auto& [delta_oil, delta_gas, delta_water, delta_alq] = delta; this->oil_rate += delta_oil; this->gas_rate += delta_gas; @@ -1056,4 +1077,5 @@ updateRates(const std::string &well_name) this->alq += delta_alq; } + } // namespace Opm diff --git a/opm/simulators/wells/GasLiftStage2.hpp b/opm/simulators/wells/GasLiftStage2.hpp index f3321d65e..ae4c022ae 100644 --- a/opm/simulators/wells/GasLiftStage2.hpp +++ b/opm/simulators/wells/GasLiftStage2.hpp @@ -172,7 +172,7 @@ protected: double oil_rate_, double gas_rate_, double water_rate_, double alq_, double min_eco_grad_, double oil_target_, double gas_target_, double water_target_, double liquid_target_, - std::optional max_glift_) : + std::optional max_glift_, std::optional max_total_gas_) : parent{parent_}, group{group_}, oil_rate{oil_rate_}, @@ -185,6 +185,7 @@ protected: water_target(water_target_), liquid_target{liquid_target_}, max_glift{max_glift_}, + max_total_gas{max_total_gas_}, it{0} {} GasLiftStage2 &parent; @@ -199,17 +200,19 @@ protected: const double water_target; const double liquid_target; std::optional max_glift; + std::optional max_total_gas; int it; void addOrRemoveALQincrement( GradMap &grad_map, const std::string& well_name, bool add); - bool checkALQlimit(); + bool checkALQlimit(double delta_alq, double delta_gas); bool checkEcoGradient(const std::string& well_name, double eco_grad); - bool checkGasTarget(); - bool checkLiquidTarget(double eco_grad); - bool checkOilTarget(double eco_grad); - bool checkWaterTarget(); - void updateRates(const std::string& name); + bool checkGasTarget(double delta_gas); + bool checkLiquidTarget(double delta_liquid); + bool checkOilTarget(double delta_oil); + bool checkWaterTarget(double delta_water); + std::array computeDelta(const std::string& name); + void updateRates(const std::array& delta); }; };