mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-01 13:29:08 -06:00
Merge pull request #3706 from hakonhagland/glift_it
Extend VFP calculations to two-phase flow.
This commit is contained in:
commit
690b33aaad
@ -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();
|
||||
|
@ -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_;
|
||||
|
@ -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:
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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>::
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user