Merge pull request #3706 from hakonhagland/glift_it

Extend VFP calculations to two-phase flow.
This commit is contained in:
Tor Harald Sandve 2022-03-08 12:59:22 +01:00 committed by GitHub
commit 690b33aaad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 106 additions and 27 deletions

View File

@ -291,21 +291,24 @@ checkDoGasLiftOptimization_(const std::string &well_name)
"further optimization skipped due to oscillation in ALQ", well_name);
return false;
}
auto itr = this->ecl_wells_.find(well_name);
if (itr == this->ecl_wells_.end()) {
// well_name is not present in the well_model's well container
displayDebugMessage_("Could find well ecl_wells. Skipping.", well_name);
return false;
}
const Well *well = (itr->second).first;
//assert(well); // Should never be nullptr
if (well->isInjector()) {
displayDebugMessage_("Injector well. Skipping", well_name);
return false;
}
if (this->optimize_only_thp_wells_) {
auto itr = this->ecl_wells_.find(well_name);
if (itr != this->ecl_wells_.end()) {
//const Well *well = (itr->second).first;
//assert(well); // Should never be nullptr
const int well_index = (itr->second).second;
const auto& ws = this->well_state_.well(well_index);
const Well::ProducerCMode& control_mode = ws.production_cmode;
if (control_mode != Well::ProducerCMode::THP ) {
displayDebugMessage_("Not THP control. Skipping.", well_name);
return false;
}
}
else {
// well_name is not present in the well_model's well container
const int well_index = (itr->second).second;
const auto& ws = this->well_state_.well(well_index);
const Well::ProducerCMode& control_mode = ws.production_cmode;
if (control_mode != Well::ProducerCMode::THP ) {
displayDebugMessage_("Not THP control. Skipping.", well_name);
return false;
}
}
@ -314,7 +317,7 @@ checkDoGasLiftOptimization_(const std::string &well_name)
}
if (!this->glo_.has_well(well_name)) {
displayDebugMessage_(
"Gas Lift not activated: WLIFTOPT is probably missing", well_name);
"Gas Lift not activated: WLIFTOPT is probably missing. Skipping.", well_name);
return false;
}
auto increment = this->glo_.gaslift_increment();

View File

@ -59,6 +59,7 @@ namespace Opm
BasicRates computeWellRates_(
double bhp, bool bhp_is_limited, bool debug_output=true) const override;
void setAlqMaxRate_(const GasLiftOpt::Well& well);
void setupPhaseVariables_();
const Simulator &ebos_simulator_;
const WellInterface<TypeTag> &well_;

View File

