mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-11-25 18:50:19 -06:00
Merge pull request #4573 from hakonhagland/glift_grad
Fix bug when recalculating gaslift gradient
This commit is contained in:
commit
734eb76910
@ -55,7 +55,7 @@ namespace Opm
|
||||
const WellInterfaceGeneric &getWell() const override { return well_; }
|
||||
|
||||
private:
|
||||
std::optional<double> computeBhpAtThpLimit_(double alq) const override;
|
||||
std::optional<double> computeBhpAtThpLimit_(double alq, bool debug_ouput=true) const override;
|
||||
BasicRates computeWellRates_(
|
||||
double bhp, bool bhp_is_limited, bool debug_output=true) const override;
|
||||
void setAlqMaxRate_(const GasLiftWell& well);
|
||||
|
@ -85,8 +85,14 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(DeferredLogger& deferred_logg
|
||||
****************************************/
|
||||
// NOTE: Used from GasLiftStage2
|
||||
std::optional<GasLiftSingleWellGeneric::GradInfo>
|
||||
GasLiftSingleWellGeneric::calcIncOrDecGradient(
|
||||
double oil_rate, double gas_rate, double water_rate, double alq, const std::string& gr_name_dont_limit, bool increase) const
|
||||
GasLiftSingleWellGeneric::calcIncOrDecGradient( double oil_rate,
|
||||
double gas_rate,
|
||||
double water_rate,
|
||||
double alq,
|
||||
const std::string& gr_name_dont_limit,
|
||||
bool increase,
|
||||
bool debug_output
|
||||
) const
|
||||
{
|
||||
auto [new_alq_opt, alq_is_limited] = addOrSubtractAlqIncrement_(alq, increase);
|
||||
// TODO: What to do if ALQ is limited and new_alq != alq?
|
||||
@ -99,15 +105,10 @@ GasLiftSingleWellGeneric::calcIncOrDecGradient(
|
||||
if (checkGroupALQrateExceeded(delta_alq, gr_name_dont_limit))
|
||||
return std::nullopt;
|
||||
|
||||
if (auto bhp = computeBhpAtThpLimit_(new_alq)) {
|
||||
if (auto bhp = computeBhpAtThpLimit_(new_alq, debug_output)) {
|
||||
auto [new_bhp, bhp_is_limited] = getBhpWithLimit_(*bhp);
|
||||
// TODO: What to do if BHP is limited?
|
||||
auto rates = computeWellRates_(new_bhp, bhp_is_limited);
|
||||
// double new_oil_rate, new_gas_rate, new_water_rate;
|
||||
// bool oil_is_limited, gas_is_limited, water_is_limited;
|
||||
// std::tie(new_oil_rate, oil_is_limited) = getOilRateWithLimit_(rates);
|
||||
// std::tie(new_gas_rate, gas_is_limited) = getGasRateWithLimit_(rates);
|
||||
// std::tie(new_water_rate, water_is_limited) = getWaterRateWithLimit_(rates);
|
||||
auto rates = computeWellRates_(new_bhp, bhp_is_limited, debug_output);
|
||||
const auto ratesLimited = getLimitedRatesFromRates_(rates);
|
||||
BasicRates oldrates = {oil_rate, gas_rate, water_rate, false};
|
||||
const auto new_rates = updateRatesToGroupLimits_(oldrates, ratesLimited, gr_name_dont_limit);
|
||||
@ -288,7 +289,7 @@ computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_() const
|
||||
auto alq = this->orig_alq_;
|
||||
double new_alq = alq;
|
||||
std::optional<double> bhp;
|
||||
while (alq <= (this->max_alq_ + this->increment_)) {
|
||||
while ((alq < this->max_alq_) || checkALQequal_(alq, this->max_alq_)) {
|
||||
if (bhp = computeBhpAtThpLimit_(alq); bhp) {
|
||||
new_alq = alq;
|
||||
break;
|
||||
@ -321,7 +322,8 @@ GasLiftSingleWellGeneric::computeInitialWellRates_() const
|
||||
rates->water);
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
displayDebugMessage_("Aborting optimization.");
|
||||
}
|
||||
return {rates, initial_alq};
|
||||
@ -1531,10 +1533,10 @@ GasLiftSingleWellGeneric::OptimizeState::checkAlqOutsideLimits(double alq, [[may
|
||||
}
|
||||
} else { // we are decreasing lift gas
|
||||
if (alq == 0) {
|
||||
ss << "ALQ is zero, cannot decrease further. Stopping iteration.";
|
||||
ss << "ALQ is zero, cannot decrease further. Stopping iteration. ";
|
||||
result = true;
|
||||
} else if (alq < 0) {
|
||||
ss << "Negative ALQ: " << alq << ". Stopping iteration.";
|
||||
ss << "Negative ALQ: " << alq << ". Stopping iteration. ";
|
||||
result = true;
|
||||
}
|
||||
// NOTE: A negative min_alq_ means: allocate at least enough lift gas
|
||||
@ -1593,7 +1595,7 @@ GasLiftSingleWellGeneric::checkGroupALQrateExceeded(double delta_alq, const std:
|
||||
const auto& pairs = group_info_.getWellGroups(well_name_);
|
||||
for (const auto& [group_name, efficiency] : pairs) {
|
||||
// in stage 2 we don't want to limit the rate to the group
|
||||
// target we are trying to redistribute the gaslift within
|
||||
// target we are trying to redistribute the gaslift within
|
||||
if (gr_name_dont_limit == group_name)
|
||||
continue;
|
||||
auto max_alq_opt = group_info_.maxAlq(group_name);
|
||||
|
@ -95,9 +95,11 @@ public:
|
||||
|
||||
std::optional<GradInfo> calcIncOrDecGradient(double oil_rate, double gas_rate,
|
||||
double water_rate,
|
||||
double alq,
|
||||
double alq,
|
||||
const std::string& gr_name_dont_limit,
|
||||
bool increase) const;
|
||||
bool increase,
|
||||
bool debug_output = true
|
||||
) const;
|
||||
|
||||
std::unique_ptr<GasLiftWellState> runOptimize(const int iteration_idx);
|
||||
|
||||
@ -253,11 +255,11 @@ protected:
|
||||
const BasicRates& rates, const BasicRates& new_rates) const;
|
||||
bool checkInitialALQmodified_(double alq, double initial_alq) const;
|
||||
virtual bool checkThpControl_() const = 0;
|
||||
virtual std::optional<double> computeBhpAtThpLimit_(double alq) const = 0;
|
||||
virtual std::optional<double> computeBhpAtThpLimit_(double alq, bool debug_output = true) const = 0;
|
||||
std::pair<std::optional<double>,double> computeConvergedBhpAtThpLimitByMaybeIncreasingALQ_() const;
|
||||
std::pair<std::optional<BasicRates>,double> computeInitialWellRates_() const;
|
||||
std::optional<LimitedRates> computeLimitedWellRatesWithALQ_(double alq) const;
|
||||
virtual BasicRates computeWellRates_(double bhp, bool bhp_is_limited, bool debug_output = true) const = 0;
|
||||
virtual BasicRates computeWellRates_(double bhp, bool bhp_is_limited, bool debug_output = true) const = 0;
|
||||
std::optional<BasicRates> computeWellRatesWithALQ_(double alq) const;
|
||||
void debugCheckNegativeGradient_(double grad, double alq, double new_alq,
|
||||
double oil_rate, double new_oil_rate,
|
||||
|
@ -128,7 +128,7 @@ computeWellRates_( double bhp, bool bhp_is_limited, bool debug_output ) const
|
||||
template<typename TypeTag>
|
||||
std::optional<double>
|
||||
GasLiftSingleWell<TypeTag>::
|
||||
computeBhpAtThpLimit_(double alq) const
|
||||
computeBhpAtThpLimit_(double alq, bool debug_output) const
|
||||
{
|
||||
auto bhp_at_thp_limit = this->well_.computeBhpAtThpLimitProdWithAlq(
|
||||
this->ebos_simulator_,
|
||||
@ -137,11 +137,14 @@ computeBhpAtThpLimit_(double alq) const
|
||||
this->deferred_logger_);
|
||||
if (bhp_at_thp_limit) {
|
||||
if (*bhp_at_thp_limit < this->controls_.bhp_limit) {
|
||||
const std::string msg = fmt::format(
|
||||
"Computed bhp ({}) from thp limit is below bhp limit ({}), (ALQ = {})."
|
||||
" Using bhp limit instead",
|
||||
*bhp_at_thp_limit, this->controls_.bhp_limit, alq);
|
||||
displayDebugMessage_(msg);
|
||||
if (debug_output && this->debug) {
|
||||
const std::string msg = fmt::format(
|
||||
"Computed bhp ({}) from thp limit is below bhp limit ({}), (ALQ = {})."
|
||||
" Using bhp limit instead",
|
||||
*bhp_at_thp_limit, this->controls_.bhp_limit, alq
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
bhp_at_thp_limit = this->controls_.bhp_limit;
|
||||
}
|
||||
//bhp_at_thp_limit = std::max(*bhp_at_thp_limit, this->controls_.bhp_limit);
|
||||
|
@ -96,6 +96,8 @@ runOptimize()
|
||||
// Update GasLiftWellState and WellState for "well_name" to the
|
||||
// new ALQ value and related data (the data has already been computed and
|
||||
// saved in "grad_map")
|
||||
// INPUT: grad_map : map of incremental (if "add" is true) or decremental
|
||||
// (if "add" is false) GradInfo structs for each well name.
|
||||
void
|
||||
GasLiftStage2::
|
||||
addOrRemoveALQincrement_(GradMap &grad_map, const std::string& well_name, bool add)
|
||||
@ -141,35 +143,35 @@ calcIncOrDecGrad_(
|
||||
// only applies to wells in the well_state_map (i.e. wells on this rank)
|
||||
if(this->well_state_map_.count(well_name) == 0)
|
||||
return std::nullopt;
|
||||
if (this->debug) {
|
||||
const std::string msg = fmt::format("well {} : calculating {} gradient..",
|
||||
well_name, (increase ? "incremental" : "decremental"));
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
GasLiftWellState &state = *(this->well_state_map_.at(well_name).get());
|
||||
if (checkRateAlreadyLimited_(state, increase)) {
|
||||
/*
|
||||
const std::string msg = fmt::format(
|
||||
"well {} : not able to obtain {} gradient",
|
||||
well_name,
|
||||
(increase ? "incremental" : "decremental")
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
*/
|
||||
if (checkRateAlreadyLimited_(well_name, state, increase)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
else {
|
||||
auto [oil_rate, gas_rate] = state.getRates();
|
||||
auto alq = state.alq();
|
||||
auto grad = gs_well.calcIncOrDecGradient(oil_rate, gas_rate, state.waterRate(), alq, gr_name_dont_limit, increase);
|
||||
if (grad) {
|
||||
const std::string msg = fmt::format(
|
||||
"well {} : adding {} gradient = {}",
|
||||
well_name,
|
||||
(increase ? "incremental" : "decremental"),
|
||||
grad->grad
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
auto grad = gs_well.calcIncOrDecGradient(
|
||||
oil_rate, gas_rate, state.waterRate(), alq, gr_name_dont_limit, increase, /*debug_output=*/false);
|
||||
if (this->debug) {
|
||||
if (grad) {
|
||||
const std::string msg = fmt::format(
|
||||
"well {} : alq = {} : adding {} gradient = {}",
|
||||
well_name,
|
||||
alq,
|
||||
(increase ? "incremental" : "decremental"),
|
||||
grad->grad
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
else {
|
||||
const std::string msg = fmt::format(
|
||||
"well {} : alq = {} : failed to compute {} gradient",
|
||||
well_name,
|
||||
alq,
|
||||
(increase ? "incremental" : "decremental")
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
}
|
||||
return grad;
|
||||
}
|
||||
@ -177,7 +179,7 @@ calcIncOrDecGrad_(
|
||||
|
||||
bool
|
||||
GasLiftStage2::
|
||||
checkRateAlreadyLimited_(GasLiftWellState &state, bool increase)
|
||||
checkRateAlreadyLimited_(const std::string& well_name, GasLiftWellState &state, bool increase)
|
||||
{
|
||||
auto current_increase = state.increase();
|
||||
bool do_check = false;
|
||||
@ -197,10 +199,12 @@ checkRateAlreadyLimited_(GasLiftWellState &state, bool increase)
|
||||
if (do_check) {
|
||||
if (state.gasIsLimited() || state.oilIsLimited() || state.alqIsLimited() || state.waterIsLimited()) {
|
||||
const std::string msg = fmt::format(
|
||||
"{} gradient : skipping since {} was limited in previous step",
|
||||
"Well {} : alq = {} : skipping {} gradient since {} was limited in previous step",
|
||||
well_name,
|
||||
state.alq(),
|
||||
(increase ? "incremental" : "decremental"),
|
||||
(state.oilIsLimited() ? "oil" :
|
||||
(state.gasIsLimited() ? "gas" : "alq")));
|
||||
(state.oilIsLimited() ? "oil" : (state.gasIsLimited() ? "gas" : "alq"))
|
||||
);
|
||||
displayDebugMessage_(msg);
|
||||
return true;
|
||||
}
|
||||
@ -405,14 +409,12 @@ optimizeGroup_(const Group &group)
|
||||
{
|
||||
const auto& group_name = group.name();
|
||||
const auto prod_control = this->group_state_.production_control(group_name);
|
||||
//if (group.has_control(Group::ProductionCMode::ORAT) || group.has_control(Group::ProductionCMode::LRAT)
|
||||
// || max_glift || max_total_gas)
|
||||
// NOTE: it only makes sense to try to optimize the distribution of the gaslift if the amount
|
||||
// of gaslift is constrained either by the maximum allowed gaslift or total gas
|
||||
// or the group is under individual control
|
||||
if ((prod_control != Group::ProductionCMode::NONE) && (prod_control != Group::ProductionCMode::FLD))
|
||||
{
|
||||
displayDebugMessage_("optimizing", group_name);
|
||||
if (this->debug) {
|
||||
const std::string msg = fmt::format("optimizing (control = {})", Group::ProductionCMode2String(prod_control));
|
||||
displayDebugMessage_(msg, group_name);
|
||||
}
|
||||
auto wells = getGroupGliftWells_(group);
|
||||
std::vector<GradPair> inc_grads;
|
||||
std::vector<GradPair> dec_grads;
|
||||
@ -420,7 +422,10 @@ optimizeGroup_(const Group &group)
|
||||
removeSurplusALQ_(group, inc_grads, dec_grads);
|
||||
}
|
||||
else {
|
||||
displayDebugMessage_("skipping", group_name);
|
||||
if (this->debug) {
|
||||
const std::string msg = fmt::format("skipping (control = {})", Group::ProductionCMode2String(prod_control));
|
||||
displayDebugMessage_(msg, group_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,12 +446,12 @@ optimizeGroupsRecursive_(const Group &group)
|
||||
void
|
||||
GasLiftStage2::
|
||||
recalculateGradientAndUpdateData_(
|
||||
GradPairItr &grad_itr, const std::string& gr_name_dont_limit, bool increase,
|
||||
GradPairItr &grad_itr, const std::string& gr_name_dont_limit, bool increase,
|
||||
|
||||
//incremental and decremental gradients, if 'grads' are incremental, then
|
||||
// 'other_grads' are decremental, or conversely, if 'grads' are decremental, then
|
||||
// 'other_grads' are incremental
|
||||
std::vector<GradPair> &grads, std::vector<GradPair> &other_grads)
|
||||
//incremental and decremental gradients, if 'grads' are incremental, then
|
||||
// 'other_grads' are decremental, or conversely, if 'grads' are decremental, then
|
||||
// 'other_grads' are incremental
|
||||
std::vector<GradPair> &grads, std::vector<GradPair> &other_grads)
|
||||
{
|
||||
// NOTE: We make a copy of the name string instead of taking a reference
|
||||
// since we may have to erase grad_itr (in the "else" condition below)
|
||||
@ -457,26 +462,44 @@ recalculateGradientAndUpdateData_(
|
||||
// the grads and other grads are synchronized later
|
||||
if(this->stage1_wells_.count(name) > 0) {
|
||||
GasLiftSingleWell &gs_well = *(this->stage1_wells_.at(name).get());
|
||||
auto grad = calcIncOrDecGrad_(name, gs_well, gr_name_dont_limit, increase);
|
||||
if (grad) {
|
||||
grad_itr->second = grad->grad;
|
||||
old_grad = updateGrad_(name, *grad, increase);
|
||||
{
|
||||
auto grad = calcIncOrDecGrad_(name, gs_well, gr_name_dont_limit, increase);
|
||||
if (grad) {
|
||||
grad_itr->second = grad->grad;
|
||||
old_grad = updateGrad_(name, *grad, increase);
|
||||
}
|
||||
else {
|
||||
grads.erase(grad_itr); // NOTE: this invalidates grad_itr
|
||||
old_grad = deleteGrad_(name, increase);
|
||||
}
|
||||
}
|
||||
else {
|
||||
grads.erase(grad_itr); // NOTE: this invalidates grad_itr
|
||||
old_grad = deleteGrad_(name, increase);
|
||||
// If the old incremental/decremental gradient was defined, it becomes the new
|
||||
// decremental/incremental gradient
|
||||
if (old_grad) {
|
||||
// NOTE: Either creates a new item or reassigns
|
||||
// The old incremental gradient becomes the new decremental gradient
|
||||
// or the old decremental gradient becomes the new incremental gradient
|
||||
// NOTE: The gradient itself (old_grad.grad) will be equal to the new decremental
|
||||
// gradient, but the other fields in old_grad cannot be used as they refer to
|
||||
// the incremental gradient. E.g. old_grad.alq is the alq after an increase in alq,
|
||||
// not a decrease, so we need to recalculate the decremental values here..
|
||||
auto grad = calcIncOrDecGrad_(name, gs_well, gr_name_dont_limit, !increase);
|
||||
if (grad) {
|
||||
updateGrad_(name, *grad, !increase);
|
||||
// NOTE: This may invalidate any iterator into 'other_grads' since
|
||||
// updateGradVector_() will do a push_back() if 'name' is not found..
|
||||
updateGradVector_(name, other_grads, grad->grad);
|
||||
}
|
||||
else {
|
||||
for (auto it = other_grads.begin(); it != other_grads.end(); it++) {
|
||||
if (it->first == name) {
|
||||
other_grads.erase(it);
|
||||
deleteGrad_(name, !increase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (old_grad) {
|
||||
// NOTE: Either creates a new item or reassigns
|
||||
// The old incremental gradient becomes the new decremental gradient
|
||||
// or the old decremental gradient becomes the new incremental gradient
|
||||
updateGrad_(name, *old_grad, !increase);
|
||||
// NOTE: This may invalidate any iterator into 'other_grads' since
|
||||
// updateGradVector_() will do a push_back() if 'name' is not found..
|
||||
updateGradVector_(name, other_grads, old_grad->grad);
|
||||
}
|
||||
}
|
||||
|
||||
// redistributeALQ_() :
|
||||
@ -608,7 +631,7 @@ removeSurplusALQ_(const Group &group,
|
||||
if (this->debug) {
|
||||
std::string max_glift_str = "unlimited";
|
||||
if (max_glift) max_glift_str = fmt::format("{}", *max_glift);
|
||||
const std::string msg = fmt::format("Starting iteration for group: {}. "
|
||||
const std::string msg = fmt::format("Starting remove surplus iteration for group: {}. "
|
||||
"oil_rate = {}, oil_target = {}, gas_rate = {}, gas_target = {}, "
|
||||
"water_rate = {}, liquid_target = {}, alq = {}, max_alq = {}",
|
||||
group.name(), oil_rate, controls.oil_target,
|
||||
@ -798,7 +821,7 @@ void
|
||||
GasLiftStage2::OptimizeState::
|
||||
debugShowIterationInfo()
|
||||
{
|
||||
const std::string msg = fmt::format("iteration {}", this->it);
|
||||
const std::string msg = fmt::format("redistribute ALQ iteration {}", this->it);
|
||||
displayDebugMessage_(msg);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ protected:
|
||||
GradMap& grad_map, const std::string& well_name, bool add);
|
||||
std::optional<GradInfo> calcIncOrDecGrad_(
|
||||
const std::string name, const GasLiftSingleWell& gs_well, const std::string& gr_name_dont_limit, bool increase);
|
||||
bool checkRateAlreadyLimited_(GasLiftWellState& state, bool increase);
|
||||
bool checkRateAlreadyLimited_(const std::string& well_name, GasLiftWellState& state, bool increase);
|
||||
GradInfo deleteDecGradItem_(const std::string& name);
|
||||
GradInfo deleteIncGradItem_(const std::string& name);
|
||||
GradInfo deleteGrad_(const std::string& name, bool increase);
|
||||
|
Loading…
Reference in New Issue
Block a user