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); group_oil_rates.reserve(num_rates_to_sync);
std::vector<double> group_gas_rates; std::vector<double> group_gas_rates;
group_gas_rates.reserve(num_rates_to_sync); 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) { if (comm.rank() == i) {
for (auto idx : groups_to_sync) { 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_indexes.push_back(idx);
group_oil_rates.push_back(oil_rate); group_oil_rates.push_back(oil_rate);
group_gas_rates.push_back(gas_rate); group_gas_rates.push_back(gas_rate);
group_water_rates.push_back(water_rate);
group_alq_rates.push_back(alq); 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_indexes.data(), num_rates_to_sync, i);
comm.broadcast(group_oil_rates.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_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); comm.broadcast(group_alq_rates.data(), num_rates_to_sync, i);
if (comm.rank() != i) { if (comm.rank() != i) {
for (int j=0; j<num_rates_to_sync; j++) { for (int j=0; j<num_rates_to_sync; j++) {
group_info.updateRate(group_indexes[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(); return group_rate.gasTarget();
} }
std::tuple<double, double, double> std::tuple<double, double, double, double>
GasLiftGroupInfo:: GasLiftGroupInfo::
getRates(int group_idx) getRates(int group_idx)
{ {
const auto& group_name = groupIdxToName(group_idx); const auto& group_name = groupIdxToName(group_idx);
auto& rates = this->group_rate_map_.at(group_name); 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>>& std::vector<std::pair<std::string,double>>&
@ -165,22 +165,46 @@ oilTarget(const std::string &group_name)
return group_rate.oilTarget(); return group_rate.oilTarget();
} }
void double
GasLiftGroupInfo:: GasLiftGroupInfo::
update( waterRate(const std::string &group_name)
const std::string &group_name, double delta_oil, double delta_gas, double delta_alq)
{ {
auto& group_rate = this->group_rate_map_.at(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 void
GasLiftGroupInfo:: 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); const auto& group_name = groupIdxToName(idx);
auto& rates = this->group_rate_map_.at(group_name); 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:: GasLiftGroupInfo::
getProducerWellRates_(int well_index) getProducerWellRates_(int well_index)
{ {
@ -311,14 +335,19 @@ getProducerWellRates_(int well_index)
? -wrate[pu.phase_pos[Gas]] ? -wrate[pu.phase_pos[Gas]]
: 0.0; : 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:: GasLiftGroupInfo::
initializeGroupRatesRecursive_(const Group &group) initializeGroupRatesRecursive_(const Group &group)
{ {
double oil_rate = 0.0; double oil_rate = 0.0;
double water_rate = 0.0;
double gas_rate = 0.0; double gas_rate = 0.0;
double alq = 0.0; double alq = 0.0;
if (group.wellgroup()) { if (group.wellgroup()) {
@ -335,17 +364,19 @@ initializeGroupRatesRecursive_(const Group &group)
assert(well); // Should never be nullptr assert(well); // Should never be nullptr
const int index = (itr->second).second; const int index = (itr->second).second;
if (well->isProducer()) { 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); auto sw_alq = this->well_state_.getALQ(well_name);
double factor = well->getEfficiencyFactor(); double factor = well->getEfficiencyFactor();
oil_rate += (factor * sw_oil_rate); oil_rate += (factor * sw_oil_rate);
gas_rate += (factor * sw_gas_rate); gas_rate += (factor * sw_gas_rate);
water_rate += (factor * sw_water_rate);
alq += (factor * sw_alq); alq += (factor * sw_alq);
} }
} }
} }
oil_rate = this->comm_.sum(oil_rate); oil_rate = this->comm_.sum(oil_rate);
gas_rate = this->comm_.sum(gas_rate); gas_rate = this->comm_.sum(gas_rate);
water_rate = this->comm_.sum(water_rate);
alq = this->comm_.sum(alq); alq = this->comm_.sum(alq);
} }
else { else {
@ -354,33 +385,40 @@ initializeGroupRatesRecursive_(const Group &group)
continue; continue;
const Group& sub_group = this->schedule_.getGroup( const Group& sub_group = this->schedule_.getGroup(
group_name, this->report_step_idx_); 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); = initializeGroupRatesRecursive_(sub_group);
const auto gefac = sub_group.getGroupEfficiencyFactor(); const auto gefac = sub_group.getGroupEfficiencyFactor();
oil_rate += (gefac * sg_oil_rate); oil_rate += (gefac * sg_oil_rate);
gas_rate += (gefac * sg_gas_rate); gas_rate += (gefac * sg_gas_rate);
water_rate += (gefac * sg_water_rate);
alq += (gefac * sg_alq); 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_); 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)) { if (group.has_control(Group::ProductionCMode::ORAT)) {
oil_target = controls.oil_target; oil_target = controls.oil_target;
} }
if (group.has_control(Group::ProductionCMode::GRAT)) { if (group.has_control(Group::ProductionCMode::GRAT)) {
gas_target = controls.gas_target; gas_target = controls.gas_target;
} }
if (group.has_control(Group::ProductionCMode::WRAT)) {
water_target = controls.water_target;
}
if (this->glo_.has_group(group.name())) { if (this->glo_.has_group(group.name())) {
const auto &gl_group = this->glo_.group(group.name()); const auto &gl_group = this->glo_.group(group.name());
max_alq = gl_group.max_lift_gas(); max_alq = gl_group.max_lift_gas();
max_total_gas = gl_group.max_total_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()); updateGroupIdxMap_(group.name());
this->group_rate_map_.try_emplace(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 void

View File

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

View File

@ -317,8 +317,9 @@ computeInitialWellRates_(std::vector<double>& potentials)
void void
GasLiftSingleWellGeneric:: GasLiftSingleWellGeneric::
debugCheckNegativeGradient_(double grad, double alq, double new_alq, double oil_rate, debugCheckNegativeGradient_(double grad, double alq, double new_alq,
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
{ {
{ {
const std::string msg = fmt::format("calculating gradient: " const std::string msg = fmt::format("calculating gradient: "
@ -471,6 +472,22 @@ getGasRateWithLimit_(const std::vector<double>& potentials) const
return { new_rate, limit}; 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 // NOTE: If the computed oil rate is larger than the target
// rate of the well, we reduce it to the target rate. This // rate of the well, we reduce it to the target rate. This
// will make the economic gradient smaller than it would be // will make the economic gradient smaller than it would be
@ -484,44 +501,152 @@ std::pair<double, bool>
GasLiftSingleWellGeneric:: GasLiftSingleWellGeneric::
getOilRateWithLimit_(const std::vector<double>& potentials) const 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)) { if (this->controls_.hasControl(Well::ProducerCMode::ORAT)) {
auto target = this->controls_.oil_rate; 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: " const std::string msg = fmt::format("limiting oil rate to target: "
"computed rate: {}, target: {}", new_rate, target); "computed rate: {}, target: {}", new_rate, target);
displayDebugMessage_(msg); displayDebugMessage_(msg);
new_rate = target; 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)) { if (this->controls_.hasControl(Well::ProducerCMode::LRAT)) {
auto target = this->controls_.liquid_rate; auto target = this->controls_.liquid_rate;
auto oil_rate = -potentials[this->oil_pos_]; double water_rate = -potentials[this->water_pos_];
auto water_rate = -potentials[this->water_pos_]; double liq_rate = oil_rate + water_rate;
auto liq_rate = oil_rate + water_rate;
if (liq_rate > target) { 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( const std::string msg = fmt::format(
"limiting oil rate due to LRAT target {}: " "limiting oil rate due to LRAT target: "
"computed rate: {}, target: {}", target, oil_rate, new_rate); "computed rate: {}, target: {}", oil_rate, new_rate);
displayDebugMessage_(msg); displayDebugMessage_(msg);
return { new_rate, /*limit=*/true};
} }
} }
return { new_rate, /*limit=*/false}; return { new_rate, limited};
} }
std::tuple<double,double,bool,bool>
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:: GasLiftSingleWellGeneric::
getInitialRatesWithLimit_(const std::vector<double>& potentials) getInitialRatesWithLimit_(const std::vector<double>& potentials)
{ {
auto [oil_rate, oil_is_limited] = getOilRateWithLimit_(potentials); auto [oil_rate, oil_is_limited] = getOilRateWithLimit_(potentials);
auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(potentials); auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(potentials);
auto [water_rate, water_is_limited] = getWaterRateWithLimit_(potentials);
if (oil_is_limited) { if (oil_is_limited) {
const std::string msg = fmt::format( const std::string msg = fmt::format(
"initial oil rate was limited to: {}", oil_rate); "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); "initial gas rate was limited to: {}", gas_rate);
displayDebugMessage_(msg); 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> std::tuple<double,double,bool,bool,double>
@ -605,11 +735,11 @@ logSuccess_(double alq, const int iteration_idx)
this->deferred_logger_.info(message); this->deferred_logger_.info(message);
} }
std::tuple<double,double,double,bool,bool> std::tuple<double,double,double,double,bool,bool,bool>
GasLiftSingleWellGeneric:: GasLiftSingleWellGeneric::
maybeAdjustALQbeforeOptimizeLoop_( maybeAdjustALQbeforeOptimizeLoop_(
bool increase, double alq, double oil_rate, double gas_rate, bool increase, double alq, double oil_rate, double gas_rate, double water_rate,
bool oil_is_limited, bool gas_is_limited, bool oil_is_limited, bool gas_is_limited,bool water_is_limited,
std::vector<double> &potentials) std::vector<double> &potentials)
{ {
double orig_alq = alq; double orig_alq = alq;
@ -646,7 +776,7 @@ maybeAdjustALQbeforeOptimizeLoop_(
const std::string msg = fmt::format("adjusted ALQ to: {}", alq); const std::string msg = fmt::format("adjusted ALQ to: {}", alq);
displayDebugMessage_(msg); 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> std::tuple<double,double,bool,bool,double>
@ -720,40 +850,46 @@ runOptimizeLoop_(bool increase)
bool alq_is_limited = false; bool alq_is_limited = false;
bool oil_is_limited = false; bool oil_is_limited = false;
bool gas_is_limited = false; bool gas_is_limited = false;
double oil_rate, gas_rate; bool water_is_limited = false;
std::tie(oil_rate, gas_rate, oil_is_limited, gas_is_limited) = 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); getInitialRatesWithLimit_(potentials);
//if (this->debug_) debugShowBhpAlqTable_(); //if (this->debug_) debugShowBhpAlqTable_();
if (this->debug_) debugShowAlqIncreaseDecreaseCounts_(); if (this->debug_) debugShowAlqIncreaseDecreaseCounts_();
if (this->debug_) debugShowTargets_(); if (this->debug_) debugShowTargets_();
bool success = false; // did we succeed to increase alq? bool success = false; // did we succeed to increase alq?
auto cur_alq = this->orig_alq_; auto cur_alq = this->orig_alq_;
double new_oil_rate, new_gas_rate, new_alq; double new_oil_rate, new_gas_rate, new_water_rate, new_alq;
bool new_oil_is_limited, new_gas_is_limited; bool new_oil_is_limited, new_gas_is_limited, new_water_is_limited;
std::tie(new_oil_rate, new_gas_rate, new_alq, new_oil_is_limited, new_gas_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_( = maybeAdjustALQbeforeOptimizeLoop_(
increase, cur_alq, oil_rate, gas_rate, increase, cur_alq, oil_rate, gas_rate, water_rate,
oil_is_limited, gas_is_limited, potentials); oil_is_limited, gas_is_limited, water_is_limited, potentials);
double delta_oil = 0.0; double delta_oil = 0.0;
double delta_gas = 0.0; double delta_gas = 0.0;
double delta_alq = 0.0; double delta_alq = 0.0;
double delta_water = 0.0;
OptimizeState state {*this, increase}; OptimizeState state {*this, increase};
// potentially reduce alq if group control is violated // potentially reduce alq if group control is violated
std::tie(new_oil_rate, new_gas_rate, new_alq) = std::tie(new_oil_rate, new_gas_rate, new_water_rate, new_alq) =
state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, potentials); state.reduceALQtoGroupTarget(new_alq, new_oil_rate, new_gas_rate, new_water_rate, potentials);
if (checkInitialALQmodified_(new_alq, cur_alq)) { if (checkInitialALQmodified_(new_alq, cur_alq)) {
delta_oil = new_oil_rate - oil_rate; delta_oil = new_oil_rate - oil_rate;
delta_gas = new_gas_rate - gas_rate; delta_gas = new_gas_rate - gas_rate;
delta_water = new_water_rate - water_rate;
delta_alq = new_alq - cur_alq; 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))) !(state.checkGroupALQrateExceeded(delta_alq)))
{ {
oil_rate = new_oil_rate; oil_rate = new_oil_rate;
gas_rate = new_gas_rate; gas_rate = new_gas_rate;
water_rate = new_water_rate;
oil_is_limited = new_oil_is_limited; oil_is_limited = new_oil_is_limited;
gas_is_limited = new_gas_is_limited; gas_is_limited = new_gas_is_limited;
water_is_limited = new_water_is_limited;
cur_alq = new_alq; cur_alq = new_alq;
success = true; success = true;
} }
@ -771,7 +907,7 @@ runOptimizeLoop_(bool increase)
while (!state.stop_iteration && (++state.it <= this->max_iterations_)) { while (!state.stop_iteration && (++state.it <= this->max_iterations_)) {
if (!increase && state.checkNegativeOilRate(oil_rate)) break; if (!increase && state.checkNegativeOilRate(oil_rate)) break;
if (state.checkWellRatesViolated(potentials)) 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; if (state.checkAlqOutsideLimits(temp_alq, oil_rate)) break;
std::optional<double> alq_opt; std::optional<double> alq_opt;
std::tie(alq_opt, alq_is_limited) std::tie(alq_opt, alq_is_limited)
@ -786,6 +922,8 @@ runOptimizeLoop_(bool increase)
auto bhp = state.getBhpWithLimit(); auto bhp = state.getBhpWithLimit();
computeWellRates_(bhp, potentials); computeWellRates_(bhp, potentials);
std::tie(new_oil_rate, new_oil_is_limited) = getOilRateWithLimit_(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 (this->debug_abort_if_decrease_and_oil_is_limited_) {
if (oil_is_limited && !increase) { if (oil_is_limited && !increase) {
// if oil is limited we do not want to decrease // 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) = 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 (this->debug_abort_if_increase_and_gas_is_limited_) {
if (gas_is_limited && increase) { if (gas_is_limited && increase) {
// if gas is limited we do not want to increase // if gas is limited we do not want to increase
@ -816,11 +963,14 @@ runOptimizeLoop_(bool increase)
success = true; success = true;
delta_oil = new_oil_rate - oil_rate; delta_oil = new_oil_rate - oil_rate;
delta_gas = new_gas_rate - gas_rate; delta_gas = new_gas_rate - gas_rate;
delta_water = new_water_rate - water_rate;
oil_rate = new_oil_rate; oil_rate = new_oil_rate;
gas_rate = new_gas_rate; gas_rate = new_gas_rate;
water_rate = new_water_rate;
oil_is_limited = new_oil_is_limited; oil_is_limited = new_oil_is_limited;
gas_is_limited = new_gas_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_) { if (state.it > this->max_iterations_) {
warnMaxIterationsExceeded_(); warnMaxIterationsExceeded_();
@ -843,11 +993,11 @@ GasLiftSingleWellGeneric::
runOptimize1_() runOptimize1_()
{ {
std::unique_ptr<GasLiftWellState> state; std::unique_ptr<GasLiftWellState> state;
auto inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_); int inc_count = this->well_state_.gliftGetAlqIncreaseCount(this->well_name_);
auto dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_); int dec_count = this->well_state_.gliftGetAlqDecreaseCount(this->well_name_);
if (dec_count == 0 && inc_count == 0) { if (dec_count == 0 && inc_count == 0) {
state = tryIncreaseLiftGas_(); state = tryIncreaseLiftGas_();
if (!state && !state->alqChanged()) { if (!state || !(state->alqChanged())) {
state = tryDecreaseLiftGas_(); state = tryDecreaseLiftGas_();
} }
} }
@ -1137,7 +1287,7 @@ checkGroupALQrateExceeded(double delta_alq)
bool bool
GasLiftSingleWellGeneric::OptimizeState:: GasLiftSingleWellGeneric::OptimizeState::
checkGroupTargetsViolated(double delta_oil, double delta_gas) checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water)
{ {
const auto &pairs = const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_); this->parent.group_info_.getWellGroups(this->parent.well_name_);
@ -1170,19 +1320,49 @@ checkGroupTargetsViolated(double delta_oil, double delta_gas)
return true; 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; return false;
} }
std::tuple<double,double,double> std::tuple<double,double,double,double>
GasLiftSingleWellGeneric::OptimizeState:: GasLiftSingleWellGeneric::OptimizeState::
reduceALQtoGroupTarget(double alq, reduceALQtoGroupTarget(double alq,
double oil_rate, double oil_rate,
double gas_rate, double gas_rate,
double water_rate,
std::vector<double>& potentials) std::vector<double>& potentials)
{ {
// Note: Currently the checkGroupTargetsViolated only check
// for GRAT and ORAT group controls.
bool stop_this_iteration = true; bool stop_this_iteration = true;
const auto &pairs = const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_); 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)) if (!this->parent.group_state_.has_production_control(groups.first))
continue; continue;
const auto& current_control = this->parent.group_state_.production_control(groups.first); 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; stop_this_iteration = false;
this->parent.displayDebugMessage_("Reducing ALQ to meet groups target before iteration starts."); this->parent.displayDebugMessage_("Reducing ALQ to meet groups target before iteration starts.");
break; break;
@ -1199,6 +1382,7 @@ reduceALQtoGroupTarget(double alq,
double temp_alq = alq; double temp_alq = alq;
double oil_rate_orig = oil_rate; double oil_rate_orig = oil_rate;
double gas_rate_orig = gas_rate; double gas_rate_orig = gas_rate;
double water_rate_orig = water_rate;
while(!stop_this_iteration) { while(!stop_this_iteration) {
temp_alq -= this->parent.increment_; temp_alq -= this->parent.increment_;
if (temp_alq <= 0) break; if (temp_alq <= 0) break;
@ -1208,15 +1392,17 @@ reduceALQtoGroupTarget(double alq,
this->parent.computeWellRates_(bhp_this.first, potentials); this->parent.computeWellRates_(bhp_this.first, potentials);
oil_rate = -potentials[this->parent.oil_pos_]; oil_rate = -potentials[this->parent.oil_pos_];
gas_rate = -potentials[this->parent.gas_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_oil = oil_rate_orig - oil_rate;
double delta_gas = gas_rate_orig - gas_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; break;
} }
alq = temp_alq; alq = temp_alq;
} }
return std::make_tuple(oil_rate, gas_rate, alq); return std::make_tuple(oil_rate, gas_rate, water_rate, alq);
} }
bool bool
GasLiftSingleWellGeneric::OptimizeState:: GasLiftSingleWellGeneric::OptimizeState::
@ -1367,7 +1553,7 @@ getBhpWithLimit()
void void
GasLiftSingleWellGeneric::OptimizeState:: 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 = const auto &pairs =
this->parent.group_info_.getWellGroups(this->parent.well_name_); 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); int idx = this->parent.group_info_.getGroupIdx(group_name);
this->parent.sync_groups_.insert(idx); this->parent.sync_groups_.insert(idx);
this->parent.group_info_.update(group_name, 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 checkAlqOutsideLimits(double alq, double oil_rate);
bool checkEcoGradient(double gradient); bool checkEcoGradient(double gradient);
bool checkGroupALQrateExceeded(double delta_alq); bool checkGroupALQrateExceeded(double delta_alq);
bool checkGroupTargetsViolated(double delta_oil, double delta_gas); bool checkGroupTargetsViolated(double delta_oil, double delta_gas, double delta_water);
std::tuple<double,double,double> std::tuple<double,double,double,double>
reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, std::vector<double> &potentials); reduceALQtoGroupTarget(double alq, double oil_rate, double gas_rate, double water_rate, std::vector<double> &potentials);
bool checkNegativeOilRate(double oil_rate); bool checkNegativeOilRate(double oil_rate);
bool checkThpControl(); bool checkThpControl();
bool checkOilRateExceedsTarget(double oil_rate); bool checkOilRateExceedsTarget(double oil_rate);
@ -137,7 +137,7 @@ protected:
bool computeBhpAtThpLimit(double alq); bool computeBhpAtThpLimit(double alq);
void debugShowIterationInfo(double alq); void debugShowIterationInfo(double alq);
double getBhpWithLimit(); 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);} void warn_(std::string msg) {parent.displayWarning_(msg);}
}; };
@ -162,8 +162,9 @@ protected:
bool computeInitialWellRates_(std::vector<double>& potentials); bool computeInitialWellRates_(std::vector<double>& potentials);
void debugCheckNegativeGradient_(double grad, double alq, double new_alq, void debugCheckNegativeGradient_(double grad, double alq, double new_alq,
double oil_rate, double new_oil_rate, double gas_rate, double oil_rate, double new_oil_rate,
double new_gas_rate, bool increase) const; double gas_rate, double new_gas_rate,
bool increase) const;
void debugShowAlqIncreaseDecreaseCounts_(); void debugShowAlqIncreaseDecreaseCounts_();
@ -178,9 +179,16 @@ protected:
std::pair<double, bool> getBhpWithLimit_(double bhp) const; std::pair<double, bool> getBhpWithLimit_(double bhp) const;
std::pair<double, bool> getGasRateWithLimit_(const std::vector<double>& potentials) 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); getInitialRatesWithLimit_(const std::vector<double>& potentials);
std::pair<double, bool> getOilRateWithLimit_(const std::vector<double>& potentials) const; 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> std::tuple<double,double,bool,bool,double>
increaseALQtoPositiveOilRate_(double alq, increaseALQtoPositiveOilRate_(double alq,
@ -200,10 +208,10 @@ protected:
void logSuccess_(double alq, void logSuccess_(double alq,
const int iteration_idx); const int iteration_idx);
std::tuple<double,double,double,bool,bool> std::tuple<double,double,double, double,bool,bool,bool>
maybeAdjustALQbeforeOptimizeLoop_( maybeAdjustALQbeforeOptimizeLoop_(
bool increase, double alq, double oil_rate, double gas_rate, bool increase, double alq, double oil_rate, double gas_rate, double water_rate,
bool oil_is_limited, bool gas_is_limited, std::vector<double> &potentials); bool oil_is_limited, bool gas_is_limited, bool water_is_limited, std::vector<double> &potentials);
std::tuple<double,double,bool,bool,double> std::tuple<double,double,bool,bool,double>
reduceALQtoOilTarget_(double alq, double oil_rate, double gas_rate, reduceALQtoOilTarget_(double alq, double oil_rate, double gas_rate,
bool oil_is_limited, bool gas_is_limited, std::vector<double> &potentials); bool oil_is_limited, bool gas_is_limited, std::vector<double> &potentials);