mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
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:
commit
c563f14aff
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user