mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #3112 from totto82/refact_ginj
Add support for explicit guiderate for injection groups
This commit is contained in:
commit
cd7c4d9927
@ -260,16 +260,24 @@ public:
|
|||||||
(*this)(d);
|
(*this)(d);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto keyHandle = [&](auto& d)
|
||||||
|
{
|
||||||
|
if constexpr (is_pair<Key>::value)
|
||||||
|
pair(d);
|
||||||
|
else
|
||||||
|
(*this)(d);
|
||||||
|
};
|
||||||
|
|
||||||
if (m_op == Operation::PACKSIZE) {
|
if (m_op == Operation::PACKSIZE) {
|
||||||
m_packSize += Mpi::packSize(data.size(), m_comm);
|
m_packSize += Mpi::packSize(data.size(), m_comm);
|
||||||
for (auto& it : data) {
|
for (auto& it : data) {
|
||||||
m_packSize += Mpi::packSize(it.first, m_comm);
|
keyHandle(it.first);
|
||||||
handle(it.second);
|
handle(it.second);
|
||||||
}
|
}
|
||||||
} else if (m_op == Operation::PACK) {
|
} else if (m_op == Operation::PACK) {
|
||||||
Mpi::pack(data.size(), m_buffer, m_position, m_comm);
|
Mpi::pack(data.size(), m_buffer, m_position, m_comm);
|
||||||
for (auto& it : data) {
|
for (auto& it : data) {
|
||||||
Mpi::pack(it.first, m_buffer, m_position, m_comm);
|
keyHandle(it.first);
|
||||||
handle(it.second);
|
handle(it.second);
|
||||||
}
|
}
|
||||||
} else if (m_op == Operation::UNPACK) {
|
} else if (m_op == Operation::UNPACK) {
|
||||||
@ -277,7 +285,7 @@ public:
|
|||||||
Mpi::unpack(size, m_buffer, m_position, m_comm);
|
Mpi::unpack(size, m_buffer, m_position, m_comm);
|
||||||
for (size_t i = 0; i < size; ++i) {
|
for (size_t i = 0; i < size; ++i) {
|
||||||
Key key;
|
Key key;
|
||||||
Mpi::unpack(key, m_buffer, m_position, m_comm);
|
keyHandle(key);
|
||||||
Data entry;
|
Data entry;
|
||||||
handle(entry);
|
handle(entry);
|
||||||
data.insert(std::make_pair(key, entry));
|
data.insert(std::make_pair(key, entry));
|
||||||
|
@ -391,7 +391,7 @@ namespace Opm {
|
|||||||
|
|
||||||
void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls);
|
void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls);
|
||||||
|
|
||||||
void updateAndCommunicateGroupData();
|
void updateAndCommunicateGroupData(Opm::DeferredLogger& deferred_logger);
|
||||||
void updateNetworkPressures();
|
void updateNetworkPressures();
|
||||||
|
|
||||||
// setting the well_solutions_ based on well_state.
|
// setting the well_solutions_ based on well_state.
|
||||||
@ -502,6 +502,7 @@ namespace Opm {
|
|||||||
void assignGroupControl(const Group& group, data::GroupData& gdata) const;
|
void assignGroupControl(const Group& group, data::GroupData& gdata) const;
|
||||||
data::GuideRateValue getGuideRateValues(const Well& well) const;
|
data::GuideRateValue getGuideRateValues(const Well& well) const;
|
||||||
data::GuideRateValue getGuideRateValues(const Group& group) const;
|
data::GuideRateValue getGuideRateValues(const Group& group) const;
|
||||||
|
data::GuideRateValue getGuideRateInjectionGroupValues(const Group& group) const;
|
||||||
void getGuideRateValues(const GuideRate::RateVector& qs,
|
void getGuideRateValues(const GuideRate::RateVector& qs,
|
||||||
const bool is_inj,
|
const bool is_inj,
|
||||||
const std::string& wgname,
|
const std::string& wgname,
|
||||||
|
@ -306,7 +306,7 @@ namespace Opm {
|
|||||||
|
|
||||||
well_state_ = previous_well_state_;
|
well_state_ = previous_well_state_;
|
||||||
well_state_.disableGliftOptimization();
|
well_state_.disableGliftOptimization();
|
||||||
updateAndCommunicateGroupData();
|
updateAndCommunicateGroupData(local_deferredLogger);
|
||||||
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
||||||
const double simulationTime = ebosSimulator_.time();
|
const double simulationTime = ebosSimulator_.time();
|
||||||
int exception_thrown = 0;
|
int exception_thrown = 0;
|
||||||
@ -1227,7 +1227,7 @@ namespace Opm {
|
|||||||
// For no well active globally we simply return.
|
// For no well active globally we simply return.
|
||||||
if( !wellsActive() ) return ;
|
if( !wellsActive() ) return ;
|
||||||
|
|
||||||
updateAndCommunicateGroupData();
|
updateAndCommunicateGroupData(deferred_logger);
|
||||||
|
|
||||||
updateNetworkPressures();
|
updateNetworkPressures();
|
||||||
|
|
||||||
@ -1241,7 +1241,7 @@ namespace Opm {
|
|||||||
// Check group's constraints from higher levels.
|
// Check group's constraints from higher levels.
|
||||||
updateGroupHigherControls(deferred_logger, switched_groups);
|
updateGroupHigherControls(deferred_logger, switched_groups);
|
||||||
|
|
||||||
updateAndCommunicateGroupData();
|
updateAndCommunicateGroupData(deferred_logger);
|
||||||
|
|
||||||
// Check wells' group constraints and communicate.
|
// Check wells' group constraints and communicate.
|
||||||
for (const auto& well : well_container_) {
|
for (const auto& well : well_container_) {
|
||||||
@ -1251,7 +1251,7 @@ namespace Opm {
|
|||||||
switched_wells.insert(well->name());
|
switched_wells.insert(well->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateAndCommunicateGroupData();
|
updateAndCommunicateGroupData(deferred_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check individual well constraints and communicate.
|
// Check individual well constraints and communicate.
|
||||||
@ -1262,7 +1262,7 @@ namespace Opm {
|
|||||||
const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
|
const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
|
||||||
well->updateWellControl(ebosSimulator_, mode, well_state_, deferred_logger);
|
well->updateWellControl(ebosSimulator_, mode, well_state_, deferred_logger);
|
||||||
}
|
}
|
||||||
updateAndCommunicateGroupData();
|
updateAndCommunicateGroupData(deferred_logger);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1305,7 +1305,7 @@ namespace Opm {
|
|||||||
template<typename TypeTag>
|
template<typename TypeTag>
|
||||||
void
|
void
|
||||||
BlackoilWellModel<TypeTag>::
|
BlackoilWellModel<TypeTag>::
|
||||||
updateAndCommunicateGroupData()
|
updateAndCommunicateGroupData(Opm::DeferredLogger& deferred_logger)
|
||||||
{
|
{
|
||||||
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
const int reportStepIdx = ebosSimulator_.episodeIndex();
|
||||||
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
|
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
|
||||||
@ -1321,6 +1321,7 @@ namespace Opm {
|
|||||||
well_state_nupcol_ = well_state_;
|
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
|
// 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?
|
// Currently the group target reduction does not honor NUPCOL. TODO: is that true?
|
||||||
std::vector<double> groupTargetReduction(numPhases(), 0.0);
|
std::vector<double> groupTargetReduction(numPhases(), 0.0);
|
||||||
@ -1328,13 +1329,13 @@ namespace Opm {
|
|||||||
std::vector<double> groupTargetReductionInj(numPhases(), 0.0);
|
std::vector<double> groupTargetReductionInj(numPhases(), 0.0);
|
||||||
WellGroupHelpers::updateGroupTargetReduction(fieldGroup, schedule(), reportStepIdx, /*isInjector*/ true, phase_usage_, *guideRate_, well_state_nupcol_, well_state_, groupTargetReductionInj);
|
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();
|
const double simulationTime = ebosSimulator_.time();
|
||||||
std::vector<double> pot(numPhases(), 0.0);
|
std::vector<double> pot(numPhases(), 0.0);
|
||||||
WellGroupHelpers::updateGuideRateForGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, /*isInjector*/ false, well_state_, comm, guideRate_.get(), pot);
|
WellGroupHelpers::updateGuideRateForProductionGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get(), pot);
|
||||||
std::vector<double> potInj(numPhases(), 0.0);
|
WellGroupHelpers::updateGuideRatesForInjectionGroups(fieldGroup, schedule(), summaryState, phase_usage_, reportStepIdx, well_state_, guideRate_.get(), deferred_logger);
|
||||||
WellGroupHelpers::updateGuideRateForGroups(fieldGroup, schedule(), phase_usage_, reportStepIdx, simulationTime, /*isInjector*/ true, well_state_, comm, guideRate_.get(), potInj);
|
|
||||||
|
|
||||||
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
|
|
||||||
WellGroupHelpers::updateREINForGroups(fieldGroup, schedule(), reportStepIdx, phase_usage_, summaryState, well_state_nupcol_, well_state_);
|
WellGroupHelpers::updateREINForGroups(fieldGroup, schedule(), reportStepIdx, phase_usage_, summaryState, well_state_nupcol_, well_state_);
|
||||||
WellGroupHelpers::updateVREPForGroups(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
|
WellGroupHelpers::updateVREPForGroups(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
|
||||||
|
|
||||||
@ -2873,6 +2874,11 @@ namespace Opm {
|
|||||||
gr[gname].production = this->getGuideRateValues(group);
|
gr[gname].production = this->getGuideRateValues(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->guideRate_->has(gname, Opm::Phase::WATER)
|
||||||
|
|| this->guideRate_->has(gname, Opm::Phase::GAS)) {
|
||||||
|
gr[gname].injection = this->getGuideRateInjectionGroupValues(group);
|
||||||
|
}
|
||||||
|
|
||||||
const auto parent = group.parent();
|
const auto parent = group.parent();
|
||||||
if (parent == "FIELD") { continue; }
|
if (parent == "FIELD") { continue; }
|
||||||
|
|
||||||
@ -2951,12 +2957,32 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto qs = WellGroupHelpers::
|
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);
|
this->getGuideRateValues(qs, well.isInjector(), wname, grval);
|
||||||
|
|
||||||
return 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_->has(gname, Opm::Phase::GAS)) {
|
||||||
|
grval.set(data::GuideRateValue::Item::Gas,
|
||||||
|
this->guideRate_->get(gname, Opm::Phase::GAS));
|
||||||
|
}
|
||||||
|
if (this->guideRate_->has(gname, Opm::Phase::WATER)) {
|
||||||
|
grval.set(data::GuideRateValue::Item::Water,
|
||||||
|
this->guideRate_->get(gname, Opm::Phase::WATER));
|
||||||
|
}
|
||||||
|
return grval;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
data::GuideRateValue
|
data::GuideRateValue
|
||||||
@ -2968,8 +2994,9 @@ namespace Opm {
|
|||||||
assert (this->guideRate_ != nullptr);
|
assert (this->guideRate_ != nullptr);
|
||||||
|
|
||||||
const auto& gname = group.name();
|
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
|
// online (e.g., for the initial condition before simulation
|
||||||
// starts).
|
// starts).
|
||||||
return grval;
|
return grval;
|
||||||
@ -2981,7 +3008,7 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto qs = WellGroupHelpers::
|
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.
|
const auto is_inj = false; // This procedure only applies to G*PGR.
|
||||||
this->getGuideRateValues(qs, is_inj, gname, grval);
|
this->getGuideRateValues(qs, is_inj, gname, grval);
|
||||||
|
@ -163,6 +163,130 @@ namespace WellGroupHelpers
|
|||||||
const double group_grat_target_from_sales_;
|
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,
|
||||||
|
DeferredLogger& deferred_logger)
|
||||||
|
: 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:
|
||||||
|
OPM_DEFLOG_THROW(std::logic_error,
|
||||||
|
"Invalid injection phase in InjectionTargetCalculator",
|
||||||
|
deferred_logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename RateVec>
|
||||||
|
auto calcModeRateFromRates(const RateVec& rates) const
|
||||||
|
{
|
||||||
|
return rates[pos_];
|
||||||
|
}
|
||||||
|
|
||||||
|
double groupTarget(const Group::InjectionControls& ctrl, Opm::DeferredLogger& deferred_logger) 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:
|
||||||
|
OPM_DEFLOG_THROW(std::logic_error,
|
||||||
|
"Invalid Group::InjectionCMode in InjectionTargetCalculator",
|
||||||
|
deferred_logger);
|
||||||
|
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 WellGroupHelpers
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include <opm/simulators/wells/TargetCalculator.hpp>
|
#include <opm/simulators/wells/TargetCalculator.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSump.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSump.hpp>
|
||||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp>
|
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GConSale.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -227,6 +226,63 @@ namespace WellGroupHelpers
|
|||||||
return gefac * rate;
|
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,
|
||||||
|
Opm::DeferredLogger& deferred_logger)
|
||||||
|
{
|
||||||
|
for (const std::string& groupName : group.groups()) {
|
||||||
|
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
|
||||||
|
updateGuideRatesForInjectionGroups(
|
||||||
|
groupTmp, schedule, summaryState, pu, reportStepIdx, wellState, guideRate, deferred_logger);
|
||||||
|
}
|
||||||
|
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_DEFLOG_THROW(std::runtime_error, "GUIDE PHASE RESV not implemented. Group " + group.name(), deferred_logger);
|
||||||
|
case Group::GuideRateInjTarget::POTN:
|
||||||
|
break;
|
||||||
|
case Group::GuideRateInjTarget::NO_GUIDE_RATE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OPM_DEFLOG_THROW(std::logic_error,
|
||||||
|
"Invalid GuideRateInjTarget in updateGuideRatesForInjectionGroups",
|
||||||
|
deferred_logger);
|
||||||
|
}
|
||||||
|
guideRate->compute(group.name(), phase, reportStepIdx, guideRateValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateGroupTargetReduction(const Group& group,
|
void updateGroupTargetReduction(const Group& group,
|
||||||
const Schedule& schedule,
|
const Schedule& schedule,
|
||||||
const int reportStepIdx,
|
const int reportStepIdx,
|
||||||
@ -282,7 +338,7 @@ namespace WellGroupHelpers
|
|||||||
const bool individual_control = (currentGroupControl != Group::ProductionCMode::FLD
|
const bool individual_control = (currentGroupControl != Group::ProductionCMode::FLD
|
||||||
&& currentGroupControl != Group::ProductionCMode::NONE);
|
&& currentGroupControl != Group::ProductionCMode::NONE);
|
||||||
const int num_group_controlled_wells
|
const int num_group_controlled_wells
|
||||||
= groupControlledWells(schedule, wellStateNupcol, reportStepIdx, subGroupName, "");
|
= groupControlledWells(schedule, wellStateNupcol, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
|
||||||
if (individual_control || num_group_controlled_wells == 0) {
|
if (individual_control || num_group_controlled_wells == 0) {
|
||||||
for (int phase = 0; phase < np; phase++) {
|
for (int phase = 0; phase < np; phase++) {
|
||||||
groupTargetReduction[phase]
|
groupTargetReduction[phase]
|
||||||
@ -350,140 +406,6 @@ namespace WellGroupHelpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
const int np = pu.num_phases;
|
|
||||||
for (const std::string& groupName : group.groups()) {
|
|
||||||
std::vector<double> thisPot(np, 0.0);
|
|
||||||
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
|
|
||||||
updateGuideRateForGroups(groupTmp, schedule, pu, reportStepIdx, simTime, isInjector, 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) {
|
|
||||||
const Group::InjectionCMode& currentGroupControl = wellState.currentInjectionGroupControl(phase,
|
|
||||||
groupName); 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 &&
|
|
||||||
currentGroupControl != Group::ProductionCMode::NONE) { 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);
|
|
||||||
|
|
||||||
if (wellTmp.isProducer() && isInjector)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (wellTmp.isInjector() && !isInjector)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (wellTmp.getStatus() == Well::Status::SHUT)
|
|
||||||
continue;
|
|
||||||
const auto& end = wellState.wellMap().end();
|
|
||||||
const auto& it = wellState.wellMap().find( wellName );
|
|
||||||
if (it == end) // the well is not found
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int well_index = it->second[0];
|
|
||||||
|
|
||||||
if (! wellIsOwned(well_index, wellName, wellState) ) // Only sum once
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto wellrate_index = well_index * wellState.numPhases();
|
|
||||||
// add contribution from wells unconditionally
|
|
||||||
for (int phase = 0; phase < np; phase++) {
|
|
||||||
pot[phase] += wellState.wellPotentials()[wellrate_index + phase];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double oilPot = 0.0;
|
|
||||||
if (pu.phase_used[BlackoilPhases::Liquid])
|
|
||||||
oilPot = pot [ pu.phase_pos[BlackoilPhases::Liquid]];
|
|
||||||
|
|
||||||
double gasPot = 0.0;
|
|
||||||
if (pu.phase_used[BlackoilPhases::Vapour])
|
|
||||||
gasPot = pot [ pu.phase_pos[BlackoilPhases::Vapour]];
|
|
||||||
|
|
||||||
double waterPot = 0.0;
|
|
||||||
if (pu.phase_used[BlackoilPhases::Aqua])
|
|
||||||
waterPot = pot [pu.phase_pos[BlackoilPhases::Aqua]];
|
|
||||||
|
|
||||||
const double gefac = group.getGroupEfficiencyFactor();
|
|
||||||
|
|
||||||
oilPot = comm.sum(oilPot) * gefac;
|
|
||||||
gasPot = comm.sum(gasPot) * gefac;
|
|
||||||
waterPot = comm.sum(waterPot) * gefac;
|
|
||||||
|
|
||||||
if (isInjector) {
|
|
||||||
wellState.setCurrentGroupInjectionPotentials(group.name(), pot);
|
|
||||||
} else {
|
|
||||||
guideRate->compute(group.name(), reportStepIdx, simTime, oilPot, gasPot, waterPot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
template <class Comm>
|
|
||||||
void updateGuideRatesForWells(const Schedule& schedule, const PhaseUsage& pu, const int reportStepIdx, const
|
|
||||||
double& simTime, const WellStateFullyImplicitBlackoil& wellState, const Comm& comm, GuideRate* guideRate) {
|
|
||||||
|
|
||||||
const auto& end = wellState.wellMap().end();
|
|
||||||
for (const auto& well : schedule.getWells(reportStepIdx)) {
|
|
||||||
double oilpot = 0.0;
|
|
||||||
double gaspot = 0.0;
|
|
||||||
double waterpot = 0.0;
|
|
||||||
|
|
||||||
const auto& it = wellState.wellMap().find( well.name());
|
|
||||||
if (it != end && wellState.wellIsOwned(it->second[0], well.name()))
|
|
||||||
{
|
|
||||||
// the well is found and owned
|
|
||||||
|
|
||||||
const auto wpot = wellState.wellPotentials().data() + well_index*wellState.numPhases();
|
|
||||||
if (pu.phase_used[BlackoilPhases::Liquid] > 0)
|
|
||||||
oilpot = wpot[pu.phase_pos[BlackoilPhases::Liquid]];
|
|
||||||
|
|
||||||
if (pu.phase_used[BlackoilPhases::Vapour] > 0)
|
|
||||||
gaspot = wpot[pu.phase_pos[BlackoilPhases::Vapour]];
|
|
||||||
|
|
||||||
if (pu.phase_used[BlackoilPhases::Aqua] > 0)
|
|
||||||
waterpot = wpot[pu.phase_pos[BlackoilPhases::Aqua]];
|
|
||||||
|
|
||||||
const double wefac = well.getEfficiencyFactor();
|
|
||||||
}
|
|
||||||
oilpot = comm.sum(oilpot) * wefac;
|
|
||||||
gaspot = comm.sum(gaspot) * wefac;
|
|
||||||
waterpot = comm.sum(waterpot) * wefac;
|
|
||||||
guideRate->compute(well.name(), reportStepIdx, simTime, oilpot, gaspot, waterpot);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void updateVREPForGroups(const Group& group,
|
void updateVREPForGroups(const Group& group,
|
||||||
const Schedule& schedule,
|
const Schedule& schedule,
|
||||||
const int reportStepIdx,
|
const int reportStepIdx,
|
||||||
@ -582,6 +504,7 @@ namespace WellGroupHelpers
|
|||||||
wellState.setCurrentProductionGroupRates(group.name(), rates);
|
wellState.setCurrentProductionGroupRates(group.name(), rates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void updateREINForGroups(const Group& group,
|
void updateREINForGroups(const Group& group,
|
||||||
const Schedule& schedule,
|
const Schedule& schedule,
|
||||||
const int reportStepIdx,
|
const int reportStepIdx,
|
||||||
@ -738,7 +661,7 @@ namespace WellGroupHelpers
|
|||||||
|
|
||||||
|
|
||||||
GuideRate::RateVector
|
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);
|
return getGuideRateVector(well_state.currentWellRates(name), pu);
|
||||||
}
|
}
|
||||||
@ -757,8 +680,12 @@ namespace WellGroupHelpers
|
|||||||
const GuideRateModel::Target target,
|
const GuideRateModel::Target target,
|
||||||
const PhaseUsage& pu)
|
const PhaseUsage& pu)
|
||||||
{
|
{
|
||||||
if (schedule.hasWell(name, reportStepIdx) || guideRate->has(name)) {
|
if (schedule.hasWell(name, reportStepIdx)) {
|
||||||
return guideRate->get(name, target, getRateVector(wellState, pu, name));
|
return guideRate->get(name, target, getWellRateVector(wellState, pu, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guideRate->has(name)) {
|
||||||
|
return guideRate->get(name, target, getProductionGroupRateVector(wellState, pu, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
double totalGuideRate = 0.0;
|
double totalGuideRate = 0.0;
|
||||||
@ -786,7 +713,7 @@ namespace WellGroupHelpers
|
|||||||
if (!wellState.isProductionGrup(wellName))
|
if (!wellState.isProductionGrup(wellName))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
totalGuideRate += guideRate->get(wellName, target, getRateVector(wellState, pu, wellName));
|
totalGuideRate += guideRate->get(wellName, target, getWellRateVector(wellState, pu, wellName));
|
||||||
}
|
}
|
||||||
return totalGuideRate;
|
return totalGuideRate;
|
||||||
}
|
}
|
||||||
@ -802,7 +729,11 @@ namespace WellGroupHelpers
|
|||||||
const PhaseUsage& pu)
|
const PhaseUsage& pu)
|
||||||
{
|
{
|
||||||
if (schedule.hasWell(name, reportStepIdx)) {
|
if (schedule.hasWell(name, reportStepIdx)) {
|
||||||
return guideRate->get(name, target, getRateVector(wellState, pu, name));
|
return guideRate->get(name, target, getWellRateVector(wellState, pu, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guideRate->has(name, injectionPhase)) {
|
||||||
|
return guideRate->get(name, injectionPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
double totalGuideRate = 0.0;
|
double totalGuideRate = 0.0;
|
||||||
@ -832,7 +763,7 @@ namespace WellGroupHelpers
|
|||||||
if (!wellState.isInjectionGrup(wellName))
|
if (!wellState.isInjectionGrup(wellName))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
totalGuideRate += guideRate->get(wellName, target, getRateVector(wellState, pu, wellName));
|
totalGuideRate += guideRate->get(wellName, target, getWellRateVector(wellState, pu, wellName));
|
||||||
}
|
}
|
||||||
return totalGuideRate;
|
return totalGuideRate;
|
||||||
}
|
}
|
||||||
@ -843,21 +774,35 @@ namespace WellGroupHelpers
|
|||||||
const WellStateFullyImplicitBlackoil& well_state,
|
const WellStateFullyImplicitBlackoil& well_state,
|
||||||
const int report_step,
|
const int report_step,
|
||||||
const std::string& group_name,
|
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);
|
const Group& group = schedule.getGroup(group_name, report_step);
|
||||||
int num_wells = 0;
|
int num_wells = 0;
|
||||||
for (const std::string& child_group : group.groups()) {
|
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)
|
bool included = (child_group == always_included_child);
|
||||||
|| (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) {
|
if (included) {
|
||||||
num_wells
|
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()) {
|
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) {
|
if (included) {
|
||||||
++num_wells;
|
++num_wells;
|
||||||
}
|
}
|
||||||
@ -866,17 +811,23 @@ namespace WellGroupHelpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
FractionCalculator::FractionCalculator(const Schedule& schedule,
|
FractionCalculator::FractionCalculator(const Schedule& schedule,
|
||||||
|
const SummaryState& summary_state,
|
||||||
const WellStateFullyImplicitBlackoil& well_state,
|
const WellStateFullyImplicitBlackoil& well_state,
|
||||||
const int report_step,
|
const int report_step,
|
||||||
const GuideRate* guide_rate,
|
const GuideRate* guide_rate,
|
||||||
const GuideRateModel::Target target,
|
const GuideRateModel::Target target,
|
||||||
const PhaseUsage& pu)
|
const PhaseUsage& pu,
|
||||||
|
const bool is_producer,
|
||||||
|
const Phase injection_phase)
|
||||||
: schedule_(schedule)
|
: schedule_(schedule)
|
||||||
|
, summary_state_(summary_state)
|
||||||
, well_state_(well_state)
|
, well_state_(well_state)
|
||||||
, report_step_(report_step)
|
, report_step_(report_step)
|
||||||
, guide_rate_(guide_rate)
|
, guide_rate_(guide_rate)
|
||||||
, target_(target)
|
, target_(target)
|
||||||
, pu_(pu)
|
, pu_(pu)
|
||||||
|
, is_producer_(is_producer)
|
||||||
|
, injection_phase_(injection_phase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
double FractionCalculator::fraction(const std::string& name,
|
double FractionCalculator::fraction(const std::string& name,
|
||||||
@ -912,15 +863,26 @@ namespace WellGroupHelpers
|
|||||||
{
|
{
|
||||||
double total_guide_rate = 0.0;
|
double total_guide_rate = 0.0;
|
||||||
for (const std::string& child_group : group.groups()) {
|
for (const std::string& child_group : group.groups()) {
|
||||||
const auto ctrl = well_state_.currentProductionGroupControl(child_group);
|
bool included = (child_group == always_included_child);
|
||||||
const bool included = (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE)
|
if (is_producer_) {
|
||||||
|| (child_group == always_included_child);
|
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) {
|
if (included) {
|
||||||
total_guide_rate += guideRate(child_group, always_included_child);
|
total_guide_rate += guideRate(child_group, always_included_child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const std::string& child_well : group.wells()) {
|
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) {
|
if (included) {
|
||||||
total_guide_rate += guideRate(child_well, always_included_child);
|
total_guide_rate += guideRate(child_well, always_included_child);
|
||||||
}
|
}
|
||||||
@ -930,11 +892,13 @@ namespace WellGroupHelpers
|
|||||||
double FractionCalculator::guideRate(const std::string& name, const std::string& always_included_child)
|
double FractionCalculator::guideRate(const std::string& name, const std::string& always_included_child)
|
||||||
{
|
{
|
||||||
if (schedule_.hasWell(name, report_step_)) {
|
if (schedule_.hasWell(name, report_step_)) {
|
||||||
return guide_rate_->get(name, target_, getRateVector(well_state_, pu_, name));
|
return guide_rate_->get(name, target_, getWellRateVector(well_state_, pu_, name));
|
||||||
} else {
|
} else {
|
||||||
if (groupControlledWells(name, always_included_child) > 0) {
|
if (groupControlledWells(name, always_included_child) > 0) {
|
||||||
if (guide_rate_->has(name)) {
|
if (is_producer_ && guide_rate_->has(name)) {
|
||||||
return guide_rate_->get(name, target_, getGroupRateVector(name));
|
return guide_rate_->get(name, target_, getGroupRateVector(name));
|
||||||
|
} else if (!is_producer_ && guide_rate_->has(name, injection_phase_)) {
|
||||||
|
return guide_rate_->get(name, injection_phase_);
|
||||||
} else {
|
} else {
|
||||||
// We are a group, with default guide rate.
|
// We are a group, with default guide rate.
|
||||||
// Compute guide rate by accumulating our children's guide rates.
|
// Compute guide rate by accumulating our children's guide rates.
|
||||||
@ -951,250 +915,16 @@ namespace WellGroupHelpers
|
|||||||
const std::string& always_included_child)
|
const std::string& always_included_child)
|
||||||
{
|
{
|
||||||
return ::Opm::WellGroupHelpers::groupControlledWells(
|
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)
|
GuideRate::RateVector FractionCalculator::getGroupRateVector(const std::string& group_name)
|
||||||
{
|
{
|
||||||
|
assert(is_producer_);
|
||||||
return getProductionGroupRateVector(this->well_state_, this->pu_, group_name);
|
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>
|
std::vector<std::string>
|
||||||
groupChainTopBot(const std::string& bottom, const std::string& top, const Schedule& schedule, const int report_step)
|
groupChainTopBot(const std::string& bottom, const std::string& top, const Schedule& schedule, const int report_step)
|
||||||
{
|
{
|
||||||
@ -1286,7 +1016,7 @@ namespace WellGroupHelpers
|
|||||||
gratTargetFromSales = wellState.currentGroupGratTargetFromSales(group.name());
|
gratTargetFromSales = wellState.currentGroupGratTargetFromSales(group.name());
|
||||||
|
|
||||||
TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
|
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); };
|
auto localFraction = [&](const std::string& child) { return fcalc.localFraction(child, name); };
|
||||||
|
|
||||||
@ -1333,7 +1063,7 @@ namespace WellGroupHelpers
|
|||||||
// the current well to be always included, because we
|
// the current well to be always included, because we
|
||||||
// want to know the situation that applied to the
|
// want to know the situation that applied to the
|
||||||
// calculation of reductions.
|
// 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], "", /*is_producer*/true, /*injectionPhaseNotUsed*/Phase::OIL);
|
||||||
if (num_gr_ctrl == 0) {
|
if (num_gr_ctrl == 0) {
|
||||||
if (guideRate->has(chain[ii + 1])) {
|
if (guideRate->has(chain[ii + 1])) {
|
||||||
target += localReduction(chain[ii + 1]);
|
target += localReduction(chain[ii + 1]);
|
||||||
@ -1347,6 +1077,130 @@ namespace WellGroupHelpers
|
|||||||
return std::make_pair(current_rate > target_rate, target_rate / current_rate);
|
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, deferred_logger);
|
||||||
|
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), deferred_logger);
|
||||||
|
// 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->has(chain[ii], injectionPhase)) {
|
||||||
|
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->has(chain[ii], injectionPhase)) {
|
||||||
|
// 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], "", /*is_producer*/false, injectionPhase);
|
||||||
|
if (num_gr_ctrl == 0) {
|
||||||
|
if (guideRate->has(chain[ii + 1], injectionPhase)) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace WellGroupHelpers
|
} // namespace WellGroupHelpers
|
||||||
|
|
||||||
|
@ -95,16 +95,15 @@ namespace WellGroupHelpers
|
|||||||
std::vector<double>& groupTargetReduction);
|
std::vector<double>& groupTargetReduction);
|
||||||
|
|
||||||
template <class Comm>
|
template <class Comm>
|
||||||
void updateGuideRateForGroups(const Group& group,
|
void updateGuideRateForProductionGroups(const Group& group,
|
||||||
const Schedule& schedule,
|
const Schedule& schedule,
|
||||||
const PhaseUsage& pu,
|
const PhaseUsage& pu,
|
||||||
const int reportStepIdx,
|
const int reportStepIdx,
|
||||||
const double& simTime,
|
const double& simTime,
|
||||||
const bool isInjector,
|
WellStateFullyImplicitBlackoil& wellState,
|
||||||
WellStateFullyImplicitBlackoil& wellState,
|
const Comm& comm,
|
||||||
const Comm& comm,
|
GuideRate* guideRate,
|
||||||
GuideRate* guideRate,
|
std::vector<double>& pot)
|
||||||
std::vector<double>& pot)
|
|
||||||
{
|
{
|
||||||
const int np = pu.num_phases;
|
const int np = pu.num_phases;
|
||||||
for (const std::string& groupName : group.groups()) {
|
for (const std::string& groupName : group.groups()) {
|
||||||
@ -112,44 +111,25 @@ namespace WellGroupHelpers
|
|||||||
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
|
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
|
||||||
|
|
||||||
// Note that group effiency factors for groupTmp are applied in updateGuideRateForGroups
|
// Note that group effiency factors for groupTmp are applied in updateGuideRateForGroups
|
||||||
updateGuideRateForGroups(
|
updateGuideRateForProductionGroups(
|
||||||
groupTmp, schedule, pu, reportStepIdx, simTime, isInjector, wellState, comm, guideRate, thisPot);
|
groupTmp, schedule, pu, reportStepIdx, simTime, wellState, comm, guideRate, thisPot);
|
||||||
|
|
||||||
// accumulate group contribution from sub group unconditionally
|
// accumulate group contribution from sub group unconditionally
|
||||||
if (isInjector) {
|
const Group::ProductionCMode& currentGroupControl = wellState.currentProductionGroupControl(groupName);
|
||||||
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
|
if (currentGroupControl != Group::ProductionCMode::FLD
|
||||||
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
|
|
||||||
&& currentGroupControl != Group::ProductionCMode::NONE) {
|
&& currentGroupControl != Group::ProductionCMode::NONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
for (int phase = 0; phase < np; phase++) {
|
|
||||||
pot[phase] += thisPot[phase];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (int phase = 0; phase < np; phase++) {
|
||||||
|
pot[phase] += thisPot[phase];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for (const std::string& wellName : group.wells()) {
|
for (const std::string& wellName : group.wells()) {
|
||||||
const auto& wellTmp = schedule.getWell(wellName, reportStepIdx);
|
const auto& wellTmp = schedule.getWell(wellName, reportStepIdx);
|
||||||
const auto wefac = wellTmp.getEfficiencyFactor();
|
const auto wefac = wellTmp.getEfficiencyFactor();
|
||||||
|
|
||||||
if (wellTmp.isProducer() && isInjector)
|
if (wellTmp.isInjector())
|
||||||
continue;
|
|
||||||
|
|
||||||
if (wellTmp.isInjector() && !isInjector)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (wellTmp.getStatus() == Well::Status::SHUT)
|
if (wellTmp.getStatus() == Well::Status::SHUT)
|
||||||
@ -195,12 +175,7 @@ namespace WellGroupHelpers
|
|||||||
oilPot = comm.sum(oilPot);
|
oilPot = comm.sum(oilPot);
|
||||||
gasPot = comm.sum(gasPot);
|
gasPot = comm.sum(gasPot);
|
||||||
waterPot = comm.sum(waterPot);
|
waterPot = comm.sum(waterPot);
|
||||||
|
guideRate->compute(group.name(), reportStepIdx, simTime, oilPot, gasPot, waterPot);
|
||||||
if (isInjector) {
|
|
||||||
wellState.setCurrentGroupInjectionPotentials(group.name(), pot);
|
|
||||||
} else {
|
|
||||||
guideRate->compute(group.name(), reportStepIdx, simTime, oilPot, gasPot, waterPot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Comm>
|
template <class Comm>
|
||||||
@ -242,6 +217,14 @@ namespace WellGroupHelpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateGuideRatesForInjectionGroups(const Group& group,
|
||||||
|
const Schedule& schedule,
|
||||||
|
const SummaryState& summaryState,
|
||||||
|
const Opm::PhaseUsage& pu,
|
||||||
|
const int reportStepIdx,
|
||||||
|
const WellStateFullyImplicitBlackoil& wellState,
|
||||||
|
GuideRate* guideRate,
|
||||||
|
Opm::DeferredLogger& deferred_logger);
|
||||||
|
|
||||||
void updateVREPForGroups(const Group& group,
|
void updateVREPForGroups(const Group& group,
|
||||||
const Schedule& schedule,
|
const Schedule& schedule,
|
||||||
@ -283,7 +266,7 @@ namespace WellGroupHelpers
|
|||||||
const int report_time_step);
|
const int report_time_step);
|
||||||
|
|
||||||
GuideRate::RateVector
|
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
|
GuideRate::RateVector
|
||||||
getProductionGroupRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& group_name);
|
getProductionGroupRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& group_name);
|
||||||
@ -310,18 +293,23 @@ namespace WellGroupHelpers
|
|||||||
const WellStateFullyImplicitBlackoil& well_state,
|
const WellStateFullyImplicitBlackoil& well_state,
|
||||||
const int report_step,
|
const int report_step,
|
||||||
const std::string& group_name,
|
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
|
class FractionCalculator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FractionCalculator(const Schedule& schedule,
|
FractionCalculator(const Schedule& schedule,
|
||||||
|
const SummaryState& summary_state,
|
||||||
const WellStateFullyImplicitBlackoil& well_state,
|
const WellStateFullyImplicitBlackoil& well_state,
|
||||||
const int report_step,
|
const int report_step,
|
||||||
const GuideRate* guide_rate,
|
const GuideRate* guide_rate,
|
||||||
const GuideRateModel::Target target,
|
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 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);
|
double localFraction(const std::string& name, const std::string& always_included_child);
|
||||||
|
|
||||||
@ -332,36 +320,17 @@ namespace WellGroupHelpers
|
|||||||
int groupControlledWells(const std::string& group_name, const std::string& always_included_child);
|
int groupControlledWells(const std::string& group_name, const std::string& always_included_child);
|
||||||
GuideRate::RateVector getGroupRateVector(const std::string& group_name);
|
GuideRate::RateVector getGroupRateVector(const std::string& group_name);
|
||||||
const Schedule& schedule_;
|
const Schedule& schedule_;
|
||||||
|
const SummaryState& summary_state_;
|
||||||
const WellStateFullyImplicitBlackoil& well_state_;
|
const WellStateFullyImplicitBlackoil& well_state_;
|
||||||
int report_step_;
|
int report_step_;
|
||||||
const GuideRate* guide_rate_;
|
const GuideRate* guide_rate_;
|
||||||
GuideRateModel::Target target_;
|
GuideRateModel::Target target_;
|
||||||
PhaseUsage pu_;
|
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,
|
std::pair<bool, double> checkGroupConstraintsInj(const std::string& name,
|
||||||
const std::string& parent,
|
const std::string& parent,
|
||||||
const Group& group,
|
const Group& group,
|
||||||
|
@ -597,7 +597,8 @@ namespace Opm
|
|||||||
const EvalWell& bhp,
|
const EvalWell& bhp,
|
||||||
const EvalWell& injection_rate,
|
const EvalWell& injection_rate,
|
||||||
EvalWell& control_eq,
|
EvalWell& control_eq,
|
||||||
double efficiencyFactor);
|
double efficiencyFactor,
|
||||||
|
Opm::DeferredLogger& deferred_logger);
|
||||||
|
|
||||||
template <class EvalWell>
|
template <class EvalWell>
|
||||||
void getGroupProductionControl(const Group& group,
|
void getGroupProductionControl(const Group& group,
|
||||||
|
@ -2016,7 +2016,8 @@ namespace Opm
|
|||||||
bhp,
|
bhp,
|
||||||
injection_rate,
|
injection_rate,
|
||||||
control_eq,
|
control_eq,
|
||||||
efficiencyFactor);
|
efficiencyFactor,
|
||||||
|
deferred_logger);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Well::InjectorCMode::CMODE_UNDEFINED: {
|
case Well::InjectorCMode::CMODE_UNDEFINED: {
|
||||||
@ -2142,47 +2143,36 @@ namespace Opm
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename TypeTag>
|
template <typename TypeTag>
|
||||||
template <class EvalWell>
|
template <class EvalWell>
|
||||||
void
|
void
|
||||||
WellInterface<TypeTag>::getGroupInjectionControl(const Group& group,
|
WellInterface<TypeTag>::getGroupInjectionControl(const Group& group,
|
||||||
const WellState& well_state,
|
const WellState& well_state,
|
||||||
const Opm::Schedule& schedule,
|
const Opm::Schedule& schedule,
|
||||||
const SummaryState& summaryState,
|
const SummaryState& summaryState,
|
||||||
const InjectorType& injectorType,
|
const InjectorType& injectorType,
|
||||||
const EvalWell& bhp,
|
const EvalWell& bhp,
|
||||||
const EvalWell& injection_rate,
|
const EvalWell& injection_rate,
|
||||||
EvalWell& control_eq,
|
EvalWell& control_eq,
|
||||||
double efficiencyFactor)
|
double efficiencyFactor,
|
||||||
|
Opm::DeferredLogger& deferred_logger)
|
||||||
{
|
{
|
||||||
const auto& well = well_ecl_;
|
|
||||||
const auto pu = phaseUsage();
|
|
||||||
|
|
||||||
// Setting some defaults to silence warnings below.
|
// Setting some defaults to silence warnings below.
|
||||||
// Will be overwritten in the switch statement.
|
// Will be overwritten in the switch statement.
|
||||||
int phasePos = -1;
|
|
||||||
Well::GuideRateTarget wellTarget = Well::GuideRateTarget::UNDEFINED;
|
|
||||||
Phase injectionPhase = Phase::WATER;
|
Phase injectionPhase = Phase::WATER;
|
||||||
switch (injectorType) {
|
switch (injectorType) {
|
||||||
case InjectorType::WATER:
|
case InjectorType::WATER:
|
||||||
{
|
{
|
||||||
phasePos = pu.phase_pos[BlackoilPhases::Aqua];
|
|
||||||
wellTarget = Well::GuideRateTarget::WAT;
|
|
||||||
injectionPhase = Phase::WATER;
|
injectionPhase = Phase::WATER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InjectorType::OIL:
|
case InjectorType::OIL:
|
||||||
{
|
{
|
||||||
phasePos = pu.phase_pos[BlackoilPhases::Liquid];
|
|
||||||
wellTarget = Well::GuideRateTarget::OIL;
|
|
||||||
injectionPhase = Phase::OIL;
|
injectionPhase = Phase::OIL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InjectorType::GAS:
|
case InjectorType::GAS:
|
||||||
{
|
{
|
||||||
phasePos = pu.phase_pos[BlackoilPhases::Vapour];
|
|
||||||
wellTarget = Well::GuideRateTarget::GAS;
|
|
||||||
injectionPhase = Phase::GAS;
|
injectionPhase = Phase::GAS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2192,7 +2182,6 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Group::InjectionCMode& currentGroupControl = well_state.currentInjectionGroupControl(injectionPhase, group.name());
|
const Group::InjectionCMode& currentGroupControl = well_state.currentInjectionGroupControl(injectionPhase, group.name());
|
||||||
|
|
||||||
if (currentGroupControl == Group::InjectionCMode::FLD ||
|
if (currentGroupControl == Group::InjectionCMode::FLD ||
|
||||||
currentGroupControl == Group::InjectionCMode::NONE) {
|
currentGroupControl == Group::InjectionCMode::NONE) {
|
||||||
if (!group.injectionGroupControlAvailable(injectionPhase)) {
|
if (!group.injectionGroupControlAvailable(injectionPhase)) {
|
||||||
@ -2211,109 +2200,68 @@ namespace Opm
|
|||||||
// Inject share of parents control
|
// Inject share of parents control
|
||||||
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
|
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
|
||||||
efficiencyFactor *= group.getGroupEfficiencyFactor();
|
efficiencyFactor *= group.getGroupEfficiencyFactor();
|
||||||
getGroupInjectionControl(parent, well_state, schedule, summaryState, injectorType, bhp, injection_rate, control_eq, efficiencyFactor);
|
getGroupInjectionControl(parent, well_state, schedule, summaryState, injectorType, bhp, injection_rate, control_eq, efficiencyFactor, deferred_logger);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
efficiencyFactor *= group.getGroupEfficiencyFactor();
|
efficiencyFactor *= group.getGroupEfficiencyFactor();
|
||||||
assert(group.hasInjectionControl(injectionPhase));
|
const auto& well = well_ecl_;
|
||||||
const auto& groupcontrols = group.injectionControls(injectionPhase, summaryState);
|
const auto pu = phaseUsage();
|
||||||
|
|
||||||
const std::vector<double>& groupInjectionReductions = well_state.currentInjectionGroupReductionRates(group.name());
|
if (!group.isInjectionGroup()) {
|
||||||
double groupTargetReduction = groupInjectionReductions[phasePos];
|
// use bhp as control eq and let the updateControl code find a valid control
|
||||||
double fraction = WellGroupHelpers::fractionFromInjectionPotentials(well.name(),
|
const auto& controls = well.injectionControls(summaryState);
|
||||||
group.name(),
|
control_eq = bhp - controls.bhp_limit;
|
||||||
schedule,
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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;
|
// If we are here, we are at the topmost group to be visited in the recursion.
|
||||||
std::vector<double> groupInjectionReservoirRates = well_state.currentInjectionGroupReservoirRates(group.name());
|
// This is the group containing the control we will check against.
|
||||||
if (groupcontrols.phase != Phase::WATER)
|
|
||||||
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Aqua]];
|
|
||||||
|
|
||||||
if (groupcontrols.phase != Phase::OIL)
|
// Make conversion factors for RESV <-> surface rates.
|
||||||
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Liquid]];
|
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)
|
double sales_target = 0;
|
||||||
injReduction += groupInjectionReservoirRates[pu.phase_pos[BlackoilPhases::Vapour]];
|
if (schedule[current_step_].gconsale().has(group.name())) {
|
||||||
|
|
||||||
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];
|
|
||||||
const auto& gconsale = schedule[current_step_].gconsale().get(group.name(), summaryState);
|
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, deferred_logger);
|
||||||
|
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;
|
auto localFraction = [&](const std::string& child) {
|
||||||
control_eq = injection_rate - fraction * target;
|
return fcalc.localFraction(child, "");
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
// default:
|
auto localReduction = [&](const std::string& group_name) {
|
||||||
// OPM_DEFLOG_THROW(std::runtime_error, "Unvalid group control specified for group " + well.groupName(), deferred_logger );
|
const std::vector<double>& groupTargetReductions = well_state.currentInjectionGroupReductionRates(group_name);
|
||||||
|
return tcalc.calcModeRateFromRates(groupTargetReductions);
|
||||||
|
};
|
||||||
|
|
||||||
|
const double orig_target = tcalc.groupTarget(group.injectionControls(injectionPhase, summaryState), deferred_logger);
|
||||||
|
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_->has(chain[ii], injectionPhase)) {
|
||||||
|
// 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 <typename TypeTag>
|
||||||
template <class EvalWell>
|
template <class EvalWell>
|
||||||
void
|
void
|
||||||
@ -2375,7 +2323,7 @@ namespace Opm
|
|||||||
gratTargetFromSales = well_state.currentGroupGratTargetFromSales(group.name());
|
gratTargetFromSales = well_state.currentGroupGratTargetFromSales(group.name());
|
||||||
|
|
||||||
WellGroupHelpers::TargetCalculator tcalc(currentGroupControl, pu, resv_coeff, gratTargetFromSales);
|
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) {
|
auto localFraction = [&](const std::string& child) {
|
||||||
return fcalc.localFraction(child, "");
|
return fcalc.localFraction(child, "");
|
||||||
|
@ -449,6 +449,7 @@ namespace Opm
|
|||||||
return this->production_group_rates.find(groupName) != this->production_group_rates.end();
|
return this->production_group_rates.find(groupName) != this->production_group_rates.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setCurrentProductionGroupReductionRates(const std::string& groupName, const std::vector<double>& target ) {
|
void setCurrentProductionGroupReductionRates(const std::string& groupName, const std::vector<double>& target ) {
|
||||||
production_group_reduction_rates[groupName] = target;
|
production_group_reduction_rates[groupName] = target;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user