Add support for explicit guiderate for injection groups

With this commit the guiderate logic used for the production groups is also used for injectors
This allows for setting guiderates explicit at different group levels
Only RATE, NETV and VOID guiderate type is suppored.
This commit is contained in:
Tor Harald Sandve 2021-03-10 14:26:04 +01:00
parent 8adea8c68a
commit f4ac7f555b
8 changed files with 518 additions and 459 deletions

View File

@ -260,16 +260,24 @@ public:
(*this)(d);
};
auto keyHandle = [&](auto& d)
{
if constexpr (is_pair<Key>::value)
pair(d);
else
(*this)(d);
};
if (m_op == Operation::PACKSIZE) {
m_packSize += Mpi::packSize(data.size(), m_comm);
for (auto& it : data) {
m_packSize += Mpi::packSize(it.first, m_comm);
keyHandle(it.first);
handle(it.second);
}
} else if (m_op == Operation::PACK) {
Mpi::pack(data.size(), m_buffer, m_position, m_comm);
for (auto& it : data) {
Mpi::pack(it.first, m_buffer, m_position, m_comm);
keyHandle(it.first);
handle(it.second);
}
} else if (m_op == Operation::UNPACK) {
@ -277,7 +285,7 @@ public:
Mpi::unpack(size, m_buffer, m_position, m_comm);
for (size_t i = 0; i < size; ++i) {
Key key;
Mpi::unpack(key, m_buffer, m_position, m_comm);
keyHandle(key);
Data entry;
handle(entry);
data.insert(std::make_pair(key, entry));

View File

@ -501,6 +501,7 @@ namespace Opm {
void assignGroupControl(const Group& group, data::GroupData& gdata) const;
data::GuideRateValue getGuideRateValues(const Well& well) const;
data::GuideRateValue getGuideRateValues(const Group& group) const;
data::GuideRateValue getGuideRateInjectionGroupValues(const Group& group) const;
void getGuideRateValues(const GuideRate::RateVector& qs,
const bool is_inj,
const std::string& wgname,

View File

@ -1319,6 +1319,7 @@ namespace Opm {
well_state_nupcol_ = well_state_;
}
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
// the group target reduction rates needs to be update since wells may have swicthed to/from GRUP control
// Currently the group target reduction does not honor NUPCOL. TODO: is that true?
std::vector<double> groupTargetReduction(numPhases(), 0.0);
@ -1326,13 +1327,13 @@ namespace Opm {
std::vector<double> groupTargetReductionInj(numPhases(), 0.0);
WellGroupHelpers::updateGroupTargetReduction(fieldGroup, schedule(), reportStepIdx, /*isInjector*/ true, phase_usage_, *guideRate_, well_state_nupcol_, well_state_, groupTargetReductionInj);
// the guiderate update should not be part of this function
// remove in seperate PR since it affects existing functionality
const double simulationTime = ebosSimulator_.time();
std::vector<double> pot(numPhases(), 0.0);
WellGroupHelpers::updateGuideRateForGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, /*isInjector*/ false, well_state_, comm, guideRate_.get(), pot);
std::vector<double> potInj(numPhases(), 0.0);
WellGroupHelpers::updateGuideRateForGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, /*isInjector*/ true, well_state_, comm, guideRate_.get(), potInj);
WellGroupHelpers::updateGuideRateForProductionGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get(), pot);
WellGroupHelpers::updateGuideRatesForInjectionGroups(fieldGroup, schedule(), summaryState, phase_usage_, reportStepIdx, well_state_, guideRate_.get());
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
WellGroupHelpers::updateREINForGroups(fieldGroup, schedule(), reportStepIdx, phase_usage_, summaryState, well_state_nupcol_, well_state_);
WellGroupHelpers::updateVREPForGroups(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
@ -2830,7 +2831,7 @@ namespace Opm {
for (const auto& wname : sched.wellNames(reportStepIdx)) {
if (! (this->well_state_.hasWellRates(wname) &&
this->guideRate_->has(wname)))
this->guideRate_->hasProductionGroupOrWell(wname)))
{
continue;
}
@ -2867,10 +2868,15 @@ namespace Opm {
const auto& gname = up[start + gi];
const auto& group = sched.getGroup(gname, reportStepIdx);
if (this->guideRate_->has(gname)) {
if (this->guideRate_->hasProductionGroupOrWell(gname)) {
gr[gname].production = this->getGuideRateValues(group);
}
if (this->guideRate_->hasInjectionGroup(::Opm::Phase::WATER, gname)
|| this->guideRate_->hasInjectionGroup(::Opm::Phase::GAS, gname)) {
gr[gname].injection = this->getGuideRateInjectionGroupValues(group);
}
const auto parent = group.parent();
if (parent == "FIELD") { continue; }
@ -2943,18 +2949,40 @@ namespace Opm {
return grval;
}
if (! this->guideRate_->has(wname)) {
if (! this->guideRate_->hasProductionGroupOrWell(wname)) {
// No guiderates exist for 'wname'.
return grval;
}
const auto qs = WellGroupHelpers::
getRateVector(this->well_state_, this->phase_usage_, wname);
getWellRateVector(this->well_state_, this->phase_usage_, wname);
this->getGuideRateValues(qs, well.isInjector(), wname, grval);
return grval;
}
template <typename TypeTag>
data::GuideRateValue
BlackoilWellModel<TypeTag>::
getGuideRateInjectionGroupValues(const Group& group) const
{
auto grval = data::GuideRateValue{};
assert (this->guideRate_ != nullptr);
const auto& gname = group.name();
if (this->guideRate_->hasInjectionGroup(Opm::Phase::GAS, gname)) {
// No guiderates exist for 'gname'.
grval.set(data::GuideRateValue::Item::Gas,
this->guideRate_->getInjectionGroup(Opm::Phase::GAS, gname));
}
if (this->guideRate_->hasInjectionGroup(Opm::Phase::WATER, gname)) {
// No guiderates exist for 'gname'.
grval.set(data::GuideRateValue::Item::Water,
this->guideRate_->getInjectionGroup(Opm::Phase::WATER, gname));
}
return grval;
}
template <typename TypeTag>
data::GuideRateValue
@ -2966,20 +2994,21 @@ namespace Opm {
assert (this->guideRate_ != nullptr);
const auto& gname = group.name();
if (! this->well_state_.hasProductionGroupRates(gname)) {
// No flow rates for 'gname' -- might be before group comes
if ( ! this->well_state_.hasProductionGroupRates(gname)) {
// No flow rates for production group 'gname' -- might be before group comes
// online (e.g., for the initial condition before simulation
// starts).
return grval;
}
if (! this->guideRate_->has(gname)) {
if (! this->guideRate_->hasProductionGroupOrWell(gname)) {
// No guiderates exist for 'gname'.
return grval;
}
const auto qs = WellGroupHelpers::
getProductionGroupRateVector(this->well_state_, this->phase_usage_, gname);
getProductionGroupRateVector(this->well_state_, this->phase_usage_, gname);
const auto is_inj = false; // This procedure only applies to G*PGR.
this->getGuideRateValues(qs, is_inj, gname, grval);
@ -2997,7 +3026,7 @@ namespace Opm {
{
auto getGR = [this, &wgname, &qs](const GuideRateModel::Target t)
{
return this->guideRate_->get(wgname, t, qs);
return this->guideRate_->getProductionGroupOrWell(wgname, t, qs);
};
// Note: GuideRate does currently (2020-07-20) not support Target::RES.
@ -3026,7 +3055,7 @@ namespace Opm {
auto xgrPos = groupGuideRates.find(group.name());
if ((xgrPos == groupGuideRates.end()) ||
!this->guideRate_->has(group.name()))
!this->guideRate_->hasProductionGroupOrWell(group.name()))
{
// No guiderates defined for this group.
return;

View File

@ -163,6 +163,126 @@ namespace WellGroupHelpers
const double group_grat_target_from_sales_;
};
/// Based on a group control mode, extract or calculate rates, and
/// provide other conveniences.
class InjectionTargetCalculator
{
public:
InjectionTargetCalculator(const Group::InjectionCMode cmode,
const PhaseUsage& pu,
const std::vector<double>& resv_coeff,
const std::string& group_name,
const double sales_target,
const WellStateFullyImplicitBlackoil& well_state,
const Phase& injection_phase)
: cmode_(cmode)
, pu_(pu)
, resv_coeff_(resv_coeff)
, group_name_(group_name)
, sales_target_(sales_target)
, well_state_(well_state)
{
// initialize to avoid warning
pos_ = pu.phase_pos[BlackoilPhases::Aqua];
target_ = GuideRateModel::Target::WAT;
switch (injection_phase) {
case Phase::WATER: {
pos_ = pu.phase_pos[BlackoilPhases::Aqua];
target_ = GuideRateModel::Target::WAT;
break;
}
case Phase::OIL: {
pos_ = pu.phase_pos[BlackoilPhases::Liquid];
target_ = GuideRateModel::Target::OIL;
break;
}
case Phase::GAS: {
pos_ = pu.phase_pos[BlackoilPhases::Vapour];
target_ = GuideRateModel::Target::GAS;
break;
}
default:
assert(false);
}
}
template <typename RateVec>
auto calcModeRateFromRates(const RateVec& rates) const
{
return rates[pos_];
}
double groupTarget(const Group::InjectionControls ctrl) const
{
switch (cmode_) {
case Group::InjectionCMode::RATE:
return ctrl.surface_max_rate;
case Group::InjectionCMode::RESV:
return ctrl.resv_max_rate;
case Group::InjectionCMode::REIN: {
double production_rate = well_state_.currentInjectionREINRates(ctrl.reinj_group)[pos_];
return ctrl.target_reinj_fraction * production_rate;
}
case Group::InjectionCMode::VREP: {
const std::vector<double>& group_injection_reductions
= well_state_.currentInjectionGroupReductionRates(group_name_);
double voidage_rate
= well_state_.currentInjectionVREPRates(ctrl.voidage_group) * ctrl.target_void_fraction;
double inj_reduction = 0.0;
if (ctrl.phase != Phase::WATER)
inj_reduction += group_injection_reductions[pu_.phase_pos[BlackoilPhases::Aqua]]
* resv_coeff_[pu_.phase_pos[BlackoilPhases::Aqua]];
if (ctrl.phase != Phase::OIL)
inj_reduction += group_injection_reductions[pu_.phase_pos[BlackoilPhases::Liquid]]
* resv_coeff_[pu_.phase_pos[BlackoilPhases::Liquid]];
if (ctrl.phase != Phase::GAS)
inj_reduction += group_injection_reductions[pu_.phase_pos[BlackoilPhases::Vapour]]
* resv_coeff_[pu_.phase_pos[BlackoilPhases::Vapour]];
voidage_rate -= inj_reduction;
return voidage_rate / resv_coeff_[pos_];
}
case Group::InjectionCMode::SALE: {
assert(pos_ == pu_.phase_pos[BlackoilPhases::Vapour]);
// Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate;
// Gas import and consumption is already included in the REIN rates
double inj_rate = well_state_.currentInjectionREINRates(group_name_)[pos_];
inj_rate -= sales_target_;
return inj_rate;
}
default:
// Should never be here.
assert(false);
return 0.0;
}
}
GuideRateModel::Target guideTargetMode() const
{
return target_;
}
private:
template <typename ElemType>
static ElemType zero()
{
// This is for Evaluation types.
ElemType x;
x = 0.0;
return x;
}
Group::InjectionCMode cmode_;
const PhaseUsage& pu_;
const std::vector<double>& resv_coeff_;
const std::string& group_name_;
double sales_target_;
const WellStateFullyImplicitBlackoil& well_state_;
int pos_;
GuideRateModel::Target target_;
};
} // namespace WellGroupHelpers
} // namespace Opm

View File

@ -227,6 +227,60 @@ namespace WellGroupHelpers
return gefac * rate;
}
void updateGuideRatesForInjectionGroups(const Group& group,
const Schedule& schedule,
const SummaryState& summaryState,
const Opm::PhaseUsage& pu,
const int reportStepIdx,
const WellStateFullyImplicitBlackoil& wellState,
GuideRate* guideRate)
{
for (const std::string& groupName : group.groups()) {
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
updateGuideRatesForInjectionGroups(
groupTmp, schedule, summaryState, pu, reportStepIdx, wellState, guideRate);
}
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
for (Phase phase : all) {
if(!group.hasInjectionControl(phase))
continue;
double guideRateValue = 0.0;
const auto& controls = group.injectionControls(phase, summaryState);
switch (controls.guide_rate_def){
case Group::GuideRateInjTarget::RATE:
break;
case Group::GuideRateInjTarget::VOID:
{
guideRateValue = wellState.currentInjectionVREPRates(group.name());
break;
}
case Group::GuideRateInjTarget::NETV:
{
guideRateValue = wellState.currentInjectionVREPRates(group.name());
const std::vector<double>& injRES = wellState.currentInjectionGroupReservoirRates(group.name());
if (phase != Phase::OIL && pu.phase_used[BlackoilPhases::Liquid])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Liquid]];
if (phase != Phase::GAS && pu.phase_used[BlackoilPhases::Vapour])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Vapour]];
if (phase != Phase::WATER && pu.phase_used[BlackoilPhases::Aqua])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Aqua]];
break;
}
case Group::GuideRateInjTarget::RESV:
OPM_THROW(std::runtime_error, "GUIDE PHASE RESV not implemented. Group " + group.name());
case Group::GuideRateInjTarget::POTN:
break;
case Group::GuideRateInjTarget::NO_GUIDE_RATE:
break;
default:
assert(false);
}
guideRate->injectionGroupCompute(group.name(), phase, reportStepIdx, guideRateValue);
}
}
void updateGroupTargetReduction(const Group& group,
const Schedule& schedule,
const int reportStepIdx,
@ -282,7 +336,7 @@ namespace WellGroupHelpers
const bool individual_control = (currentGroupControl != Group::ProductionCMode::FLD
&& currentGroupControl != Group::ProductionCMode::NONE);
const int num_group_controlled_wells
= groupControlledWells(schedule, wellStateNupcol, reportStepIdx, subGroupName, "");
= groupControlledWells(schedule, wellStateNupcol, reportStepIdx, subGroupName, "", !isInjector, Phase::OIL);
if (individual_control || num_group_controlled_wells == 0) {
for (int phase = 0; phase < np; phase++) {
groupTargetReduction[phase]
@ -290,7 +344,7 @@ namespace WellGroupHelpers
}
} else {
// The subgroup may participate in group control.
if (!guide_rate.has(subGroupName)) {
if (!guide_rate.hasProductionGroupOrWell(subGroupName)) {
// Accumulate from this subgroup only if no group guide rate is set for it.
for (int phase = 0; phase < np; phase++) {
groupTargetReduction[phase] += subGroupTargetReduction[phase];
@ -582,6 +636,7 @@ namespace WellGroupHelpers
wellState.setCurrentProductionGroupRates(group.name(), rates);
}
void updateREINForGroups(const Group& group,
const Schedule& schedule,
const int reportStepIdx,
@ -738,7 +793,7 @@ namespace WellGroupHelpers
GuideRate::RateVector
getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name)
getWellRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name)
{
return getGuideRateVector(well_state.currentWellRates(name), pu);
}
@ -757,8 +812,12 @@ namespace WellGroupHelpers
const GuideRateModel::Target target,
const PhaseUsage& pu)
{
if (schedule.hasWell(name, reportStepIdx) || guideRate->has(name)) {
return guideRate->get(name, target, getRateVector(wellState, pu, name));
if (schedule.hasWell(name, reportStepIdx)) {
return guideRate->getProductionGroupOrWell(name, target, getWellRateVector(wellState, pu, name));
}
if (guideRate->hasProductionGroupOrWell(name)) {
return guideRate->getProductionGroupOrWell(name, target, getProductionGroupRateVector(wellState, pu, name));
}
double totalGuideRate = 0.0;
@ -786,7 +845,7 @@ namespace WellGroupHelpers
if (!wellState.isProductionGrup(wellName))
continue;
totalGuideRate += guideRate->get(wellName, target, getRateVector(wellState, pu, wellName));
totalGuideRate += guideRate->getProductionGroupOrWell(wellName, target, getWellRateVector(wellState, pu, wellName));
}
return totalGuideRate;
}
@ -802,7 +861,11 @@ namespace WellGroupHelpers
const PhaseUsage& pu)
{
if (schedule.hasWell(name, reportStepIdx)) {
return guideRate->get(name, target, getRateVector(wellState, pu, name));
return guideRate->getProductionGroupOrWell(name, target, getWellRateVector(wellState, pu, name));
}
if (guideRate->hasInjectionGroup(injectionPhase, name)) {
return guideRate->getInjectionGroup(injectionPhase, name);
}
double totalGuideRate = 0.0;
@ -832,7 +895,7 @@ namespace WellGroupHelpers
if (!wellState.isInjectionGrup(wellName))
continue;
totalGuideRate += guideRate->get(wellName, target, getRateVector(wellState, pu, wellName));
totalGuideRate += guideRate->getProductionGroupOrWell(wellName, target, getWellRateVector(wellState, pu, wellName));
}
return totalGuideRate;
}
@ -843,21 +906,35 @@ namespace WellGroupHelpers
const WellStateFullyImplicitBlackoil& well_state,
const int report_step,
const std::string& group_name,
const std::string& always_included_child)
const std::string& always_included_child,
const bool is_production_group,
const Phase injection_phase)
{
const Group& group = schedule.getGroup(group_name, report_step);
int num_wells = 0;
for (const std::string& child_group : group.groups()) {
const auto ctrl = well_state.currentProductionGroupControl(child_group);
const bool included = (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE)
|| (child_group == always_included_child);
bool included = (child_group == always_included_child);
if (is_production_group) {
const auto ctrl = well_state.currentProductionGroupControl(child_group);
included = included || (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE);
} else {
const auto ctrl = well_state.currentInjectionGroupControl(injection_phase, child_group);
included = included || (ctrl == Group::InjectionCMode::FLD) || (ctrl == Group::InjectionCMode::NONE);
}
if (included) {
num_wells
+= groupControlledWells(schedule, well_state, report_step, child_group, always_included_child);
+= groupControlledWells(schedule, well_state, report_step, child_group, always_included_child, is_production_group, injection_phase);
}
}
for (const std::string& child_well : group.wells()) {
const bool included = (well_state.isProductionGrup(child_well)) || (child_well == always_included_child);
bool included = (child_well == always_included_child);
if (is_production_group) {
included = included || well_state.isProductionGrup(child_well);
} else {
included = included || well_state.isInjectionGrup(child_well);
}
if (included) {
++num_wells;
}
@ -866,17 +943,23 @@ namespace WellGroupHelpers
}
FractionCalculator::FractionCalculator(const Schedule& schedule,
const SummaryState& summary_state,
const WellStateFullyImplicitBlackoil& well_state,
const int report_step,
const GuideRate* guide_rate,
const GuideRateModel::Target target,
const PhaseUsage& pu)
const PhaseUsage& pu,
const bool is_producer,
const Phase injection_phase)
: schedule_(schedule)
, summary_state_(summary_state)
, well_state_(well_state)
, report_step_(report_step)
, guide_rate_(guide_rate)
, target_(target)
, pu_(pu)
, is_producer_(is_producer)
, injection_phase_(injection_phase)
{
}
double FractionCalculator::fraction(const std::string& name,
@ -912,15 +995,26 @@ namespace WellGroupHelpers
{
double total_guide_rate = 0.0;
for (const std::string& child_group : group.groups()) {
const auto ctrl = well_state_.currentProductionGroupControl(child_group);
const bool included = (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE)
|| (child_group == always_included_child);
bool included = (child_group == always_included_child);
if (is_producer_) {
const auto ctrl = well_state_.currentProductionGroupControl(child_group);
included = included || (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE);
} else {
const auto ctrl = well_state_.currentInjectionGroupControl(injection_phase_, child_group);
included = included || (ctrl == Group::InjectionCMode::FLD) || (ctrl == Group::InjectionCMode::NONE);
}
if (included) {
total_guide_rate += guideRate(child_group, always_included_child);
}
}
for (const std::string& child_well : group.wells()) {
const bool included = (well_state_.isProductionGrup(child_well)) || (child_well == always_included_child);
bool included = (child_well == always_included_child);
if (is_producer_) {
included = included || well_state_.isProductionGrup(child_well);
} else {
included = included || well_state_.isInjectionGrup(child_well);
}
if (included) {
total_guide_rate += guideRate(child_well, always_included_child);
}
@ -930,11 +1024,13 @@ namespace WellGroupHelpers
double FractionCalculator::guideRate(const std::string& name, const std::string& always_included_child)
{
if (schedule_.hasWell(name, report_step_)) {
return guide_rate_->get(name, target_, getRateVector(well_state_, pu_, name));
return guide_rate_->getProductionGroupOrWell(name, target_, getWellRateVector(well_state_, pu_, name));
} else {
if (groupControlledWells(name, always_included_child) > 0) {
if (guide_rate_->has(name)) {
return guide_rate_->get(name, target_, getGroupRateVector(name));
if (is_producer_ && guide_rate_->hasProductionGroupOrWell(name)) {
return guide_rate_->getProductionGroupOrWell(name, target_, getGroupRateVector(name));
} else if (!is_producer_ && guide_rate_->hasInjectionGroup(injection_phase_, name)) {
return guide_rate_->getInjectionGroup(injection_phase_, name);
} else {
// We are a group, with default guide rate.
// Compute guide rate by accumulating our children's guide rates.
@ -951,250 +1047,16 @@ namespace WellGroupHelpers
const std::string& always_included_child)
{
return ::Opm::WellGroupHelpers::groupControlledWells(
schedule_, well_state_, report_step_, group_name, always_included_child);
schedule_, well_state_, report_step_, group_name, always_included_child, is_producer_, injection_phase_);
}
GuideRate::RateVector FractionCalculator::getGroupRateVector(const std::string& group_name)
{
assert(is_producer_);
return getProductionGroupRateVector(this->well_state_, this->pu_, group_name);
}
double fractionFromGuideRates(const std::string& name,
const std::string& controlGroupName,
const Schedule& schedule,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu,
const bool alwaysIncludeThis)
{
FractionCalculator calc(schedule, wellState, reportStepIdx, guideRate, target, pu);
return calc.fraction(name, controlGroupName, alwaysIncludeThis);
}
double fractionFromInjectionPotentials(const std::string& name,
const std::string& controlGroupName,
const Schedule& schedule,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu,
const Phase& injectionPhase,
const bool alwaysIncludeThis)
{
double thisGuideRate
= getGuideRateInj(name, schedule, wellState, reportStepIdx, guideRate, target, injectionPhase, pu);
double controlGroupGuideRate = getGuideRateInj(
controlGroupName, schedule, wellState, reportStepIdx, guideRate, target, injectionPhase, pu);
if (alwaysIncludeThis)
controlGroupGuideRate += thisGuideRate;
assert(controlGroupGuideRate >= thisGuideRate);
const double guideRateEpsilon = 1e-12;
return (controlGroupGuideRate > guideRateEpsilon) ? thisGuideRate / controlGroupGuideRate : 0.0;
}
std::pair<bool, double> checkGroupConstraintsInj(const std::string& name,
const std::string& parent,
const Group& group,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const double* rates,
Phase injectionPhase,
const PhaseUsage& pu,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const std::vector<double>& resv_coeff,
DeferredLogger& deferred_logger)
{
// When called for a well ('name' is a well name), 'parent'
// will be the name of 'group'. But if we recurse, 'name' and
// 'parent' will stay fixed while 'group' will be higher up
// in the group tree.
// efficiency factor is the well efficiency factor for the first group the well is
// part of. Later it is the accumulated factor including the group efficiency factor
// of the child of group.
const Group::InjectionCMode& currentGroupControl
= wellState.currentInjectionGroupControl(injectionPhase, group.name());
if (currentGroupControl == Group::InjectionCMode::FLD || currentGroupControl == Group::InjectionCMode::NONE) {
// Return if we are not available for parent group.
if (!group.injectionGroupControlAvailable(injectionPhase)) {
return std::make_pair(false, 1.0);
}
// Otherwise: check injection share of parent's control.
const auto& parentGroup = schedule.getGroup(group.parent(), reportStepIdx);
return checkGroupConstraintsInj(name,
parent,
parentGroup,
wellState,
reportStepIdx,
guideRate,
rates,
injectionPhase,
pu,
efficiencyFactor * group.getGroupEfficiencyFactor(),
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
// If we are here, we are at the topmost group to be visited in the recursion.
// This is the group containing the control we will check against.
// This can be false for FLD-controlled groups, we must therefore
// check for FLD first (done above).
if (!group.isInjectionGroup()) {
return std::make_pair(false, 1.0);
}
int phasePos;
GuideRateModel::Target target;
switch (injectionPhase) {
case Phase::WATER: {
phasePos = pu.phase_pos[BlackoilPhases::Aqua];
target = GuideRateModel::Target::WAT;
break;
}
case Phase::OIL: {
phasePos = pu.phase_pos[BlackoilPhases::Liquid];
target = GuideRateModel::Target::OIL;
break;
}
case Phase::GAS: {
phasePos = pu.phase_pos[BlackoilPhases::Vapour];
target = GuideRateModel::Target::GAS;
break;
}
default:
OPM_DEFLOG_THROW(
std::logic_error, "Expected WATER, OIL or GAS as injecting type for " + name, deferred_logger);
}
assert(group.hasInjectionControl(injectionPhase));
const auto& groupcontrols = group.injectionControls(injectionPhase, summaryState);
const std::vector<double>& groupInjectionReductions
= wellState.currentInjectionGroupReductionRates(group.name());
const double groupTargetReduction = groupInjectionReductions[phasePos];
double fraction = fractionFromInjectionPotentials(
name, group.name(), schedule, wellState, reportStepIdx, guideRate, target, pu, injectionPhase, true);
double target_fraction = 1.0;
bool constraint_broken = false;
double efficiencyFactorInclGroup = efficiencyFactor * group.getGroupEfficiencyFactor();
switch (currentGroupControl) {
case Group::InjectionCMode::RATE: {
const double current_rate = rates[phasePos];
const double target_rate = fraction
* std::max(0.0,
(groupcontrols.surface_max_rate - groupTargetReduction + current_rate * efficiencyFactorInclGroup))
/ efficiencyFactorInclGroup;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
case Group::InjectionCMode::RESV: {
const double coeff = resv_coeff[phasePos];
const double current_rate = rates[phasePos];
const double target_rate = fraction
* std::max(0.0,
(groupcontrols.resv_max_rate / coeff - groupTargetReduction
+ current_rate * efficiencyFactorInclGroup))
/ efficiencyFactorInclGroup;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
case Group::InjectionCMode::REIN: {
double productionRate = wellState.currentInjectionREINRates(groupcontrols.reinj_group)[phasePos];
const double current_rate = rates[phasePos];
const double target_rate = fraction
* std::max(0.0,
(groupcontrols.target_reinj_fraction * productionRate - groupTargetReduction
+ current_rate * efficiencyFactorInclGroup))
/ efficiencyFactorInclGroup;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
case Group::InjectionCMode::VREP: {
const double coeff = resv_coeff[phasePos];
double voidageRate
= wellState.currentInjectionVREPRates(groupcontrols.voidage_group) * groupcontrols.target_void_fraction;
double injReduction = 0.0;
if (groupcontrols.phase != Phase::WATER)
injReduction += groupInjectionReductions[pu.phase_pos[BlackoilPhases::Aqua]]
* resv_coeff[pu.phase_pos[BlackoilPhases::Aqua]];
if (groupcontrols.phase != Phase::OIL)
injReduction += groupInjectionReductions[pu.phase_pos[BlackoilPhases::Liquid]]
* resv_coeff[pu.phase_pos[BlackoilPhases::Liquid]];
if (groupcontrols.phase != Phase::GAS)
injReduction += groupInjectionReductions[pu.phase_pos[BlackoilPhases::Vapour]]
* resv_coeff[pu.phase_pos[BlackoilPhases::Vapour]];
voidageRate -= injReduction;
const double current_rate = rates[phasePos];
const double target_rate = fraction
* std::max(0.0, (voidageRate / coeff - groupTargetReduction + current_rate * efficiencyFactorInclGroup))
/ efficiencyFactorInclGroup;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
case Group::InjectionCMode::SALE: {
// only for gas injectors
assert(phasePos == pu.phase_pos[BlackoilPhases::Vapour]);
// Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate;
// Gas import and consumption is already included in the REIN rates
double inj_rate = wellState.currentInjectionREINRates(group.name())[phasePos];
const auto& gconsale = schedule[reportStepIdx].gconsale().get(group.name(), summaryState);
inj_rate -= gconsale.sales_target;
const double current_rate = rates[phasePos];
const double target_rate = fraction
* std::max(0.0, (inj_rate - groupTargetReduction + current_rate * efficiencyFactorInclGroup)) / efficiencyFactorInclGroup;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
case Group::InjectionCMode::NONE: {
assert(false); // Should already be handled at the top.
}
case Group::InjectionCMode::FLD: {
assert(false); // Should already be handled at the top.
}
default:
OPM_DEFLOG_THROW(
std::runtime_error, "Invalid group control specified for group " + group.name(), deferred_logger);
}
return std::make_pair(constraint_broken, target_fraction);
}
std::vector<std::string>
groupChainTopBot(const std::string& bottom, const std::string& top, const Schedule& schedule, const int report_step)
{
@ -1286,7 +1148,7 @@ namespace WellGroupHelpers
gratTargetFromSales = wellState.currentGroupGratTargetFromSales(group.name());
TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
FractionCalculator fcalc(schedule, wellState, reportStepIdx, guideRate, tcalc.guideTargetMode(), pu);
FractionCalculator fcalc(schedule, summaryState, wellState, reportStepIdx, guideRate, tcalc.guideTargetMode(), pu, true, Phase::OIL);
auto localFraction = [&](const std::string& child) { return fcalc.localFraction(child, name); };
@ -1308,7 +1170,7 @@ namespace WellGroupHelpers
// we need to find out the level where the current well is applied to the local reduction
size_t local_reduction_level = 0;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guideRate->has(chain[ii])) {
if ((ii == 0) || guideRate->hasProductionGroupOrWell(chain[ii])) {
local_reduction_level = ii;
}
}
@ -1316,7 +1178,7 @@ namespace WellGroupHelpers
double efficiencyFactorInclGroup = efficiencyFactor * group.getGroupEfficiencyFactor();
double target = orig_target;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guideRate->has(chain[ii])) {
if ((ii == 0) || guideRate->hasProductionGroupOrWell(chain[ii])) {
// Apply local reductions only at the control level
// (top) and for levels where we have a specified
// group guide rate.
@ -1333,9 +1195,132 @@ namespace WellGroupHelpers
// the current well to be always included, because we
// want to know the situation that applied to the
// calculation of reductions.
const int num_gr_ctrl = groupControlledWells(schedule, wellState, reportStepIdx, chain[ii + 1], "");
const int num_gr_ctrl = groupControlledWells(schedule, wellState, reportStepIdx, chain[ii + 1], "", true, Phase::OIL);
if (num_gr_ctrl == 0) {
if (guideRate->has(chain[ii + 1])) {
if (guideRate->hasProductionGroupOrWell(chain[ii + 1])) {
target += localReduction(chain[ii + 1]);
}
}
}
target *= localFraction(chain[ii + 1]);
}
// Avoid negative target rates comming from too large local reductions.
const double target_rate = std::max(1e-12, target / efficiencyFactorInclGroup);
return std::make_pair(current_rate > target_rate, target_rate / current_rate);
}
std::pair<bool, double> checkGroupConstraintsInj(const std::string& name,
const std::string& parent,
const Group& group,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const double* rates,
Phase injectionPhase,
const PhaseUsage& pu,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const std::vector<double>& resv_coeff,
DeferredLogger& deferred_logger)
{
// When called for a well ('name' is a well name), 'parent'
// will be the name of 'group'. But if we recurse, 'name' and
// 'parent' will stay fixed while 'group' will be higher up
// in the group tree.
// efficiencyfactor is the well efficiency factor for the first group the well is
// part of. Later it is the accumulated factor including the group efficiency factor
// of the child of group.
const Group::InjectionCMode& currentGroupControl = wellState.currentInjectionGroupControl(injectionPhase, group.name());
if (currentGroupControl == Group::InjectionCMode::FLD || currentGroupControl == Group::InjectionCMode::NONE) {
// Return if we are not available for parent group.
if (!group.injectionGroupControlAvailable(injectionPhase)) {
return std::make_pair(false, 1);
}
// Otherwise: check production share of parent's control.
const auto& parentGroup = schedule.getGroup(group.parent(), reportStepIdx);
return checkGroupConstraintsInj(name,
parent,
parentGroup,
wellState,
reportStepIdx,
guideRate,
rates,
injectionPhase,
pu,
efficiencyFactor * group.getGroupEfficiencyFactor(),
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
// This can be false for FLD-controlled groups, we must therefore
// check for FLD first (done above).
if (!group.isInjectionGroup()) {
return std::make_pair(false, 1.0);
}
// If we are here, we are at the topmost group to be visited in the recursion.
// This is the group containing the control we will check against.
double sales_target = 0;
if (schedule[reportStepIdx].gconsale().has(group.name())) {
const auto& gconsale = schedule[reportStepIdx].gconsale().get(group.name(), summaryState);
sales_target = gconsale.sales_target;
}
InjectionTargetCalculator tcalc(currentGroupControl, pu, resv_coeff, group.name(), sales_target, wellState, injectionPhase);
FractionCalculator fcalc(schedule, summaryState, wellState, reportStepIdx, guideRate, tcalc.guideTargetMode(), pu, false, injectionPhase);
auto localFraction = [&](const std::string& child) { return fcalc.localFraction(child, name); };
auto localReduction = [&](const std::string& group_name) {
const std::vector<double>& groupTargetReductions
= wellState.currentInjectionGroupReductionRates(group_name);
return tcalc.calcModeRateFromRates(groupTargetReductions);
};
const double orig_target = tcalc.groupTarget(group.injectionControls(injectionPhase, summaryState));
// Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP.
// Then ...
// TODO finish explanation.
const double current_rate
= tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
const auto chain = groupChainTopBot(name, group.name(), schedule, reportStepIdx);
// Because 'name' is the last of the elements, and not an ancestor, we subtract one below.
const size_t num_ancestors = chain.size() - 1;
// we need to find out the level where the current well is applied to the local reduction
size_t local_reduction_level = 0;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guideRate->hasInjectionGroup(injectionPhase, chain[ii])) {
local_reduction_level = ii;
}
}
double efficiencyFactorInclGroup = efficiencyFactor * group.getGroupEfficiencyFactor();
double target = orig_target;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guideRate->hasInjectionGroup(injectionPhase, chain[ii])) {
// Apply local reductions only at the control level
// (top) and for levels where we have a specified
// group guide rate.
target -= localReduction(chain[ii]);
// Add my reduction back at the level where it is included in the local reduction
if (local_reduction_level == ii )
target += current_rate * efficiencyFactorInclGroup;
}
if (ii < num_ancestors - 1) {
// Not final level. Add sub-level reduction back, if
// it was nonzero due to having no group-controlled
// wells. Note that we make this call without setting
// the current well to be always included, because we
// want to know the situation that applied to the
// calculation of reductions.
const int num_gr_ctrl = groupControlledWells(schedule, wellState, reportStepIdx, chain[ii + 1], "", false, injectionPhase);
if (num_gr_ctrl == 0) {
if (guideRate->hasInjectionGroup(injectionPhase, chain[ii + 1])) {
target += localReduction(chain[ii + 1]);
}
}
@ -1348,6 +1333,7 @@ namespace WellGroupHelpers
}
} // namespace WellGroupHelpers
} // namespace Opm

View File

@ -95,16 +95,15 @@ namespace WellGroupHelpers
std::vector<double>& groupTargetReduction);
template <class Comm>
void updateGuideRateForGroups(const Group& group,
const Schedule& schedule,
const PhaseUsage& pu,
const int reportStepIdx,
const double& simTime,
const bool isInjector,
WellStateFullyImplicitBlackoil& wellState,
const Comm& comm,
GuideRate* guideRate,
std::vector<double>& pot)
void updateGuideRateForProductionGroups(const Group& group,
const Schedule& schedule,
const PhaseUsage& pu,
const int reportStepIdx,
const double& simTime,
WellStateFullyImplicitBlackoil& wellState,
const Comm& comm,
GuideRate* guideRate,
std::vector<double>& pot)
{
const int np = pu.num_phases;
for (const std::string& groupName : group.groups()) {
@ -112,44 +111,25 @@ namespace WellGroupHelpers
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
// Note that group effiency factors for groupTmp are applied in updateGuideRateForGroups
updateGuideRateForGroups(
groupTmp, schedule, pu, reportStepIdx, simTime, isInjector, wellState, comm, guideRate, thisPot);
updateGuideRateForProductionGroups(
groupTmp, schedule, pu, reportStepIdx, simTime, wellState, comm, guideRate, thisPot);
// accumulate group contribution from sub group unconditionally
if (isInjector) {
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
for (Phase phase : all) {
int phasePos;
if (phase == Phase::GAS && pu.phase_used[BlackoilPhases::Vapour])
phasePos = pu.phase_pos[BlackoilPhases::Vapour];
else if (phase == Phase::OIL && pu.phase_used[BlackoilPhases::Liquid])
phasePos = pu.phase_pos[BlackoilPhases::Liquid];
else if (phase == Phase::WATER && pu.phase_used[BlackoilPhases::Aqua])
phasePos = pu.phase_pos[BlackoilPhases::Aqua];
else
continue;
pot[phasePos] += thisPot[phasePos];
}
} else {
const Group::ProductionCMode& currentGroupControl = wellState.currentProductionGroupControl(groupName);
if (currentGroupControl != Group::ProductionCMode::FLD
const Group::ProductionCMode& currentGroupControl = wellState.currentProductionGroupControl(groupName);
if (currentGroupControl != Group::ProductionCMode::FLD
&& currentGroupControl != Group::ProductionCMode::NONE) {
continue;
}
for (int phase = 0; phase < np; phase++) {
pot[phase] += thisPot[phase];
}
continue;
}
for (int phase = 0; phase < np; phase++) {
pot[phase] += thisPot[phase];
}
}
for (const std::string& wellName : group.wells()) {
const auto& wellTmp = schedule.getWell(wellName, reportStepIdx);
const auto wefac = wellTmp.getEfficiencyFactor();
if (wellTmp.isProducer() && isInjector)
continue;
if (wellTmp.isInjector() && !isInjector)
if (wellTmp.isInjector())
continue;
if (wellTmp.getStatus() == Well::Status::SHUT)
@ -195,12 +175,7 @@ namespace WellGroupHelpers
oilPot = comm.sum(oilPot);
gasPot = comm.sum(gasPot);
waterPot = comm.sum(waterPot);
if (isInjector) {
wellState.setCurrentGroupInjectionPotentials(group.name(), pot);
} else {
guideRate->compute(group.name(), reportStepIdx, simTime, oilPot, gasPot, waterPot);
}
guideRate->productionGroupCompute(group.name(), reportStepIdx, simTime, oilPot, gasPot, waterPot);
}
template <class Comm>
@ -238,10 +213,17 @@ namespace WellGroupHelpers
oilpot = comm.sum(oilpot);
gaspot = comm.sum(gaspot);
waterpot = comm.sum(waterpot);
guideRate->compute(well.name(), reportStepIdx, simTime, oilpot, gaspot, waterpot);
guideRate->wellCompute(well.name(), reportStepIdx, simTime, oilpot, gaspot, waterpot);
}
}
void updateGuideRatesForInjectionGroups(const Group& group,
const Schedule& schedule,
const SummaryState& summaryState,
const Opm::PhaseUsage& pu,
const int reportStepIdx,
const WellStateFullyImplicitBlackoil& wellState,
GuideRate* guideRate);
void updateVREPForGroups(const Group& group,
const Schedule& schedule,
@ -283,7 +265,7 @@ namespace WellGroupHelpers
const int report_time_step);
GuideRate::RateVector
getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name);
getWellRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name);
GuideRate::RateVector
getProductionGroupRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& group_name);
@ -310,18 +292,23 @@ namespace WellGroupHelpers
const WellStateFullyImplicitBlackoil& well_state,
const int report_step,
const std::string& group_name,
const std::string& always_included_child);
const std::string& always_included_child,
const bool is_production_group,
const Phase injection_phase);
class FractionCalculator
{
public:
FractionCalculator(const Schedule& schedule,
const SummaryState& summary_state,
const WellStateFullyImplicitBlackoil& well_state,
const int report_step,
const GuideRate* guide_rate,
const GuideRateModel::Target target,
const PhaseUsage& pu);
const PhaseUsage& pu,
const bool is_producer,
const Phase injection_phase);
double fraction(const std::string& name, const std::string& control_group_name, const bool always_include_this);
double localFraction(const std::string& name, const std::string& always_included_child);
@ -332,36 +319,17 @@ namespace WellGroupHelpers
int groupControlledWells(const std::string& group_name, const std::string& always_included_child);
GuideRate::RateVector getGroupRateVector(const std::string& group_name);
const Schedule& schedule_;
const SummaryState& summary_state_;
const WellStateFullyImplicitBlackoil& well_state_;
int report_step_;
const GuideRate* guide_rate_;
GuideRateModel::Target target_;
PhaseUsage pu_;
bool is_producer_;
Phase injection_phase_;
};
double fractionFromGuideRates(const std::string& name,
const std::string& controlGroupName,
const Schedule& schedule,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu,
const bool alwaysIncludeThis = false);
double fractionFromInjectionPotentials(const std::string& name,
const std::string& controlGroupName,
const Schedule& schedule,
const WellStateFullyImplicitBlackoil& wellState,
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu,
const Phase& injectionPhase,
const bool alwaysIncludeThis = false);
std::pair<bool, double> checkGroupConstraintsInj(const std::string& name,
const std::string& parent,
const Group& group,

View File

@ -2142,47 +2142,35 @@ namespace Opm
template <typename TypeTag>
template <class EvalWell>
void
WellInterface<TypeTag>::getGroupInjectionControl(const Group& group,
const WellState& well_state,
const Opm::Schedule& schedule,
const SummaryState& summaryState,
const InjectorType& injectorType,
const EvalWell& bhp,
const EvalWell& injection_rate,
EvalWell& control_eq,
double efficiencyFactor)
const WellState& well_state,
const Opm::Schedule& schedule,
const SummaryState& summaryState,
const InjectorType& injectorType,
const EvalWell& bhp,
const EvalWell& injection_rate,
EvalWell& control_eq,
double efficiencyFactor)
{
const auto& well = well_ecl_;
const auto pu = phaseUsage();
// Setting some defaults to silence warnings below.
// Will be overwritten in the switch statement.
int phasePos = -1;
Well::GuideRateTarget wellTarget = Well::GuideRateTarget::UNDEFINED;
Phase injectionPhase = Phase::WATER;
switch (injectorType) {
case InjectorType::WATER:
{
phasePos = pu.phase_pos[BlackoilPhases::Aqua];
wellTarget = Well::GuideRateTarget::WAT;
injectionPhase = Phase::WATER;
break;
}
case InjectorType::OIL:
{
phasePos = pu.phase_pos[BlackoilPhases::Liquid];
wellTarget = Well::GuideRateTarget::OIL;
injectionPhase = Phase::OIL;
break;
}
case InjectorType::GAS:
{
phasePos = pu.phase_pos[BlackoilPhases::Vapour];
wellTarget = Well::GuideRateTarget::GAS;
injectionPhase = Phase::GAS;
break;
}
@ -2192,7 +2180,6 @@ namespace Opm
}
const Group::InjectionCMode& currentGroupControl = well_state.currentInjectionGroupControl(injectionPhase, group.name());
if (currentGroupControl == Group::InjectionCMode::FLD ||
currentGroupControl == Group::InjectionCMode::NONE) {
if (!group.injectionGroupControlAvailable(injectionPhase)) {
@ -2217,103 +2204,62 @@ namespace Opm
}
efficiencyFactor *= group.getGroupEfficiencyFactor();
assert(group.hasInjectionControl(injectionPhase));
const auto& groupcontrols = group.injectionControls(injectionPhase, summaryState);
const auto& well = well_ecl_;
const auto pu = phaseUsage();
const std::vector<double>& groupInjectionReductions = well_state.currentInjectionGroupReductionRates(group.name());
double groupTargetReduction = groupInjectionReductions[phasePos];
double fraction = WellGroupHelpers::fractionFromInjectionPotentials(well.name(),
group.name(),
schedule,
well_state,
current_step_,
guide_rate_,
GuideRateModel::convert_target(wellTarget),
pu,
injectionPhase,
false);
switch (currentGroupControl) {
case Group::InjectionCMode::NONE:
{
// The NONE case is handled earlier
assert(false);
break;
if (!group.isInjectionGroup()) {
// use bhp as control eq and let the updateControl code find a valid control
const auto& controls = well.injectionControls(summaryState);
control_eq = bhp - controls.bhp_limit;
return;
}
case Group::InjectionCMode::RATE:
{
double target = std::max(0.0, (groupcontrols.surface_max_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = injection_rate - fraction * target;
break;
}
case Group::InjectionCMode::RESV:
{
std::vector<double> convert_coeff(number_of_phases_, 1.0);
rateConverter_.calcCoeff(/*fipreg*/ 0, pvtRegionIdx_, convert_coeff);
double coeff = convert_coeff[phasePos];
double target = std::max(0.0, (groupcontrols.resv_max_rate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = injection_rate - fraction * target;
break;
}
case Group::InjectionCMode::REIN:
{
double productionRate = well_state.currentInjectionREINRates(groupcontrols.reinj_group)[phasePos];
double target = std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction)) / efficiencyFactor;
control_eq = injection_rate - fraction * target;
break;
}
case Group::InjectionCMode::VREP:
{
std::vector<double> convert_coeff(number_of_phases_, 1.0);
rateConverter_.calcCoeff(/*fipreg*/ 0, pvtRegionIdx_, convert_coeff);
double coeff = convert_coeff[phasePos];
double voidageRate = well_state.currentInjectionVREPRates(groupcontrols.voidage_group)*groupcontrols.target_void_fraction;
double injReduction = 0.0;
std::vector<double> groupInjectionReservoirRates = well_state.currentInjectionGroupReservoirRates(group.name());
if (groupcontrols.phase != Phase::WATER)
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Aqua]];
// If we are here, we are at the topmost group to be visited in the recursion.
// This is the group containing the control we will check against.
if (groupcontrols.phase != Phase::OIL)
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Liquid]];
// Make conversion factors for RESV <-> surface rates.
std::vector<double> resv_coeff(phaseUsage().num_phases, 1.0);
rateConverter_.calcCoeff(0, pvtRegionIdx_, resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
if (groupcontrols.phase != Phase::GAS)
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Vapour]];
voidageRate -= injReduction;
double target = std::max(0.0, ( voidageRate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = injection_rate - fraction * target;
break;
}
case Group::InjectionCMode::FLD:
{
// The FLD case is handled earlier
assert(false);
break;
}
case Group::InjectionCMode::SALE:
{
// only for gas injectors
assert (phasePos == pu.phase_pos[BlackoilPhases::Vapour]);
// Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate;
// The import and consumption is already included in the REIN rates.
double inj_rate = well_state.currentInjectionREINRates(group.name())[phasePos];
double sales_target = 0;
if (schedule[current_step_].gconsale().has(group.name())) {
const auto& gconsale = schedule[current_step_].gconsale().get(group.name(), summaryState);
inj_rate -= gconsale.sales_target;
sales_target = gconsale.sales_target;
}
WellGroupHelpers::InjectionTargetCalculator tcalc(currentGroupControl, pu, resv_coeff, group.name(), sales_target, well_state, injectionPhase);
WellGroupHelpers::FractionCalculator fcalc(schedule, summaryState, well_state, current_step_, guide_rate_, tcalc.guideTargetMode(), pu, false, injectionPhase);
double target = std::max(0.0, (inj_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = injection_rate - fraction * target;
break;
}
// default:
// OPM_DEFLOG_THROW(std::runtime_error, "Unvalid group control specified for group " + well.groupName(), deferred_logger );
auto localFraction = [&](const std::string& child) {
return fcalc.localFraction(child, "");
};
auto localReduction = [&](const std::string& group_name) {
const std::vector<double>& groupTargetReductions = well_state.currentInjectionGroupReductionRates(group_name);
return tcalc.calcModeRateFromRates(groupTargetReductions);
};
const double orig_target = tcalc.groupTarget(group.injectionControls(injectionPhase, summaryState));
const auto chain = WellGroupHelpers::groupChainTopBot(name(), group.name(), schedule, current_step_);
// Because 'name' is the last of the elements, and not an ancestor, we subtract one below.
const size_t num_ancestors = chain.size() - 1;
double target = orig_target;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guide_rate_->hasInjectionGroup(injectionPhase, chain[ii])) {
// Apply local reductions only at the control level
// (top) and for levels where we have a specified
// group guide rate.
target -= localReduction(chain[ii]);
}
target *= localFraction(chain[ii+1]);
}
// Avoid negative target rates coming from too large local reductions.
const double target_rate = std::max(0.0, target / efficiencyFactor);
const auto current_rate = injection_rate; // Switch sign since 'rates' are negative for producers.
control_eq = current_rate - target_rate;
}
template <typename TypeTag>
template <class EvalWell>
void
@ -2375,7 +2321,7 @@ namespace Opm
gratTargetFromSales = well_state.currentGroupGratTargetFromSales(group.name());
WellGroupHelpers::TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
WellGroupHelpers::FractionCalculator fcalc(schedule, well_state, current_step_, guide_rate_, tcalc.guideTargetMode(), pu);
WellGroupHelpers::FractionCalculator fcalc(schedule, summaryState, well_state, current_step_, guide_rate_, tcalc.guideTargetMode(), pu, true, Phase::OIL);
auto localFraction = [&](const std::string& child) {
return fcalc.localFraction(child, "");
@ -2392,7 +2338,7 @@ namespace Opm
const size_t num_ancestors = chain.size() - 1;
double target = orig_target;
for (size_t ii = 0; ii < num_ancestors; ++ii) {
if ((ii == 0) || guide_rate_->has(chain[ii])) {
if ((ii == 0) || guide_rate_->hasProductionGroupOrWell(chain[ii])) {
// Apply local reductions only at the control level
// (top) and for levels where we have a specified
// group guide rate.

View File

@ -449,6 +449,7 @@ namespace Opm
return this->production_group_rates.find(groupName) != this->production_group_rates.end();
}
void setCurrentProductionGroupReductionRates(const std::string& groupName, const std::vector<double>& target ) {
production_group_reduction_rates[groupName] = target;
}