Merge pull request #3673 from totto82/fixGasliftX

Add check for group production control for LRAT and WRAT in the gasslift code
This commit is contained in:
Bård Skaflestad 2021-11-09 13:32:02 +01:00 committed by GitHub
commit c563f14aff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 337 additions and 84 deletions

View File

@ -948,12 +948,15 @@ namespace Opm {
group_oil_rates.reserve(num_rates_to_sync);
std::vector<double> group_gas_rates;
group_gas_rates.reserve(num_rates_to_sync);
std::vector<double> group_water_rates;
group_water_rates.reserve(num_rates_to_sync);
if (comm.rank() == i) {
for (auto idx : groups_to_sync) {
auto [oil_rate, gas_rate, alq] = group_info.getRates(idx);
auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
group_indexes.push_back(idx);
group_oil_rates.push_back(oil_rate);
group_gas_rates.push_back(gas_rate);
group_water_rates.push_back(water_rate);
group_alq_rates.push_back(alq);
}
}
@ -968,11 +971,12 @@ namespace Opm {
comm.broadcast(group_indexes.data(), num_rates_to_sync, i);
comm.broadcast(group_oil_rates.data(), num_rates_to_sync, i);
comm.broadcast(group_gas_rates.data(), num_rates_to_sync, i);
comm.broadcast(group_water_rates.data(), num_rates_to_sync, i);
comm.broadcast(group_alq_rates.data(), num_rates_to_sync, i);
if (comm.rank() != i) {
for (int j=0; j<num_rates_to_sync; j++) {
group_info.updateRate(group_indexes[j],
group_oil_rates[j], group_gas_rates[j], group_alq_rates[j]);
group_oil_rates[j], group_gas_rates[j], group_water_rates[j], group_alq_rates[j]);
}
}
}

View File

