Refactor some methods in GasLiftSingleWellGeneric.

Refactor getOilRateWithGroupLimit_(), getGasRateWithGroupLimit_(),
getWaterRateWithGroupLimit_(), and getLiquidRateWithGroupLimit_() into
a single generic method called getRateWithGroupLimit_().
This commit is contained in:
Håkon Hægland 2021-12-17 01:52:34 +01:00
parent f77d82a0e9
commit 837f33e679
4 changed files with 171 additions and 118 deletions

View File

@ -84,6 +84,26 @@ gasTarget(const std::string& group_name)
return group_rate.gasTarget();
}
double
GasLiftGroupInfo::
getRate(Rate rate_type, const std::string& group_name)
{
switch (rate_type) {
case Rate::oil:
return oilRate(group_name);
case Rate::gas:
return gasRate(group_name);
case Rate::water:
return waterRate(group_name);
case Rate::liquid:
return oilRate(group_name) + waterRate(group_name);
default:
// Need this to avoid compiler warning : control reaches end of non-void function
throw std::runtime_error("This should not happen");
}
}
std::tuple<double, double, double, double>
GasLiftGroupInfo::
getRates(int group_idx)
@ -93,6 +113,25 @@ getRates(int group_idx)
return std::make_tuple(rates.oilRate(), rates.gasRate(), rates.waterRate(), rates.alq());
}
std::optional<double>
GasLiftGroupInfo::
getTarget(Rate rate_type, const std::string& group_name)
{
switch (rate_type) {
case Rate::oil:
return oilTarget(group_name);
case Rate::gas:
return gasTarget(group_name);
case Rate::water:
return waterTarget(group_name);
case Rate::liquid:
return liquidTarget(group_name);
default:
// Need this to avoid compiler warning : control reaches end of non-void function
throw std::runtime_error("This should not happen");
}
}
std::vector<std::pair<std::string,double>>&
GasLiftGroupInfo::
getWellGroups(const std::string& well_name)
@ -189,6 +228,23 @@ liquidTarget(const std::string &group_name)
return group_rate.liquidTarget();
}
const std::string
GasLiftGroupInfo::
rateToString(Rate rate) {
switch (rate) {
case Rate::oil:
return "oil";
case Rate::gas:
return "gas";
case Rate::water:
return "water";
case Rate::liquid:
return "liquid";
default:
throw std::runtime_error("This should not happen");
}
}
void
GasLiftGroupInfo::
update(

View File

@ -67,6 +67,8 @@ class GasLiftGroupInfo
static const int Oil = BlackoilPhases::Liquid;
static const int Gas = BlackoilPhases::Vapour;
public:
enum class Rate {oil, gas, water, liquid};
using GLiftEclWells = std::map<std::string,std::pair<const Well *,int>>;
GasLiftGroupInfo(
GLiftEclWells& ecl_wells,
@ -84,13 +86,16 @@ public:
double alqRate(const std::string& group_name);
double gasRate(const std::string& group_name);
int getGroupIdx(const std::string& group_name);
double getRate(Rate rate_type, const std::string& group_name);
std::tuple<double,double,double,double> getRates(int group_idx);
std::optional<double> gasTarget(const std::string& group_name);
std::optional<double> getTarget(Rate rate_type, 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);
static const std::string rateToString(Rate rate);
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);

View File

@ -601,140 +601,125 @@ getOilRateWithLimit_(const std::vector<double>& potentials) const
return { new_rate, limited};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getOilRateWithGroupLimit_(const double new_oil_rate, const double oil_rate) const
getOilRateWithGroupLimit_(double new_oil_rate, double oil_rate) const
{
const double delta_oil = new_oil_rate - oil_rate;
if (delta_oil > 0) {
// It is required that the production rate for a given group is
// is less than or equal to its target rate, see assert() below.
// Then it only makes sense to check if the group target is exceeded
// if delta_oil > 0
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
bool limit = false;
double limited_oil_rate = new_oil_rate;
double gr_oil_target, new_gr_oil_rate;
const std::string *group_name = nullptr;
for (const auto& [group_name_temp, efficiency] : pairs) {
auto gr_oil_target_opt = this->group_info_.oilTarget(group_name_temp);
if (gr_oil_target_opt) {
double gr_oil_target_temp = *gr_oil_target_opt;
double gr_oil_rate_temp =
this->group_info_.oilRate(group_name_temp);
assert(gr_oil_rate_temp <= gr_oil_target_temp);
double new_gr_oil_rate_temp = gr_oil_rate_temp + efficiency * delta_oil;
if (new_gr_oil_rate_temp > gr_oil_target_temp) {
double limited_oil_rate_temp =
oil_rate + (gr_oil_target_temp - gr_oil_rate_temp) / efficiency;
if (limited_oil_rate_temp < limited_oil_rate) {
limit = true;
group_name = &group_name_temp;
limited_oil_rate = limited_oil_rate_temp;
gr_oil_target = gr_oil_target_temp;
new_gr_oil_rate = new_gr_oil_rate_temp;
}
}
}
}
if (this->debug_ && limit) {
const std::string msg = fmt::format(
"limiting oil rate from {} to {} to meet group target {} "
"for group {}. Computed group rate was: {}",
new_oil_rate, limited_oil_rate, gr_oil_target,
*group_name, new_gr_oil_rate);
displayDebugMessage_(msg);
return { limited_oil_rate, /*limit=*/true};
}
}
return { new_oil_rate, /*limit=*/false};
[[maybe_unused]] auto [rate, gr_name, efficiency]
= getRateWithGroupLimit_(Rate::oil, new_oil_rate, oil_rate);
bool limited = gr_name != nullptr;
return {rate, limited};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getGasRateWithGroupLimit_(const double new_gas_rate, const double gas_rate) const
getGasRateWithGroupLimit_(double new_gas_rate, 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};
[[maybe_unused]] auto [rate, gr_name, efficiency]
= getRateWithGroupLimit_(Rate::gas, new_gas_rate, gas_rate);
bool limited = gr_name != nullptr;
return {rate, limited};
}
std::pair<double, bool>
GasLiftSingleWellGeneric::
getWaterRateWithGroupLimit_(const double new_water_rate, const double water_rate) const
getWaterRateWithGroupLimit_(double new_water_rate, 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};
[[maybe_unused]] auto [rate, gr_name, efficiency] = getRateWithGroupLimit_(
Rate::water, new_water_rate, water_rate);
bool limited = gr_name != nullptr;
return {rate, limited};
}
std::tuple<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
getLiquidRateWithGroupLimit_(double new_oil_rate, double oil_rate,
double new_water_rate, 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};
}
}
auto liquid_rate = oil_rate + water_rate;
auto new_liquid_rate = new_oil_rate + new_water_rate;
auto [liquid_rate_limited, group_name, efficiency]
= getRateWithGroupLimit_(Rate::liquid, new_liquid_rate, liquid_rate);
bool limited = group_name != nullptr;
if (limited) {
// the oil, gas, and water cases can be handled directly by
// getRateWithGroupLimit_() above. However, for the liquid case
// we must do some postprocessing. I chose to include it here
// instead of cluttering up getRateWithGroupLimit_() with this
// special case.
double delta_water = new_water_rate - water_rate;
double delta_oil = new_oil_rate - oil_rate;
double gr_water_rate = this->group_info_.waterRate(*group_name);
double gr_oil_rate = this->group_info_.oilRate(*group_name);
// NOTE: these rates are too large according to the limited liquid rate
// but it does not matter since we are only using them to calculate
// the fraction of the liquid corresponding to the oil phase
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;
double oil_fraction = new_gr_oil_rate / new_gr_liquid_rate;
double delta_liquid = liquid_rate_limited - liquid_rate;
new_oil_rate = oil_rate + oil_fraction * delta_liquid;
new_water_rate = water_rate + (1.0 - oil_fraction) * delta_liquid;
}
return { new_oil_rate, new_water_rate, /*limit=*/false, /*limit=*/false};
return {new_oil_rate, new_water_rate, limited, limited};
}
std::tuple<double, const std::string*, double>
GasLiftSingleWellGeneric::
getRateWithGroupLimit_(
Rate rate_type, const double new_rate, const double old_rate) const
{
const double delta_rate = new_rate - old_rate;
if (delta_rate > 0) {
// It is required that the production rate for a given group is
// is less than or equal to its target rate, see assert() below.
// Then it only makes sense to check if the group target is exceeded
// if delta_rate > 0
const auto &pairs =
this->group_info_.getWellGroups(this->well_name_);
double limited_rate = new_rate;
double gr_target, new_gr_rate, efficiency;
const std::string *group_name = nullptr;
for (const auto& [group_name_temp, efficiency_temp] : pairs) {
auto gr_target_opt = this->group_info_.getTarget(rate_type, group_name_temp);
if (gr_target_opt) {
double gr_target_temp = *gr_target_opt;
double gr_rate_temp =
this->group_info_.getRate(rate_type, group_name_temp);
assert(gr_rate_temp <= gr_target_temp);
double new_gr_rate_temp = gr_rate_temp + efficiency_temp * delta_rate;
if (new_gr_rate_temp > gr_target_temp) {
double limited_rate_temp =
old_rate + (gr_target_temp - gr_rate_temp) / efficiency_temp;
if (limited_rate_temp < limited_rate) {
group_name = &group_name_temp;
efficiency = efficiency_temp;
limited_rate = limited_rate_temp;
gr_target = gr_target_temp;
new_gr_rate = new_gr_rate_temp;
}
}
}
}
if (this->debug_ && group_name) {
const std::string msg = fmt::format(
"limiting {} rate from {} to {} to meet group target {} "
"for group {}. Computed group rate was: {}",
GasLiftGroupInfo::rateToString(rate_type),
new_rate, limited_rate, gr_target,
*group_name, new_gr_rate);
displayDebugMessage_(msg);
return { limited_rate, group_name, efficiency };
}
}
return { new_rate, /*group_name =*/nullptr, /*efficiency dummy value*/0.0 };
}
std::tuple<double,double,double, bool, bool,bool>
GasLiftSingleWellGeneric::
getInitialRatesWithLimit_(const std::vector<double>& potentials)

View File

@ -57,6 +57,7 @@ protected:
public:
using GLiftSyncGroups = std::set<int>;
using Rate = GasLiftGroupInfo::Rate;
struct GradInfo
{
GradInfo() { }
@ -180,14 +181,20 @@ protected:
std::pair<double, bool> getGasRateWithLimit_(const std::vector<double>& potentials) const;
std::tuple<double,double,double,bool,bool,bool>
getInitialRatesWithLimit_(const std::vector<double>& potentials);
std::tuple<double, const std::string*, double> getRateWithGroupLimit_(
Rate rate_type, const double new_rate, const double old_rate) 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::pair<double, bool> getOilRateWithGroupLimit_(
double new_oil_rate, double oil_rate) const;
std::pair<double, bool> getGasRateWithGroupLimit_(
double new_gas_rate, double gas_rate) const;
std::pair<double, bool> getWaterRateWithGroupLimit_(
double new_water_rate, double water_rate) const;
std::tuple<double,double,bool,bool> getLiquidRateWithGroupLimit_(
double new_oil_rate, double oil_rate,
double new_water_rate, double water_rate) const;
std::tuple<double,double,bool,bool,double>
increaseALQtoPositiveOilRate_(double alq,