@ -58,7 +58,6 @@ GasLiftSingleWellGeneric::GasLiftSingleWellGeneric(
, phase_usage_{phase_usage}
, sync_groups_{sync_groups}
, controls_{ecl_well_.productionControls(summary_state_)}
, num_phases_{well_state_.numPhases()}
, debug_limit_increase_decrease_{false}
{
this->well_name_ = ecl_well_.name();
@ -388,6 +387,8 @@ debugShowBhpAlqTable_()
const std::string fmt_fmt2 {"{:>12.5g} {:>12.5g} {:>12.5g} {:>12.5g}"};
const std::string header = fmt::format(fmt_fmt1, "ALQ", "BHP", "oil", "gas");
displayDebugMessage_(header);
auto max_it = 50;
auto it = 1;
while (alq <= (this->max_alq_+this->increment_)) {
auto bhp_at_thp_limit = computeBhpAtThpLimit_(alq);
if (!bhp_at_thp_limit) {
@ -403,6 +404,13 @@ debugShowBhpAlqTable_()
displayDebugMessage_(msg);
}
alq += this->increment_;
if (it > max_it) {
const std::string msg = fmt::format(
"ALQ table : max iterations {} reached. Stopping iteration.", max_it);
displayDebugMessage_(msg);
break;
}
it++;
}
}
@ -1161,7 +1169,7 @@ runOptimizeLoop_(bool increase)
std::unique_ptr<GasLiftWellState> ret_value; // nullptr initially
auto rates = getInitialRatesWithLimit_();
if (!rates) return ret_value;
//if (this->debug) debugShowBhpAlqTable_();
// if (this->debug) debugShowBhpAlqTable_();
if (this->debug) debugShowAlqIncreaseDecreaseCounts_();
if (this->debug) debugShowTargets_();
bool success = false; // did we succeed to increase alq?
@ -1440,6 +1448,7 @@ useFixedAlq_(const GasLiftOpt::Well& well)
return false;
}
else {
displayDebugMessage_("WLIFTOPT item2 = NO. Skipping optimization.");
// auto& max_alq_optional = well.max_rate();
// if (max_alq_optional) {
// According to WLIFTOPT, item 3:

View File

@ -51,9 +51,10 @@ class GroupState;
class GasLiftSingleWellGeneric : public GasLiftCommon
{
protected:
static const int Water = BlackoilPhases::Aqua;
static const int Oil = BlackoilPhases::Liquid;
static const int Gas = BlackoilPhases::Vapour;
static constexpr int Water = BlackoilPhases::Aqua;
static constexpr int Oil = BlackoilPhases::Liquid;
static constexpr int Gas = BlackoilPhases::Vapour;
static constexpr int NUM_PHASES = 3;
static constexpr double ALQ_EPSILON = 1e-8;
public:
@ -347,7 +348,6 @@ protected:
int water_pos_;
int max_iterations_;
int num_phases_;
std::string well_name_;

View File

@ -59,10 +59,7 @@ GasLiftSingleWell(const WellInterface<TypeTag> &well,
this->optimize_ = true;
}
const auto& pu = well_.phaseUsage();
this->oil_pos_ = pu.phase_pos[Oil];
this->gas_pos_ = pu.phase_pos[Gas];
this->water_pos_ = pu.phase_pos[Water];
setupPhaseVariables_();
// get the alq value used for this well for the previous iteration (a
// nonlinear iteration in assemble() in BlackoilWellModel).
// If gas lift optimization has not been applied to this well yet, the
@ -102,7 +99,7 @@ GasLiftSingleWellGeneric::BasicRates
GasLiftSingleWell<TypeTag>::
computeWellRates_( double bhp, bool bhp_is_limited, bool debug_output ) const
{
std::vector<double> potentials(this->num_phases_, 0.0);
std::vector<double> potentials(NUM_PHASES, 0.0);
this->well_.computeWellRatesWithBhp(
this->ebos_simulator_, bhp, potentials, this->deferred_logger_);
if (debug_output) {
@ -152,6 +149,41 @@ computeBhpAtThpLimit_(double alq) const
return bhp_at_thp_limit;
}
template<typename TypeTag>
void
GasLiftSingleWell<TypeTag>::
setupPhaseVariables_()
{
const auto& pu = this->phase_usage_;
bool num_phases_ok = (pu.num_phases == 3);
if (pu.num_phases == 2) {
// NOTE: We support two-phase oil-water flow, by setting the gas flow rate
// to zero. This is done by initializing the potential vector to zero:
//
// std::vector<double> potentials(NUM_PHASES, 0.0);
//
// see e.g. runOptimizeLoop_() in GasLiftSingleWellGeneric.cpp
// In addition the VFP calculations, e.g. to calculate BHP from THP
// has been adapted to the two-phase oil-water case, see the comment
// in WellInterfaceGeneric.cpp for the method adaptRatesForVFP() for
// more information.
if ( pu.phase_used[BlackoilPhases::Aqua] == 1
&& pu.phase_used[BlackoilPhases::Liquid] == 1
&& pu.phase_used[BlackoilPhases::Vapour] == 0)
{
num_phases_ok = true; // two-phase oil-water is also supported
}
else {
throw std::logic_error("Two-phase gas lift optimization only supported"
" for oil and water");
}
}
assert(num_phases_ok);
this->oil_pos_ = pu.phase_pos[Oil];
this->gas_pos_ = pu.phase_pos[Gas];
this->water_pos_ = pu.phase_pos[Water];
}
template<typename TypeTag>
void
GasLiftSingleWell<TypeTag>::

View File

@ -419,7 +419,12 @@ getWellRates_(const WellInterfaceGeneric &well)
const auto& ws = this->well_state_.well(well_index);
const auto& pu = well.phaseUsage();
auto oil_rate = ws.well_potentials[pu.phase_pos[Oil]];
auto gas_rate = ws.well_potentials[pu.phase_pos[Gas]];
double gas_rate = 0.0;
// See comment for setupPhaseVariables_() in GasLiftSingleWell_impl.hpp
// about the two-phase oil-water case.
if (pu.phase_used[BlackoilPhases::Vapour]) {
gas_rate = ws.well_potentials[pu.phase_pos[Gas]];
}
return {oil_rate, gas_rate};
}

View File

@ -1053,6 +1053,7 @@ namespace Opm
std::vector<double> well_rates_bhp_limit;
computeWellRatesWithBhp(ebos_simulator, bhp_limit, well_rates_bhp_limit, deferred_logger);
this->adaptRatesForVFP(well_rates_bhp_limit);
const double thp = this->calculateThpFromBhp(well_state, well_rates_bhp_limit, bhp_limit, deferred_logger);
const double thp_limit = this->getTHPConstraint(summaryState);
if ( (this->isProducer() && thp < thp_limit) || (this->isInjector() && thp > thp_limit) ) {
@ -2317,6 +2318,7 @@ namespace Opm
// approximation.
std::vector<double> rates(3);
computeWellRatesWithBhp(ebos_simulator, bhp, rates, deferred_logger);
this->adaptRatesForVFP(rates);
return rates;
};

View File

@ -100,6 +100,30 @@ WellInterfaceGeneric::WellInterfaceGeneric(const Well& well,
well_control_log_.clear();
}
// Currently the VFP calculations requires three-phase input data, see
// the documentation for keyword VFPPROD and its implementation in
// VFPProdProperties.cpp. However, by setting the gas flow rate to a dummy
// value in VFPPROD record 5 (GFR values) and supplying a dummy input value
// for the gas rate to the methods in VFPProdProperties.cpp, we can extend
// the VFP calculations to the two-phase oil-water case.
void WellInterfaceGeneric::adaptRatesForVFP(std::vector<double>& rates) const
{
const auto& pu = this->phaseUsage();
if (pu.num_phases == 2) {
if ( pu.phase_used[BlackoilPhases::Aqua] == 1
&& pu.phase_used[BlackoilPhases::Liquid] == 1
&& pu.phase_used[BlackoilPhases::Vapour] == 0)
{
assert(rates.size() == 2);
rates.push_back(0.0); // set gas rate to zero
}
else {
throw std::logic_error("Two-phase VFP calculation only "
"supported for oil and water");
}
}
}
const std::vector<PerforationData>& WellInterfaceGeneric::perforationData() const
{
return *perf_data_;

View File

@ -78,6 +78,8 @@ public:
/// Index of well in the wells struct and wellState
int indexOfWell() const;
void adaptRatesForVFP(std::vector<double>& rates) const;
const Well& wellEcl() const;
const PhaseUsage& phaseUsage() const;

View File

@ -900,6 +900,7 @@ namespace Opm
case Well::ProducerCMode::THP:
{
auto rates = ws.surface_rates;
this->adaptRatesForVFP(rates);
double bhp = this->calculateBhpFromThp(well_state, rates, well, summaryState, this->getRefDensity(), deferred_logger);
ws.bhp = bhp;