@ -84,13 +84,13 @@ gasTarget(const std::string& group_name)
return group_rate.gasTarget();
}
std::tuple<double, double, double>
std::tuple<double, double, double, double>
GasLiftGroupInfo::
getRates(int group_idx)
{
const auto& group_name = groupIdxToName(group_idx);
auto& rates = this->group_rate_map_.at(group_name);
return std::make_tuple(rates.oilRate(), rates.gasRate(), rates.alq());
return std::make_tuple(rates.oilRate(), rates.gasRate(), rates.waterRate(), rates.alq());
}
std::vector<std::pair<std::string,double>>&
@ -165,22 +165,46 @@ oilTarget(const std::string &group_name)
return group_rate.oilTarget();
}
void
double
GasLiftGroupInfo::
update(
const std::string &group_name, double delta_oil, double delta_gas, double delta_alq)
waterRate(const std::string &group_name)
{
auto& group_rate = this->group_rate_map_.at(group_name);
group_rate.update(delta_oil, delta_gas, delta_alq);
return group_rate.waterRate();
}
std::optional<double>
GasLiftGroupInfo::
waterTarget(const std::string &group_name)
{
auto& group_rate = this->group_rate_map_.at(group_name);
return group_rate.waterTarget();
}
std::optional<double>
GasLiftGroupInfo::
liquidTarget(const std::string &group_name)
{
auto& group_rate = this->group_rate_map_.at(group_name);
return group_rate.liquidTarget();
}
void
GasLiftGroupInfo::
updateRate(int idx, double oil_rate, double gas_rate, double alq)
update(
const std::string &group_name, double delta_oil, double delta_gas, double delta_water, double delta_alq)
{
auto& group_rate = this->group_rate_map_.at(group_name);
group_rate.update(delta_oil, delta_gas, delta_water, delta_alq);
}
void
GasLiftGroupInfo::
updateRate(int idx, double oil_rate, double gas_rate, double water_rate, double alq)
{
const auto& group_name = groupIdxToName(idx);
auto& rates = this->group_rate_map_.at(group_name);
rates.assign(oil_rate, gas_rate, alq);
rates.assign(oil_rate, gas_rate, water_rate, alq);
}
/****************************************
@ -295,7 +319,7 @@ displayDebugMessage_(const std::string &msg, const std::string &well_name)
}
std::pair<double, double>
std::tuple<double, double, double>
GasLiftGroupInfo::
getProducerWellRates_(int well_index)
{
@ -311,14 +335,19 @@ getProducerWellRates_(int well_index)
? -wrate[pu.phase_pos[Gas]]
: 0.0;
return {oil_rate, gas_rate};
const auto water_rate = pu.phase_used[Water]
? -wrate[pu.phase_pos[Water]]
: 0.0;
return {oil_rate, gas_rate, water_rate};
}
std::tuple<double, double, double>
std::tuple<double, double, double, double>
GasLiftGroupInfo::
initializeGroupRatesRecursive_(const Group &group)
{
double oil_rate = 0.0;
double water_rate = 0.0;
double gas_rate = 0.0;
double alq = 0.0;
if (group.wellgroup()) {
@ -335,17 +364,19 @@ initializeGroupRatesRecursive_(const Group &group)
assert(well); // Should never be nullptr
const int index = (itr->second).second;
if (well->isProducer()) {
auto [sw_oil_rate, sw_gas_rate] = getProducerWellRates_(index);
auto [sw_oil_rate, sw_gas_rate, sw_water_rate] = getProducerWellRates_(index);
auto sw_alq = this->well_state_.getALQ(well_name);
double factor = well->getEfficiencyFactor();
oil_rate += (factor * sw_oil_rate);
gas_rate += (factor * sw_gas_rate);
water_rate += (factor * sw_water_rate);
alq += (factor * sw_alq);
}
}
}
oil_rate = this->comm_.sum(oil_rate);
gas_rate = this->comm_.sum(gas_rate);
water_rate = this->comm_.sum(water_rate);
alq = this->comm_.sum(alq);
}
else {
@ -354,33 +385,40 @@ initializeGroupRatesRecursive_(const Group &group)
continue;
const Group& sub_group = this->schedule_.getGroup(
group_name, this->report_step_idx_);
auto [sg_oil_rate, sg_gas_rate, sg_alq]
auto [sg_oil_rate, sg_gas_rate, sg_water_rate, sg_alq]
= initializeGroupRatesRecursive_(sub_group);
const auto gefac = sub_group.getGroupEfficiencyFactor();
oil_rate += (gefac * sg_oil_rate);
gas_rate += (gefac * sg_gas_rate);
water_rate += (gefac * sg_water_rate);
alq += (gefac * sg_alq);
}
}
std::optional<double> oil_target, gas_target, max_total_gas, max_alq;
std::optional<double> oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq;
const auto controls = group.productionControls(this->summary_state_);
if (group.has_control(Group::ProductionCMode::LRAT)) {
liquid_target = controls.liquid_target;
}
if (group.has_control(Group::ProductionCMode::ORAT)) {
oil_target = controls.oil_target;
}
if (group.has_control(Group::ProductionCMode::GRAT)) {
gas_target = controls.gas_target;
}
if (group.has_control(Group::ProductionCMode::WRAT)) {
water_target = controls.water_target;
}
if (this->glo_.has_group(group.name())) {
const auto &gl_group = this->glo_.group(group.name());
max_alq = gl_group.max_lift_gas();
max_total_gas = gl_group.max_total_gas();
}
if (oil_target || gas_target || max_total_gas || max_alq) {
if (oil_target || liquid_target || water_target || gas_target || max_total_gas || max_alq) {
updateGroupIdxMap_(group.name());
this->group_rate_map_.try_emplace(group.name(),
oil_rate, gas_rate, alq, oil_target, gas_target, max_total_gas, max_alq);
oil_rate, gas_rate, water_rate, alq, oil_target, gas_target, water_target, liquid_target, max_total_gas, max_alq);
}
return std::make_tuple(oil_rate, gas_rate, alq);
return std::make_tuple(oil_rate, gas_rate, water_rate, alq);
}
void

View File

@ -84,25 +84,28 @@ public:
double alqRate(const std::string& group_name);
double gasRate(const std::string& group_name);
int getGroupIdx(const std::string& group_name);
std::tuple<double,double,double> getRates(int group_idx);
std::tuple<double,double,double,double> getRates(int group_idx);
std::optional<double> gasTarget(const std::string& group_name);
const std::string& groupIdxToName(int group_idx);
bool hasWell(const std::string& well_name);
void initialize();
std::optional<double> maxAlq(const std::string& group_name);
double oilRate(const std::string& group_name);
double waterRate(const std::string& group_name);
std::optional<double> oilTarget(const std::string& group_name);
std::optional<double> waterTarget(const std::string& group_name);
std::optional<double> liquidTarget(const std::string& group_name);
void update(const std::string& well_name,
double delta_oil, double delta_gas, double delta_alq);
void updateRate(int idx, double oil_rate, double gas_rate, double alq);
double delta_oil, double delta_gas, double delta_water, double delta_alq);
void updateRate(int idx, double oil_rate, double gas_rate, double water_rate, double alq);
const Well2GroupMap& wellGroupMap() { return well_group_map_; }
private:
bool checkDoGasLiftOptimization_(const std::string& well_name);
bool checkNewtonIterationIdxOk_(const std::string& well_name);
void displayDebugMessage_(const std::string& msg);
void displayDebugMessage_(const std::string& msg, const std::string& well_name);
std::pair<double, double> getProducerWellRates_(const int index);
std::tuple<double, double, double>
std::tuple<double, double, double> getProducerWellRates_(const int index);
std::tuple<double, double, double, double>
initializeGroupRatesRecursive_(const Group &group);
void initializeWell2GroupMapRecursive_(
const Group& group, std::vector<std::string>& group_names,
@ -112,44 +115,58 @@ private:
class GroupRates {
public:
GroupRates( double oil_rate, double gas_rate, double alq,
GroupRates( double oil_rate, double gas_rate, double water_rate, double alq,
std::optional<double> oil_target,
std::optional<double> gas_target,
std::optional<double> water_target,
std::optional<double> liquid_target,
std::optional<double> total_gas,
std::optional<double> max_alq
) :
oil_rate_{oil_rate},
gas_rate_{gas_rate},
water_rate_{water_rate},
alq_{alq},
oil_target_{oil_target},
gas_target_{gas_target},
water_target_{water_target},
liquid_target_{liquid_target},
total_gas_{total_gas},
max_alq_{max_alq}
{}
double alq() const { return alq_; }
void assign(double oil_rate, double gas_rate, double alq)
void assign(double oil_rate, double gas_rate, double water_rate, double alq)
{
oil_rate_ = oil_rate;
gas_rate_ = gas_rate;
water_rate_ = water_rate;
alq_ = alq;
}
double gasRate() const { return gas_rate_; }
double waterRate() const { return water_rate_; }
std::optional<double> gasTarget() const { return gas_target_; }
std::optional<double> waterTarget() const { return water_target_; }
std::optional<double> maxAlq() const { return max_alq_; }
double oilRate() const { return oil_rate_; }
std::optional<double> oilTarget() const { return oil_target_; }
void update(double delta_oil, double delta_gas, double delta_alq)
std::optional<double> liquidTarget() const { return liquid_target_; }
void update(double delta_oil, double delta_gas, double delta_water, double delta_alq)
{
oil_rate_ += delta_oil;
gas_rate_ += delta_gas;
water_rate_ += delta_water;
alq_ += delta_alq;
}
private:
double oil_rate_;
double gas_rate_;
double water_rate_;
double alq_;
std::optional<double> oil_target_;
std::optional<double> gas_target_;
std::optional<double> water_target_;
std::optional<double> liquid_target_;
std::optional<double> total_gas_;
std::optional<double> max_alq_;
};

View File

@ -317,8 +317,9 @@ computeInitialWellRates_(std::vector<double>& potentials)
void
GasLiftSingleWellGeneric::
debugCheckNegativeGradient_(double grad, double alq, double new_alq, double oil_rate,
double new_oil_rate, double gas_rate, double new_gas_rate, bool increase) const
debugCheckNegativeGradient_(double grad, double alq, double new_alq,
double oil_rate, double new_oil_rate,
double gas_rate, double new_gas_rate, bool increase) const
{
{
const std::string msg = fmt::format("calculating gradient: "
@ -471,6 +472,22 @@ getGasRateWithLimit_(const std::vector<double>& potentials) const
return { new_rate, limit};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getWaterRateWithLimit_(const std::vector<double>& potentials) const
{
double new_rate = -potentials[this->water_pos_];
bool limit = false;
if (this->controls_.hasControl(Well::ProducerCMode::WRAT)) {
auto target = this->controls_.water_rate;
if (new_rate > target) {
new_rate = target;
limit = true;
}
}
return { new_rate, limit};
}
// NOTE: If the computed oil rate is larger than the target
// rate of the well, we reduce it to the target rate. This
// will make the economic gradient smaller than it would be
@ -484,44 +501,152 @@ std::pair<double, bool>
GasLiftSingleWellGeneric::
getOilRateWithLimit_(const std::vector<double>& potentials) const
{
double new_rate = -potentials[this->oil_pos_];
double oil_rate = -potentials[this->oil_pos_];
double new_rate = oil_rate;
bool limited = false;
if (this->controls_.hasControl(Well::ProducerCMode::ORAT)) {
auto target = this->controls_.oil_rate;
if (new_rate > target) {
if (oil_rate > target) {
const std::string msg = fmt::format("limiting oil rate to target: "
"computed rate: {}, target: {}", new_rate, target);
displayDebugMessage_(msg);
new_rate = target;
return { new_rate, /*limit=*/true};
limited = true;
}
}
// TODO: What to do if both oil and lrat are violated?
// Currently oil rate violation takes precedence if both are
// violated, and the new rate is set to the oil rate target.
if (this->controls_.hasControl(Well::ProducerCMode::LRAT)) {
auto target = this->controls_.liquid_rate;
auto oil_rate = -potentials[this->oil_pos_];
auto water_rate = -potentials[this->water_pos_];
auto liq_rate = oil_rate + water_rate;
double water_rate = -potentials[this->water_pos_];
double liq_rate = oil_rate + water_rate;
if (liq_rate > target) {
new_rate = oil_rate * (target/liq_rate);
double oil_fraction = oil_rate / liq_rate;
new_rate = std::min(new_rate, oil_fraction * target);
limited = true;
const std::string msg = fmt::format(
"limiting oil rate due to LRAT target {}: "
"computed rate: {}, target: {}", target, oil_rate, new_rate);
"limiting oil rate due to LRAT target: "
"computed rate: {}, target: {}", oil_rate, new_rate);
displayDebugMessage_(msg);
return { new_rate, /*limit=*/true};
}
}
return { new_rate, /*limit=*/false};
return { new_rate, limited};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getOilRateWithGroupLimit_(const double new_oil_rate, const double oil_rate) const
{
const double delta_oil = new_oil_rate - oil_rate;
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
for (const auto &[group_name, efficiency] : pairs) {
auto gr_oil_target_opt = this->group_info_.oilTarget(group_name);
if (gr_oil_target_opt) {
double gr_oil_rate =
this->group_info_.oilRate(group_name);
double new_gr_oil_rate = gr_oil_rate + efficiency * delta_oil;
if (new_gr_oil_rate > *gr_oil_target_opt) {
const std::string msg = fmt::format("limiting oil rate to group target: "
"computed group rate: {}, target: {}", new_gr_oil_rate, *gr_oil_target_opt);
displayDebugMessage_(msg);
double new_rate = oil_rate + (*gr_oil_target_opt - gr_oil_rate) / efficiency;
return { std::min(new_rate, new_oil_rate), /*limit=*/true};
}
}
}
return { new_oil_rate, /*limit=*/false};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getGasRateWithGroupLimit_(const double new_gas_rate, const double gas_rate) const
{
const double delta_gas = new_gas_rate - gas_rate;
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
for (const auto &[group_name, efficiency] : pairs) {
auto gr_gas_target_opt = this->group_info_.gasTarget(group_name);
if (gr_gas_target_opt) {
double gr_gas_rate =
this->group_info_.gasRate(group_name);
double new_gr_gas_rate = gr_gas_rate + efficiency * delta_gas;
if (new_gr_gas_rate > *gr_gas_target_opt) {
const std::string msg = fmt::format("limiting gas rate to group target: "
"computed group rate: {}, target: {}", new_gr_gas_rate, *gr_gas_target_opt);
displayDebugMessage_(msg);
double new_rate = gas_rate + (*gr_gas_target_opt - gr_gas_rate) / efficiency;
return { std::min(new_rate, new_gas_rate), /*limit=*/true};
}
}
}
return { new_gas_rate, /*limit=*/false};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getWaterRateWithGroupLimit_(const double new_water_rate, const double water_rate) const
{
const double delta_water = new_water_rate - water_rate;
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
for (const auto &[group_name, efficiency] : pairs) {
auto gr_water_target_opt = this->group_info_.waterTarget(group_name);
if (gr_water_target_opt) {
double gr_water_rate =
this->group_info_.waterRate(group_name);
double new_gr_water_rate = gr_water_rate + efficiency * delta_water;
if (new_gr_water_rate > *gr_water_target_opt) {
const std::string msg = fmt::format("limiting water rate to group target: "
"computed group rate: {}, target: {}", new_gr_water_rate, *gr_water_target_opt);
displayDebugMessage_(msg);
double new_rate = water_rate + (*gr_water_target_opt - gr_water_rate) / efficiency;
return { std::min(new_rate, new_water_rate), /*limit=*/true};
}
}
}
return { new_water_rate, /*limit=*/false};
}
std::tuple<double, double, bool, bool>
GasLiftSingleWellGeneric::
getLiquidRateWithGroupLimit_(const double new_oil_rate, const double oil_rate,
const double new_water_rate, const double water_rate) const
{
const double delta_water = new_water_rate - water_rate;
const double delta_oil = new_oil_rate - oil_rate;
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
for (const auto &[group_name, efficiency] : pairs) {
auto gr_liquid_target_opt = this->group_info_.liquidTarget(group_name);
if (gr_liquid_target_opt) {
double gr_water_rate =
this->group_info_.waterRate(group_name);
double gr_oil_rate =
this->group_info_.oilRate(group_name);
double new_gr_water_rate = gr_water_rate + efficiency * delta_water;
double new_gr_oil_rate = gr_oil_rate + efficiency * delta_oil;
double new_gr_liquid_rate = new_gr_water_rate + new_gr_oil_rate;
if (new_gr_liquid_rate > *gr_liquid_target_opt) {
const std::string msg = fmt::format("limiting liquid rate to group target: "
"computed group rate: {}, target: {}", new_gr_liquid_rate, *gr_liquid_target_opt);
displayDebugMessage_(msg);
double oil_fraction = new_gr_oil_rate / new_gr_liquid_rate;
double water_rate_limited = water_rate + (1.0 - oil_fraction) * (new_gr_liquid_rate - *gr_liquid_target_opt) / efficiency;
double oil_rate_limited = oil_rate + oil_fraction * (new_gr_liquid_rate - *gr_liquid_target_opt) / efficiency;
return { std::min(oil_rate_limited, new_oil_rate), std::min(water_rate_limited, new_water_rate), /*limit=*/true, /*limit=*/true};
}
}
}
return { new_oil_rate, new_water_rate, /*limit=*/false, /*limit=*/false};
}
std::tuple<double,double,double, bool, bool,bool>
GasLiftSingleWellGeneric::
getInitialRatesWithLimit_(const std::vector<double>& potentials)
{
auto [oil_rate, oil_is_limited] = getOilRateWithLimit_(potentials);
auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(potentials);
auto [water_rate, water_is_limited] = getWaterRateWithLimit_(potentials);
if (oil_is_limited) {
const std::string msg = fmt::format(
"initial oil rate was limited to: {}", oil_rate);
@ -532,7 +657,12 @@ getInitialRatesWithLimit_(const std::vector<double>& potentials)
"initial gas rate was limited to: {}", gas_rate);
displayDebugMessage_(msg);
}
return std::make_tuple(oil_rate, gas_rate, oil_is_limited, gas_is_limited);
if (water_is_limited) {
const std::string msg = fmt::format(
"initial water rate was limited to: {}", water_rate);
displayDebugMessage_(msg);
}
return std::make_tuple(oil_rate, gas_rate, water_rate, oil_is_limited, gas_is_limited, water_is_limited);
}
std::tuple<double,double,bool,bool,double>
@ -605,11 +735,11 @@ logSuccess_(double alq, const int iteration_idx)
this->deferred_logger_.info(message);
}
std::tuple<double,double,double,bool,bool>
std::tuple<double,double,double,double,bool,bool,bool>
GasLiftSingleWellGeneric::
maybeAdjustALQbeforeOptimizeLoop_(
bool increase, double alq, double oil_rate, double gas_rate,
bool oil_is_limited, bool gas_is_limited,
bool increase, double alq, double oil_rate, double gas_rate, double water_rate,
bool oil_is_limited, bool gas_is_limited,bool water_is_limited,
std::vector<double> &potentials)
{
double orig_alq = alq;
@ -646,7 +776,7 @@ maybeAdjustALQbeforeOptimizeLoop_(
const std::string msg = fmt::format("adjusted ALQ to: {}", alq);
displayDebugMessage_(msg);
}
return std::make_tuple(oil_rate, gas_rate, alq, oil_is_limited, gas_is_limited);
return std::make_tuple(oil_rate, gas_rate, water_rate, alq, oil_is_limited, gas_is_limited, water_is_limited);
}
std::tuple<double,double,bool,bool,double>
@ -720,40 +850,46 @@ runOptimizeLoop_(bool increase)
bool alq_is_limited = false;
bool oil_is_limited = false;
bool gas_is_limited = false;
double oil_rate, gas_rate;
std::tie(oil_rate, gas_rate, oil_is_limited, gas_is_limited) =
bool water_is_limited = false;
double oil_rate, gas_rate, water_rate;
std::tie(oil_rate, gas_rate, water_rate, oil_is_limited, gas_is_limited, water_is_limited) =
getInitialRatesWithLimit_(potentials);
//if (this->debug_) debugShowBhpAlqTable_();
if (this->debug_) debugShowAlqIncreaseDecreaseCounts_();
if (this->debug_) debugShowTargets_();
bool success = false; // did we succeed to increase alq?
auto cur_alq = this->orig_alq_;
double new_oil_rate, new_gas_rate, new_alq;
bool new_oil_is_limited, new_gas_is_limited;
std::tie(new_oil_rate, new_gas_rate, new_alq, new_oil_is_limited, new_gas_is_limited)
double new_oil_rate, new_gas_rate, new_water_rate, new_alq;
bool new_oil_is_limited, new_gas_is_limited, new_water_is_limited;
std::tie(new_oil_rate, new_gas_rate, new_water_rate, new_alq,
new_oil_is_limited, new_gas_is_limited, new_water_is_limited)
= maybeAdjustALQbeforeOptimizeLoop_(
increase, cur_alq, oil_rate, gas_rate,
oil_is_limited, gas_is_limited, potentials);
increase, cur_alq, oil_rate, gas_rate, water_rate,
oil_is_limited, gas_is_limited, water_is_limited, potentials);
double delta_oil = 0.0;
double delta_gas = 0.0;
double delta_alq = 0.0;
double delta_water = 0.0;
OptimizeState state {*this, increase};
// potentially reduce alq if group control is violated
std::tie(new_oil_rate, new_gas_rate, new_alq) =
state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, potentials);
std::tie(new_oil_rate, new_gas_rate, new_water_rate, new_alq) =
state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, new_water_rate, potentials);
if (checkInitialALQmodified_(new_alq, cur_alq)) {
delta_oil = new_oil_rate - oil_rate;
delta_gas = new_gas_rate - gas_rate;
delta_water = new_water_rate - water_rate;
delta_alq = new_alq - cur_alq;
if (!(state.checkGroupTargetsViolated(delta_oil, delta_gas)) &&
if (!(state.checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) &&
!(state.checkGroupALQrateExceeded(delta_alq)))
{
oil_rate = new_oil_rate;
gas_rate = new_gas_rate;
water_rate = new_water_rate;
oil_is_limited = new_oil_is_limited;
gas_is_limited = new_gas_is_limited;
water_is_limited = new_water_is_limited;
cur_alq = new_alq;
success = true;
}
@ -771,7 +907,7 @@ runOptimizeLoop_(bool increase)
while (!state.stop_iteration && (++state.it <= this->max_iterations_)) {
if (!increase && state.checkNegativeOilRate(oil_rate)) break;
if (state.checkWellRatesViolated(potentials)) break;
if (state.checkGroupTargetsViolated(delta_oil, delta_gas)) break;
if (state.checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) break;
if (state.checkAlqOutsideLimits(temp_alq, oil_rate)) break;
std::optional<double> alq_opt;
std::tie(alq_opt, alq_is_limited)
@ -786,6 +922,8 @@ runOptimizeLoop_(bool increase)
auto bhp = state.getBhpWithLimit();
computeWellRates_(bhp, potentials);
std::tie(new_oil_rate, new_oil_is_limited) = getOilRateWithLimit_(potentials);
std::tie(new_oil_rate, new_oil_is_limited) = getOilRateWithGroupLimit_(new_oil_rate, oil_rate);
/* if (this->debug_abort_if_decrease_and_oil_is_limited_) {
if (oil_is_limited && !increase) {
// if oil is limited we do not want to decrease
@ -796,6 +934,15 @@ runOptimizeLoop_(bool increase)
}
*/
std::tie(new_gas_rate, new_gas_is_limited) = getGasRateWithLimit_(potentials);
std::tie(new_gas_rate, new_gas_is_limited) = getGasRateWithGroupLimit_(new_gas_rate, gas_rate);
std::tie(new_water_rate, new_water_is_limited) = getWaterRateWithLimit_(potentials);
std::tie(new_water_rate, new_water_is_limited) = getWaterRateWithGroupLimit_(new_water_rate, water_rate);
std::tie(new_oil_rate, new_water_rate, new_oil_is_limited, new_water_is_limited)
= getLiquidRateWithGroupLimit_(new_oil_rate, oil_rate, new_water_rate, water_rate);
/* if (this->debug_abort_if_increase_and_gas_is_limited_) {
if (gas_is_limited && increase) {
// if gas is limited we do not want to increase
@ -816,11 +963,14 @@ runOptimizeLoop_(bool increase)
success = true;
delta_oil = new_oil_rate - oil_rate;
delta_gas = new_gas_rate - gas_rate;
delta_water = new_water_rate - water_rate;
oil_rate = new_oil_rate;
gas_rate = new_gas_rate;
water_rate = new_water_rate;
oil_is_limited = new_oil_is_limited;
gas_is_limited = new_gas_is_limited;
state.updateGroupRates(delta_oil, delta_gas, delta_alq);
water_is_limited = new_water_is_limited;
state.updateGroupRates(delta_oil, delta_gas, delta_water, delta_alq);
}
if (state.it > this->max_iterations_) {
warnMaxIterationsExceeded_();
@ -843,11 +993,11 @@ GasLiftSingleWellGeneric::
runOptimize1_()
{
std::unique_ptr<GasLiftWellState> state;
auto inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_);
auto dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_);
int inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_);
int dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_);
if (dec_count == 0 && inc_count == 0) {
state = tryIncreaseLiftGas_();
if (!state && !state->alqChanged()) {
if (!state || !(state->alqChanged())) {
state = tryDecreaseLiftGas_();
}
}
@ -1137,7 +1287,7 @@ checkGroupALQrateExceeded(double delta_alq)
bool
GasLiftSingleWellGeneric::OptimizeState::
checkGroupTargetsViolated(double delta_oil, double delta_gas)
checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water)
{
const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_);
@ -1170,19 +1320,49 @@ checkGroupTargetsViolated(double delta_oil, double delta_gas)
return true;
}
}
auto liquid_target_opt = this->parent.group_info_.liquidTarget(group_name);
if (liquid_target_opt) {
double oil_rate =
this->parent.group_info_.oilRate(group_name) + efficiency * delta_oil;
double water_rate =
this->parent.group_info_.waterRate(group_name) + efficiency * delta_water;
double liquid_rate = oil_rate + water_rate;
if (liquid_rate > *liquid_target_opt) {
if (this->parent.debug_) {
const std::string msg = fmt::format(
"Group {} : liquid rate {} exceeds liquid target {}. Stopping iteration",
group_name, liquid_rate, *liquid_target_opt);
this->parent.displayDebugMessage_(msg);
}
return true;
}
}
auto water_target_opt = this->parent.group_info_.waterTarget(group_name);
if (water_target_opt) {
double water_rate =
this->parent.group_info_.waterRate(group_name) + efficiency * delta_water;
if (water_rate > *water_target_opt) {
if (this->parent.debug_) {
const std::string msg = fmt::format(
"Group {} : water rate {} exceeds water target {}. Stopping iteration",
group_name, water_rate, *water_target_opt);
this->parent.displayDebugMessage_(msg);
}
return true;
}
}
}
return false;
}
std::tuple<double,double,double>
std::tuple<double,double,double,double>
GasLiftSingleWellGeneric::OptimizeState::
reduceALQtoGroupTarget(double alq,
double oil_rate,
double gas_rate,
double water_rate,
std::vector<double>& potentials)
{
// Note: Currently the checkGroupTargetsViolated only check
// for GRAT and ORAT group controls.
bool stop_this_iteration = true;
const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_);
@ -1190,7 +1370,10 @@ reduceALQtoGroupTarget(double alq,
if (!this->parent.group_state_.has_production_control(groups.first))
continue;
const auto& current_control = this->parent.group_state_.production_control(groups.first);
if(current_control == Group::ProductionCMode::ORAT || current_control == Group::ProductionCMode::GRAT){
if(current_control == Group::ProductionCMode::ORAT
|| current_control == Group::ProductionCMode::LRAT
|| current_control == Group::ProductionCMode::WRAT
|| current_control == Group::ProductionCMode::GRAT){
stop_this_iteration = false;
this->parent.displayDebugMessage_("Reducing ALQ to meet groups target before iteration starts.");
break;
@ -1199,6 +1382,7 @@ reduceALQtoGroupTarget(double alq,
double temp_alq = alq;
double oil_rate_orig = oil_rate;
double gas_rate_orig = gas_rate;
double water_rate_orig = water_rate;
while(!stop_this_iteration) {
temp_alq -= this->parent.increment_;
if (temp_alq <= 0) break;
@ -1208,15 +1392,17 @@ reduceALQtoGroupTarget(double alq,
this->parent.computeWellRates_(bhp_this.first, potentials);
oil_rate = -potentials[this->parent.oil_pos_];
gas_rate = -potentials[this->parent.gas_pos_];
water_rate = -potentials[this->parent.gas_pos_];
double delta_oil = oil_rate_orig - oil_rate;
double delta_gas = gas_rate_orig - gas_rate;
double delta_water = water_rate_orig - water_rate;
if (!this->checkGroupTargetsViolated(delta_oil, delta_gas)) {
if (!this->checkGroupTargetsViolated(delta_oil, delta_gas, delta_water)) {
break;
}
alq = temp_alq;
}
return std::make_tuple(oil_rate, gas_rate, alq);
return std::make_tuple(oil_rate, gas_rate, water_rate, alq);
}
bool
GasLiftSingleWellGeneric::OptimizeState::
@ -1367,7 +1553,7 @@ getBhpWithLimit()
void
GasLiftSingleWellGeneric::OptimizeState::
updateGroupRates(double delta_oil, double delta_gas, double delta_alq)
updateGroupRates(double delta_oil, double delta_gas, double delta_water, double delta_alq)
{
const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_);
@ -1375,7 +1561,7 @@ updateGroupRates(double delta_oil, double delta_gas, double delta_alq)
int idx = this->parent.group_info_.getGroupIdx(group_name);
this->parent.sync_groups_.insert(idx);
this->parent.group_info_.update(group_name,
efficiency * delta_oil, efficiency * delta_gas, efficiency * delta_alq);
efficiency * delta_oil, efficiency * delta_gas, efficiency * delta_water, efficiency * delta_alq);
}
}

View File

@ -126,9 +126,9 @@ protected:
bool checkAlqOutsideLimits(double alq, double oil_rate);
bool checkEcoGradient(double gradient);
bool checkGroupALQrateExceeded(double delta_alq);
bool checkGroupTargetsViolated(double delta_oil, double delta_gas);
std::tuple<double,double,double>
reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, std::vector<double> &potentials);
bool checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water);
std::tuple<double,double,double,double>
reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, double water_rate, std::vector<double> &potentials);
bool checkNegativeOilRate(double oil_rate);
bool checkThpControl();
bool checkOilRateExceedsTarget(double oil_rate);
@ -137,7 +137,7 @@ protected:
bool computeBhpAtThpLimit(double alq);
void debugShowIterationInfo(double alq);
double getBhpWithLimit();
void updateGroupRates(double delta_oil, double delta_gas, double delta_alq);
void updateGroupRates(double delta_oil, double delta_gas, double delta_water, double delta_alq);
void warn_(std::string msg) {parent.displayWarning_(msg);}
};
@ -162,8 +162,9 @@ protected:
bool computeInitialWellRates_(std::vector<double>& potentials);
void debugCheckNegativeGradient_(double grad, double alq, double new_alq,
double oil_rate, double new_oil_rate, double gas_rate,
double new_gas_rate, bool increase) const;
double oil_rate, double new_oil_rate,
double gas_rate, double new_gas_rate,
bool increase) const;
void debugShowAlqIncreaseDecreaseCounts_();
@ -178,9 +179,16 @@ protected:
std::pair<double, bool> getBhpWithLimit_(double bhp) const;
std::pair<double, bool> getGasRateWithLimit_(const std::vector<double>& potentials) const;
std::tuple<double,double,bool,bool>
std::tuple<double,double,double,bool,bool,bool>
getInitialRatesWithLimit_(const std::vector<double>& potentials);
std::pair<double, bool> getOilRateWithLimit_(const std::vector<double>& potentials) const;
std::pair<double, bool> getWaterRateWithLimit_(const std::vector<double>& potentials) const;
std::pair<double, bool> getOilRateWithGroupLimit_(const double new_oil_rate, const double oil_rate) const;
std::pair<double, bool> getGasRateWithGroupLimit_(const double new_gas_rate, const double gas_rate) const;
std::pair<double, bool> getWaterRateWithGroupLimit_(const double new_water_rate, const double water_rate) const;
std::tuple<double,double,bool,bool> getLiquidRateWithGroupLimit_(double new_oil_rate, const double oil_rate,
double new_water_rate, const double water_rate) const;
std::tuple<double,double,bool,bool,double>
increaseALQtoPositiveOilRate_(double alq,
@ -200,10 +208,10 @@ protected:
void logSuccess_(double alq,
const int iteration_idx);
std::tuple<double,double,double,bool,bool>
std::tuple<double,double,double, double,bool,bool,bool>
maybeAdjustALQbeforeOptimizeLoop_(
bool increase, double alq, double oil_rate, double gas_rate,
bool oil_is_limited, bool gas_is_limited, std::vector<double> &potentials);
bool increase, double alq, double oil_rate, double gas_rate, double water_rate,
bool oil_is_limited, bool gas_is_limited, bool water_is_limited, std::vector<double> &potentials);
std::tuple<double,double,bool,bool,double>
reduceALQtoOilTarget_(double alq, double oil_rate, double gas_rate,
bool oil_is_limited, bool gas_is_limited, std::vector<double> &potentials);