Limit the other rates when a rate is limited

This commit is contained in:
Tor Harald Sandve 2024-10-25 08:57:38 +02:00
parent b42537155e
commit 6a30966500
2 changed files with 96 additions and 44 deletions

View File

@ -532,16 +532,21 @@ getProducerWellRates_(const Well* well, int well_index)
const auto controls = well->productionControls(this->summary_state_);
Scalar oil_rate = oil_pot;
if (controls.hasControl(Well::ProducerCMode::ORAT)) {
oil_rate = std::min(static_cast<Scalar>(controls.oil_rate), oil_rate);
}
Scalar water_rate = water_pot;
Scalar gas_rate = gas_pot;
if (controls.hasControl(Well::ProducerCMode::ORAT) && oil_rate > static_cast<Scalar>(controls.oil_rate)) {
water_rate *= (static_cast<Scalar>(controls.oil_rate) / oil_rate);
oil_rate = static_cast<Scalar>(controls.oil_rate);
}
if (controls.hasControl(Well::ProducerCMode::GRAT)) {
gas_rate = std::min(static_cast<Scalar>(controls.gas_rate), gas_rate);
}
Scalar water_rate = water_pot;
if (controls.hasControl(Well::ProducerCMode::WRAT)) {
water_rate = std::min(static_cast<Scalar>(controls.water_rate), water_rate);
if (controls.hasControl(Well::ProducerCMode::WRAT) && water_rate > static_cast<Scalar>(controls.water_rate)) {
oil_rate *= (static_cast<Scalar>(controls.water_rate) / water_rate);
water_rate = static_cast<Scalar>(controls.water_rate);
}
if (controls.hasControl(Well::ProducerCMode::LRAT)) {
Scalar liquid_rate = oil_rate + water_rate;
@ -650,12 +655,16 @@ initializeGroupRatesRecursive_(const Group& group)
group.name(), oil_rate, gas_rate, water_rate, alq);
}
if (oil_target)
oil_rate = std::min(oil_rate, *oil_target);
if (gas_target)
gas_rate = std::min(gas_rate, *gas_target);
if (water_target)
water_rate = std::min(water_rate, *water_target);
if (oil_target && oil_rate > *oil_target) {
water_rate *= (*oil_target/oil_rate);
oil_rate = *oil_target;
}
if (gas_target && gas_rate > *gas_target)
gas_rate = *gas_target;
if (water_target && water_rate > *water_target) {
oil_rate *= (*water_target/water_rate);
water_rate = *water_target;
}
if (liquid_target) {
Scalar liquid_rate = oil_rate + water_rate;
Scalar liquid_rate_limited = *liquid_target;

View File

@ -666,6 +666,13 @@ getRateWithLimit_(Rate rate_type, const BasicRates& rates) const
// for why the rate was limited.
std::optional<Rate> target_type;
Scalar rate2;
if (rate_type == Rate::oil) {
rate2 = getRate_(Rate::water, rates);
} else {
rate2 = getRate_(Rate::oil, rates);
}
if (hasProductionControl_(rate_type)) {
auto target = getProductionTarget_(rate_type);
if (new_rate > target) {
@ -675,42 +682,73 @@ getRateWithLimit_(Rate rate_type, const BasicRates& rates) const
new_rate,
target);
displayDebugMessage_(msg);
rate2 *= target/new_rate;
new_rate = target;
target_type = rate_type;
target_type = rate_type;
}
}
if (((rate_type == Rate::oil) || (rate_type == Rate::water)) && hasProductionControl_(Rate::liquid)) {
Scalar rate2;
if (((rate_type == Rate::oil) || (rate_type == Rate::water))) {
if (rate_type == Rate::oil) {
rate2 = getRate_(Rate::water, rates);
if(hasProductionControl_(Rate::water)) {
auto water_target = getProductionTarget_(Rate::water);
if (rate2 > water_target) {
new_rate *= (water_target / rate2);
target_type = Rate::water;
rate2 = water_target;
const std::string msg = fmt::format("limiting {} rate to {} due to WRAT target: "
"computed WRAT: {}, target WRAT: {}",
GasLiftGroupInfo<Scalar>::rateToString(rate_type),
new_rate,
rate2,
water_target);
displayDebugMessage_(msg);
}
}
} else {
rate2 = getRate_(Rate::oil, rates);
if(hasProductionControl_(Rate::oil)) {
auto oil_target = getProductionTarget_(Rate::oil);
if (rate2 > oil_target) {
new_rate *= (oil_target / rate2);
target_type = Rate::oil;
rate2 = oil_target;
const std::string msg = fmt::format("limiting {} rate to {} due to ORAT target: "
"computed ORAT: {}, target ORAT: {}",
GasLiftGroupInfo<Scalar>::rateToString(rate_type),
new_rate,
rate2,
oil_target);
displayDebugMessage_(msg);
}
}
}
// Note: Since "new_rate" was first updated for ORAT or WRAT, see first "if"
// statement in the method, the rate is limited due to LRAT only if
// it becomes less than the rate limited by a WRAT or ORAT target..
Scalar liq_rate = new_rate + rate2;
auto liq_target = getProductionTarget_(Rate::liquid);
if (liq_rate > liq_target) {
Scalar fraction = new_rate / liq_rate;
// NOTE: since
// fraction * liq_rate = new_rate,
// we must have
// fraction * liq_target < new_rate
// since
// liq_target < liq_rate
// therefore new_rate will become less than it original was and
// limited = true.
new_rate = fraction * liq_target;
target_type = Rate::liquid;
const std::string msg = fmt::format("limiting {} rate to {} due to LRAT target: "
"computed LRAT: {}, target LRAT: {}",
GasLiftGroupInfo<Scalar>::rateToString(rate_type),
new_rate,
liq_rate,
liq_target);
displayDebugMessage_(msg);
if(hasProductionControl_(Rate::liquid)) {
// Note: Since "new_rate" was first updated for ORAT or WRAT, see first "if"
// statement in the method, the rate is limited due to LRAT only if
// it becomes less than the rate limited by a WRAT or ORAT target..
Scalar liq_rate = new_rate + rate2;
auto liq_target = getProductionTarget_(Rate::liquid);
if (liq_rate > liq_target) {
Scalar fraction = new_rate / liq_rate;
// NOTE: since
// fraction * liq_rate = new_rate,
// we must have
// fraction * liq_target < new_rate
// since
// liq_target < liq_rate
// therefore new_rate will become less than it original was and
// limited = true.
new_rate = fraction * liq_target;
target_type = Rate::liquid;
const std::string msg = fmt::format("limiting {} rate to {} due to LRAT target: "
"computed LRAT: {}, target LRAT: {}",
GasLiftGroupInfo<Scalar>::rateToString(rate_type),
new_rate,
liq_rate,
liq_target);
displayDebugMessage_(msg);
}
}
}
// TODO: Also check RESV target?
@ -768,7 +806,7 @@ getLiquidRateWithGroupLimit_(const Scalar new_oil_rate,
= getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate, gr_name_dont_limit);
bool limited = group_name != nullptr;
if (limited) {
Scalar oil_fraction = new_oil_rate / new_liquid_rate;
Scalar oil_fraction = oil_rate / liquid_rate;
Scalar delta_liquid = liquid_rate_limited - liquid_rate;
auto limited_oil_rate = oil_rate + oil_fraction * delta_liquid;
auto limited_water_rate = water_rate + (1.0 - oil_fraction) * delta_liquid;
@ -862,6 +900,7 @@ getInitialRatesWithLimit_() const
auto temp_rates = getLimitedRatesFromRates_(*rates);
BasicRates old_rates = getWellStateRates_();
limited_rates = updateRatesToGroupLimits_(old_rates, temp_rates);
initial_alq = alq;
}
return {limited_rates, initial_alq};
@ -873,9 +912,10 @@ GasLiftSingleWellGeneric<Scalar>::
getLimitedRatesFromRates_(const BasicRates& rates) const
{
auto [oil_rate, oil_limiting_target] = getOilRateWithLimit2_(rates);
bool oil_is_limited = oil_limiting_target.has_value();
auto [gas_rate, gas_is_limited] = getGasRateWithLimit_(rates);
auto [water_rate, water_limiting_target] = getWaterRateWithLimit2_(rates);
bool oil_is_limited = oil_limiting_target.has_value();
bool water_is_limited = water_limiting_target.has_value();
return LimitedRates {oil_rate,
gas_rate,
@ -1447,13 +1487,16 @@ updateRatesToGroupLimits_(const BasicRates& old_rates,
{
LimitedRates new_rates = rates;
auto [new_oil_rate, oil_is_limited] = getOilRateWithGroupLimit_(new_rates.oil, old_rates.oil, gr_name);
auto mod_water_rate = new_rates.water;
if (oil_is_limited) {
new_rates.oil_limiting_target = Rate::oil;
mod_water_rate *= (new_oil_rate / new_rates.oil);
}
auto [new_gas_rate, gas_is_limited] = getGasRateWithGroupLimit_(new_rates.gas, old_rates.gas, gr_name);
auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_(new_rates.water, old_rates.water, gr_name);
auto [new_water_rate, water_is_limited] = getWaterRateWithGroupLimit_(mod_water_rate, old_rates.water, gr_name);
if (water_is_limited) {
new_rates.water_limiting_target = Rate::water;
new_oil_rate *= (new_water_rate / new_rates.water);
}
auto [new_oil_rate2, new_water_rate2, oil_is_limited2, water_is_limited2]
= getLiquidRateWithGroupLimit_(new_oil_rate, old_rates.oil, new_water_rate, old_rates.water, gr_name);