Handle guide-rate based well constraints from groups.

This commit is contained in:
Atgeirr Flø Rasmussen 2020-02-10 15:16:09 +01:00
parent 202235abe0
commit 27f62399f5
8 changed files with 1369 additions and 376 deletions

View File

@ -348,7 +348,9 @@ namespace Opm {
// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const BVector& x);
void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControl, const bool checkCurrentGroupControl);
void updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls);
void updateAndCommunicateGroupData();
// setting the well_solutions_ based on well_state.
void updatePrimaryVariables(Opm::DeferredLogger& deferred_logger);
@ -421,7 +423,10 @@ namespace Opm {
const Well& getWellEcl(const std::string& well_name) const;
void checkGroupConstraints(const Group& group, const bool checkCurrentControl, Opm::DeferredLogger& deferred_logger);
void updateGroupIndividualControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
void checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
void updateGroupHigherControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
void checkGroupHigherConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
void actionOnBrokenConstraints(const Group& group, const Group::ExceedAction& exceed_action, const Group::ProductionCMode& newControl, const int reportStepIdx, Opm::DeferredLogger& deferred_logger);

View File

@ -381,7 +381,7 @@ namespace Opm {
//compute well guideRates
const auto& comm = ebosSimulator_.vanguard().grid().comm();
wellGroupHelpers::updateGuideRatesForWells(schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get());
wellGroupHelpers::updateGuideRatesForWells(schedule(), phase_usage_, reportStepIdx, simulationTime, well_state_, comm, guideRate_.get());
}
@ -820,11 +820,7 @@ namespace Opm {
calculateExplicitQuantities(local_deferredLogger);
prepareTimeStep(local_deferredLogger);
}
// check the current group control in the beginning of an episode for the first two iterations. The first itertion is needed for changes in group/well controls and closing of wells etc.
// a second check is needed for REIN and VREP controls since they depend on results from other wells.
// This check can probably be made more sofisticated, but this simple rule seems to work
bool checkCurrentGroupControls = (report_step_starts_ && iterationIdx < 2);
updateWellControls(local_deferredLogger, /*allow for switching to group controls*/true, checkCurrentGroupControls);
updateWellControls(local_deferredLogger, /* check group controls */ true);
// Set the well primary variables based on the value of well solutions
initPrimaryVariablesEvaluation();
@ -1065,7 +1061,7 @@ namespace Opm {
// are active wells anywhere in the global domain.
if( wellsActive() )
{
updateWellControls(deferred_logger, /*don't switch group controls*/false, /*don't check current group controls*/false);
updateWellControls(deferred_logger, /*don't switch group controls*/false);
initPrimaryVariablesEvaluation();
}
} catch (std::exception& e) {
@ -1162,41 +1158,80 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControl, const bool checkCurrentGroupControl)
updateWellControls(Opm::DeferredLogger& deferred_logger, const bool checkGroupControls)
{
// Even if there are no wells active locally, we cannot
// return as the DeferredLogger uses global communication.
// For no well active globally we simply return.
if( !wellsActive() ) return ;
updateAndCommunicateGroupData();
std::set<std::string> switched_wells;
std::set<std::string> switched_groups;
if (checkGroupControls) {
// Check group individual constraints.
updateGroupIndividualControls(deferred_logger, switched_groups);
// Check group's constraints from higher levels.
updateGroupHigherControls(deferred_logger, switched_groups);
updateAndCommunicateGroupData();
// Check wells' group constraints and communicate.
for (const auto& well : well_container_) {
const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Group;
const bool changed = well->updateWellControl(ebosSimulator_, mode, well_state_, deferred_logger);
if (changed) {
switched_wells.insert(well->name());
}
}
updateAndCommunicateGroupData();
}
// Check individual well constraints and communicate.
for (const auto& well : well_container_) {
if (switched_wells.count(well->name())) {
continue;
}
const auto mode = WellInterface<TypeTag>::IndividualOrGroup::Individual;
well->updateWellControl(ebosSimulator_, mode, well_state_, deferred_logger);
}
updateAndCommunicateGroupData();
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateAndCommunicateGroupData()
{
const int reportStepIdx = ebosSimulator_.episodeIndex();
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
// update group controls
if (checkGroupControl) {
checkGroupConstraints(fieldGroup, checkCurrentGroupControl, deferred_logger);
}
for (const auto& well : well_container_) {
well->updateWellControl(ebosSimulator_, well_state_, deferred_logger);
}
const int nupcol = schedule().getNupcol(reportStepIdx);
const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations();
// This builds some necessary lookup structures, so it must be called
// before we copy to well_state_nupcol_.
const auto& comm = ebosSimulator_.vanguard().grid().comm();
well_state_.updateGlobalIsGrup(schedule(), reportStepIdx, comm);
if (iterationIdx < nupcol) {
well_state_nupcol_ = well_state_;
}
// the group target reduction rates needs to be update since wells may have swicthed to/from GRUP control
// Currently the group targer reduction does not honor NUPCOL
// Currently the group target reduction does not honor NUPCOL. TODO: is that true?
std::vector<double> groupTargetReduction(numPhases(), 0.0);
wellGroupHelpers::updateGroupTargetReduction(fieldGroup, schedule(), reportStepIdx, /*isInjector*/ false, phase_usage_, well_state_nupcol_, well_state_, groupTargetReduction);
std::vector<double> groupTargetReductionInj(numPhases(), 0.0);
wellGroupHelpers::updateGroupTargetReduction(fieldGroup, schedule(), reportStepIdx, /*isInjector*/ true, phase_usage_, well_state_nupcol_, well_state_, groupTargetReductionInj);
const auto& comm = ebosSimulator_.vanguard().grid().comm();
well_state_.updateGlobalIsGrup(schedule(), reportStepIdx, comm);
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);
@ -1268,7 +1303,7 @@ namespace Opm {
summaryConfig.hasSummaryKey( "WGPP:" + well->name())) && well->isProducer());
const Well& eclWell = well->wellEcl();
bool needPotentialsForGuideRate = eclWell.getGuideRatePhase() == Well::GuideRateTarget::UNDEFINED;
bool needPotentialsForGuideRate = true;//eclWell.getGuideRatePhase() == Well::GuideRateTarget::UNDEFINED;
if (write_restart_file || needed_for_summary || needPotentialsForGuideRate)
{
std::vector<double> potentials;
@ -1692,17 +1727,35 @@ namespace Opm {
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
checkGroupConstraints(const Group& group, const bool checkCurrentControl, Opm::DeferredLogger& deferred_logger) {
updateGroupIndividualControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups)
{
const int reportStepIdx = ebosSimulator_.episodeIndex();
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
checkGroupConstraints(fieldGroup, deferred_logger, switched_groups);
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups) {
const int reportStepIdx = ebosSimulator_.episodeIndex();
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
const auto& comm = ebosSimulator_.vanguard().grid().comm();
auto& well_state = well_state_;
if (group.isInjectionGroup())
const bool skip = switched_groups.count(group.name());
if (!skip && group.isInjectionGroup())
{
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
@ -1725,7 +1778,7 @@ namespace Opm {
if (controls.has_control(Group::InjectionCMode::RATE))
{
if (checkCurrentControl || currentControl != Group::InjectionCMode::RATE)
if (currentControl != Group::InjectionCMode::RATE)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/true);
@ -1734,13 +1787,14 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.surface_max_rate < current_rate) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::RATE, phase, reportStepIdx, deferred_logger);
}
}
}
if (controls.has_control(Group::InjectionCMode::RESV))
{
if (checkCurrentControl || currentControl != Group::InjectionCMode::RESV)
if (currentControl != Group::InjectionCMode::RESV)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/true);
@ -1748,13 +1802,14 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.resv_max_rate < current_rate) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::RESV, phase, reportStepIdx, deferred_logger);
}
}
}
if (controls.has_control(Group::InjectionCMode::REIN))
{
if (checkCurrentControl || currentControl != Group::InjectionCMode::REIN)
if (currentControl != Group::InjectionCMode::REIN)
{
double production_Rate = 0.0;
const Group& groupRein = schedule().getGroup(controls.reinj_group, reportStepIdx);
@ -1770,13 +1825,14 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.target_reinj_fraction*production_Rate < current_rate) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::REIN, phase,reportStepIdx, deferred_logger);
}
}
}
if (controls.has_control(Group::InjectionCMode::VREP))
{
if (checkCurrentControl || currentControl != Group::InjectionCMode::VREP)
if (currentControl != Group::InjectionCMode::VREP)
{
double voidage_rate = 0.0;
const Group& groupVoidage = schedule().getGroup(controls.voidage_group, reportStepIdx);
@ -1796,6 +1852,7 @@ namespace Opm {
total_rate = comm.sum(total_rate);
if (controls.target_void_fraction*voidage_rate < total_rate) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::VREP, phase, reportStepIdx, deferred_logger);
}
}
@ -1838,13 +1895,13 @@ namespace Opm {
}
}
if (group.isProductionGroup()) {
if (!skip && group.isProductionGroup()) {
const auto controls = group.productionControls(summaryState);
const Group::ProductionCMode& currentControl = well_state.currentProductionGroupControl(group.name());
if (group.has_control(Group::ProductionCMode::ORAT))
{
if (checkCurrentControl || currentControl != Group::ProductionCMode::ORAT)
if (currentControl != Group::ProductionCMode::ORAT)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], false);
@ -1853,6 +1910,7 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.oil_target < current_rate ) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, Group::ProductionCMode::ORAT, reportStepIdx, deferred_logger);
}
}
@ -1860,7 +1918,7 @@ namespace Opm {
if (group.has_control(Group::ProductionCMode::WRAT))
{
if (checkCurrentControl || currentControl != Group::ProductionCMode::WRAT)
if (currentControl != Group::ProductionCMode::WRAT)
{
double current_rate = 0.0;
@ -1870,13 +1928,14 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.water_target < current_rate ) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, Group::ProductionCMode::WRAT, reportStepIdx, deferred_logger);
}
}
}
if (group.has_control(Group::ProductionCMode::GRAT))
{
if (checkCurrentControl || currentControl != Group::ProductionCMode::GRAT)
if (currentControl != Group::ProductionCMode::GRAT)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], false);
@ -1884,13 +1943,14 @@ namespace Opm {
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.gas_target < current_rate ) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, Group::ProductionCMode::GRAT, reportStepIdx, deferred_logger);
}
}
}
if (group.has_control(Group::ProductionCMode::LRAT))
{
if (checkCurrentControl || currentControl != Group::ProductionCMode::LRAT)
if (currentControl != Group::ProductionCMode::LRAT)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], false);
@ -1900,6 +1960,7 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.liquid_target < current_rate ) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, Group::ProductionCMode::LRAT, reportStepIdx, deferred_logger);
}
}
@ -1912,7 +1973,7 @@ namespace Opm {
}
if (group.has_control(Group::ProductionCMode::RESV))
{
if (checkCurrentControl || currentControl != Group::ProductionCMode::RESV)
if (currentControl != Group::ProductionCMode::RESV)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], true);
@ -1923,6 +1984,7 @@ namespace Opm {
current_rate = comm.sum(current_rate);
if (controls.resv_target < current_rate ) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, Group::ProductionCMode::RESV, reportStepIdx, deferred_logger);
}
}
@ -1940,7 +2002,7 @@ namespace Opm {
// call recursively down the group hiearchy
for (const std::string& groupName : group.groups()) {
checkGroupConstraints( schedule().getGroup(groupName, reportStepIdx), checkCurrentControl, deferred_logger);
checkGroupConstraints( schedule().getGroup(groupName, reportStepIdx), deferred_logger, switched_groups);
}
@ -1984,9 +2046,6 @@ namespace Opm {
well_state.setCurrentProductionGroupControl(group.name(), newControl);
ss << "Switching control mode for group "<< group.name() << " to " << Group::ProductionCMode2String(newControl);
}
// Pass a dummy phase for producer groups. The topUpPhase is only relevant for injector groups
const Phase topUpPhase = Phase::WATER;
wellGroupHelpers::setGroupControl(group, schedule(), topUpPhase, reportStepIdx, false, well_state, ss);
break;
}
default:
@ -2023,13 +2082,128 @@ namespace Opm {
}
well_state.setCurrentInjectionGroupControl(controlPhase, group.name(), newControl);
}
wellGroupHelpers::setGroupControl(group, schedule(), controlPhase, reportStepIdx, /*isInjector*/true, well_state, ss);
if (!ss.str().empty())
deferred_logger.info(ss.str());
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateGroupHigherControls(Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups)
{
const int reportStepIdx = ebosSimulator_.episodeIndex();
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
checkGroupHigherConstraints(fieldGroup, deferred_logger, switched_groups);
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
checkGroupHigherConstraints(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups)
{
// Use the pvtRegionIdx from the top cell of the first well.
// TODO fix this!
// This is only used for converting RESV rates.
// What is the proper approach?
const int pvtreg = well_perf_data_.empty()
? pvt_region_idx_[0]
: pvt_region_idx_[well_perf_data_[0][0].cell_index];
const int reportStepIdx = ebosSimulator_.episodeIndex();
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
std::vector<double> rates(phase_usage_.num_phases, 0.0);
const auto& comm = ebosSimulator_.vanguard().grid().comm();
const bool skip = switched_groups.count(group.name());
if (!skip && group.isInjectionGroup()) {
// Obtain rates for group.
for (int phasePos = 0; phasePos < phase_usage_.num_phases; ++phasePos) {
const double local_current_rate = wellGroupHelpers::sumWellRates(
group, schedule(), well_state_, reportStepIdx, phasePos, /* isInjector */ true);
// Sum over all processes
rates[phasePos] = comm.sum(local_current_rate);
}
const Phase all[] = { Phase::WATER, Phase::OIL, Phase::GAS };
for (Phase phase : all) {
// Check higher up only if under individual (not FLD) control.
const Group::InjectionCMode& currentControl = well_state_.currentInjectionGroupControl(phase, group.name());
if (currentControl != Group::InjectionCMode::FLD) {
const Group& parentGroup = schedule().getGroup(group.parent(), reportStepIdx);
const bool changed = wellGroupHelpers::checkGroupConstraintsInj(
group.name(),
group.parent(),
parentGroup,
well_state_,
reportStepIdx,
guideRate_.get(),
rates.data(),
phase,
phase_usage_,
group.getGroupEfficiencyFactor(),
schedule(),
summaryState,
*rateConverter_,
pvtreg,
deferred_logger);
if (changed) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::FLD, phase, reportStepIdx, deferred_logger);
}
}
}
}
if (!skip && group.isProductionGroup()) {
// Obtain rates for group.
for (int phasePos = 0; phasePos < phase_usage_.num_phases; ++phasePos) {
const double local_current_rate = wellGroupHelpers::sumWellRates(
group, schedule(), well_state_, reportStepIdx, phasePos, /* isInjector */ false);
// Sum over all processes
rates[phasePos] = -comm.sum(local_current_rate);
}
// Check higher up only if under individual (not FLD) control.
const Group::ProductionCMode& currentControl = well_state_.currentProductionGroupControl(group.name());
if (currentControl != Group::ProductionCMode::FLD) {
const Group& parentGroup = schedule().getGroup(group.parent(), reportStepIdx);
const bool changed = wellGroupHelpers::checkGroupConstraintsProd(
group.name(),
group.parent(),
parentGroup,
well_state_,
reportStepIdx,
guideRate_.get(),
rates.data(),
phase_usage_,
group.getGroupEfficiencyFactor(),
schedule(),
summaryState,
*rateConverter_,
pvtreg,
deferred_logger);
if (changed) {
switched_groups.insert(group.name());
const auto exceed_action = group.productionControls(summaryState).exceed_action;
actionOnBrokenConstraints(group, exceed_action, Group::ProductionCMode::FLD, reportStepIdx, deferred_logger);
}
}
}
// call recursively down the group hiearchy
for (const std::string& groupName : group.groups()) {
checkGroupHigherConstraints( schedule().getGroup(groupName, reportStepIdx), deferred_logger, switched_groups);
}
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::

View File

@ -2115,6 +2115,21 @@ namespace Opm
MultisegmentWell<TypeTag>::
assembleGroupInjectionControl(const Group& group, const WellState& well_state, const Opm::Schedule& schedule, const SummaryState& summaryState, const InjectorType& injectorType, EvalWell& control_eq, double efficiencyFactor, Opm::DeferredLogger& deferred_logger)
{
if (!group.isAvailableForGroupControl()) {
// We cannot go any further up the hierarchy. This could
// be the FIELD group, or any group for which this has
// been set in GCONINJE or GCONPROD. If we are here
// anyway, it is likely that the deck set inconsistent
// requirements, such as GRUP control mode on a well with
// no appropriate controls defined on any of its
// containing groups. We will therefore use the wells' bhp
// limit equation as a fallback.
const auto& controls = well_ecl_.injectionControls(summaryState);
control_eq = getSegmentPressure(0) - controls.bhp_limit;
return;
}
const auto& well = well_ecl_;
const auto& pu = phaseUsage();
@ -2153,30 +2168,23 @@ namespace Opm
}
const Group::InjectionCMode& currentGroupControl = well_state.currentInjectionGroupControl(injectionPhase, group.name());
if (currentGroupControl == Group::InjectionCMode::FLD) {
if (currentGroupControl == Group::InjectionCMode::FLD ||
currentGroupControl == Group::InjectionCMode::NONE) {
// Inject share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
if (group.getTransferGroupEfficiencyFactor())
efficiencyFactor *= group.getGroupEfficiencyFactor();
efficiencyFactor *= group.getGroupEfficiencyFactor();
assembleGroupInjectionControl(parent, well_state, schedule, summaryState, injectorType, control_eq, efficiencyFactor, deferred_logger);
return;
}
if (!group.isInjectionGroup() || currentGroupControl == Group::InjectionCMode::NONE) {
// use bhp as control eq and let the updateControl code find a valid control
const auto& controls = well.injectionControls(summaryState);
control_eq = getSegmentPressure(0) - controls.bhp_limit;
return;
}
assert(group.hasInjectionControl(injectionPhase));
const auto& groupcontrols = group.injectionControls(injectionPhase, summaryState);
const std::vector<double>& groupInjectionReductions = well_state.currentInjectionGroupReductionRates(group.name());
double groupTargetReduction = groupInjectionReductions[phasePos];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, wellTarget, /*isInjector*/true);
wellGroupHelpers::accumulateGroupInjectionPotentialFractions(well.groupName(), group.name(), schedule, well_state, pu, current_step_, injectionPhase, fraction);
double fraction = wellGroupHelpers::fractionFromInjectionPotentials(well.name(), group.name(), schedule,well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(wellTarget), pu, injectionPhase,false);
switch(currentGroupControl) {
case Group::InjectionCMode::NONE:
@ -2187,8 +2195,8 @@ namespace Opm
}
case Group::InjectionCMode::RATE:
{
control_eq = getSegmentGTotal(0) / scaling - fraction * (groupcontrols.surface_max_rate / efficiencyFactor - groupTargetReduction);
double target = std::max(0.0, (groupcontrols.surface_max_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = getSegmentGTotal(0) / scaling - fraction * target;
break;
}
case Group::InjectionCMode::RESV:
@ -2196,7 +2204,7 @@ namespace Opm
std::vector<double> convert_coeff(number_of_phases_, 1.0);
Base::rateConverter_.calcCoeff(/*fipreg*/ 0, Base::pvtRegionIdx_, convert_coeff);
double coeff = convert_coeff[phasePos];
double target = std::max(0.0, (groupcontrols.resv_max_rate/coeff/efficiencyFactor - groupTargetReduction));
double target = std::max(0.0, (groupcontrols.resv_max_rate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = getSegmentGTotal(0) / scaling - fraction * target;
break;
}
@ -2204,7 +2212,7 @@ namespace Opm
{
double productionRate = well_state.currentInjectionREINRates(groupcontrols.reinj_group)[phasePos];
productionRate /= efficiencyFactor;
double target = std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction));
double target = std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction)) / efficiencyFactor;
control_eq = getSegmentGTotal(0) / scaling - fraction * target;
break;
}
@ -2228,9 +2236,7 @@ namespace Opm
voidageRate -= injReduction;
voidageRate /= efficiencyFactor;
double target = std::max(0.0, ( voidageRate/coeff - groupTargetReduction));
double target = std::max(0.0, ( voidageRate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = getSegmentGTotal(0) / scaling - fraction * target;
break;
}
@ -2258,7 +2264,7 @@ namespace Opm
inj_rate -= gconsale.sales_target;
inj_rate /= efficiencyFactor;
double target = std::max(0.0, (inj_rate - groupTargetReduction));
double target = std::max(0.0, (inj_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = getSegmentGTotal(0) /scaling - fraction * target;
break;
}
@ -2283,17 +2289,30 @@ namespace Opm
const auto pu = phaseUsage();
const Group::ProductionCMode& currentGroupControl = well_state.currentProductionGroupControl(group.name());
if (currentGroupControl == Group::ProductionCMode::FLD ) {
// Produce share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
if (group.getTransferGroupEfficiencyFactor())
if (currentGroupControl == Group::ProductionCMode::FLD ||
currentGroupControl == Group::ProductionCMode::NONE) {
if (!group.isAvailableForGroupControl()) {
// We cannot go any further up the hierarchy. This could
// be the FIELD group, or any group for which this has
// been set in GCONINJE or GCONPROD. If we are here
// anyway, it is likely that the deck set inconsistent
// requirements, such as GRUP control mode on a well with
// no appropriate controls defined on any of its
// containing groups. We will therefore use the wells' bhp
// limit equation as a fallback.
const auto& controls = well_ecl_.productionControls(summaryState);
control_eq = getSegmentPressure(0) - controls.bhp_limit;
return;
} else {
// Produce share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
efficiencyFactor *= group.getGroupEfficiencyFactor();
assembleGroupProductionControl(parent, well_state, schedule, summaryState, control_eq, efficiencyFactor, deferred_logger);
return;
assembleGroupProductionControl(parent, well_state, schedule, summaryState, control_eq, efficiencyFactor, deferred_logger);
return;
}
}
if (!group.isProductionGroup() || currentGroupControl == Group::ProductionCMode::NONE) {
if (!group.isProductionGroup()) {
// use bhp as control eq and let the updateControl code find a vallied control
const auto& controls = well.productionControls(summaryState);
control_eq = getSegmentPressure(0) - controls.bhp_limit;
@ -2313,10 +2332,9 @@ namespace Opm
case Group::ProductionCMode::ORAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Oil]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::OIL, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::OIL, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::OIL));
const double rate_target = std::max(0.0, groupcontrols.oil_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.oil_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx));
const EvalWell& rate = -getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx));
control_eq = rate - fraction * rate_target;
@ -2325,10 +2343,9 @@ namespace Opm
case Group::ProductionCMode::WRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Water]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::WAT, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::WAT, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::WAT));
const double rate_target = std::max(0.0, groupcontrols.water_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.gas_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx));
const EvalWell& rate = -getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx));
control_eq = rate - fraction * rate_target;
@ -2337,9 +2354,9 @@ namespace Opm
case Group::ProductionCMode::GRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Gas]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::GAS, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::GAS, fraction);
const double rate_target = std::max(0.0, groupcontrols.gas_target / efficiencyFactor - groupTargetReduction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::GAS));
const double rate_target = std::max(0.0, groupcontrols.gas_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::gasCompIdx));
const EvalWell& rate = -getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx));
control_eq = rate - fraction * rate_target;
@ -2348,12 +2365,9 @@ namespace Opm
case Group::ProductionCMode::LRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Oil]] + groupTargetReductions[pu.phase_pos[Water]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::LIQ, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::LIQ, fraction);
const double rate_target = std::max(0.0, groupcontrols.liquid_target / efficiencyFactor - groupTargetReduction);
assert(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx));
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::LIQ));
const double rate_target = std::max(0.0, groupcontrols.liquid_target - groupTargetReduction) / efficiencyFactor; assert(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx));
EvalWell rate = -getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx))
-getSegmentRate(0, Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx));
control_eq = rate - fraction * rate_target;

View File

@ -981,6 +981,20 @@ namespace Opm
StandardWell<TypeTag>::
assembleGroupInjectionControl(const Group& group, const WellState& well_state, const Opm::Schedule& schedule, const SummaryState& summaryState, const InjectorType& injectorType, EvalWell& control_eq, double efficiencyFactor, Opm::DeferredLogger& deferred_logger)
{
if (!group.isAvailableForGroupControl()) {
// We cannot go any further up the hierarchy. This could
// be the FIELD group, or any group for which this has
// been set in GCONINJE or GCONPROD. If we are here
// anyway, it is likely that the deck set inconsistent
// requirements, such as GRUP control mode on a well with
// no appropriate controls defined on any of its
// containing groups. We will therefore use the wells' bhp
// limit equation as a fallback.
const auto& controls = well_ecl_.injectionControls(summaryState);
control_eq = getBhp() - controls.bhp_limit;
return;
}
const auto& well = well_ecl_;
const auto pu = phaseUsage();
@ -1015,31 +1029,21 @@ namespace Opm
}
const Group::InjectionCMode& currentGroupControl = well_state.currentInjectionGroupControl(injectionPhase, group.name());
if (currentGroupControl == Group::InjectionCMode::FLD) {
if (currentGroupControl == Group::InjectionCMode::FLD ||
currentGroupControl == Group::InjectionCMode::NONE) {
// Inject share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
if (group.getTransferGroupEfficiencyFactor())
efficiencyFactor *= group.getGroupEfficiencyFactor();
efficiencyFactor *= group.getGroupEfficiencyFactor();
assembleGroupInjectionControl(parent, well_state, schedule, summaryState, injectorType, control_eq, efficiencyFactor, deferred_logger);
return;
}
if (!group.isInjectionGroup() || currentGroupControl == Group::InjectionCMode::NONE) {
// use bhp as control eq and let the updateControl code find a valid control
const auto& controls = well.injectionControls(summaryState);
control_eq = getBhp() - controls.bhp_limit;
return;
}
assert(group.hasInjectionControl(injectionPhase));
const auto& groupcontrols = group.injectionControls(injectionPhase, summaryState);
const std::vector<double>& groupInjectionReductions = well_state.currentInjectionGroupReductionRates(group.name());
double groupTargetReduction = groupInjectionReductions[phasePos];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, wellTarget, /*isInjector*/true);
wellGroupHelpers::accumulateGroupInjectionPotentialFractions(well.groupName(), group.name(), schedule, well_state, pu, current_step_, injectionPhase, fraction);
double fraction = wellGroupHelpers::fractionFromInjectionPotentials(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(wellTarget), pu, injectionPhase,false);
switch(currentGroupControl) {
case Group::InjectionCMode::NONE:
{
@ -1049,7 +1053,7 @@ namespace Opm
}
case Group::InjectionCMode::RATE:
{
double target = std::max(0.0, (groupcontrols.surface_max_rate / efficiencyFactor - groupTargetReduction) );
double target = std::max(0.0, (groupcontrols.surface_max_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = getWQTotal() - fraction * target;
break;
}
@ -1058,15 +1062,14 @@ namespace Opm
std::vector<double> convert_coeff(number_of_phases_, 1.0);
Base::rateConverter_.calcCoeff(/*fipreg*/ 0, Base::pvtRegionIdx_, convert_coeff);
double coeff = convert_coeff[phasePos];
double target = std::max(0.0, (groupcontrols.resv_max_rate/coeff/efficiencyFactor - groupTargetReduction));
double target = std::max(0.0, (groupcontrols.resv_max_rate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = getWQTotal() - fraction * target;
break;
}
case Group::InjectionCMode::REIN:
{
double productionRate = well_state.currentInjectionREINRates(groupcontrols.reinj_group)[phasePos];
productionRate /= efficiencyFactor;
double target = std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction));
double target = std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction)) / efficiencyFactor;
control_eq = getWQTotal() - fraction * target;
break;
}
@ -1090,9 +1093,7 @@ namespace Opm
voidageRate -= injReduction;
voidageRate /= efficiencyFactor;
double target = std::max(0.0, ( voidageRate/coeff - groupTargetReduction));
double target = std::max(0.0, ( voidageRate/coeff - groupTargetReduction)) / efficiencyFactor;
control_eq = getWQTotal() - fraction * target;
break;
}
@ -1119,8 +1120,7 @@ namespace Opm
const auto& gconsale = schedule.gConSale(current_step_).get(group.name(), summaryState);
inj_rate -= gconsale.sales_target;
inj_rate /= efficiencyFactor;
double target = std::max(0.0, (inj_rate - groupTargetReduction));
double target = std::max(0.0, (inj_rate - groupTargetReduction)) / efficiencyFactor;
control_eq = getWQTotal() - fraction * target;
break;
}
@ -1139,30 +1139,94 @@ namespace Opm
StandardWell<TypeTag>::
assembleGroupProductionControl(const Group& group, const WellState& well_state, const Opm::Schedule& schedule, const SummaryState& summaryState, EvalWell& control_eq, double efficiencyFactor, Opm::DeferredLogger& deferred_logger)
{
const auto& well = well_ecl_;
const auto pu = phaseUsage();
const Group::ProductionCMode& currentGroupControl = well_state.currentProductionGroupControl(group.name());
if (currentGroupControl == Group::ProductionCMode::FLD) {
// Produce share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
if (group.getTransferGroupEfficiencyFactor())
if (currentGroupControl == Group::ProductionCMode::FLD ||
currentGroupControl == Group::ProductionCMode::NONE) {
if (!group.isAvailableForGroupControl()) {
// We cannot go any further up the hierarchy. This could
// be the FIELD group, or any group for which this has
// been set in GCONINJE or GCONPROD. If we are here
// anyway, it is likely that the deck set inconsistent
// requirements, such as GRUP control mode on a well with
// no appropriate controls defined on any of its
// containing groups. We will therefore use the wells' bhp
// limit equation as a fallback.
const auto& controls = well_ecl_.productionControls(summaryState);
control_eq = getBhp() - controls.bhp_limit;
return;
} else {
// Produce share of parents control
const auto& parent = schedule.getGroup( group.parent(), current_step_ );
efficiencyFactor *= group.getGroupEfficiencyFactor();
assembleGroupProductionControl(parent, well_state, schedule, summaryState, control_eq, efficiencyFactor, deferred_logger);
return;
assembleGroupProductionControl(parent, well_state, schedule, summaryState, control_eq, efficiencyFactor, deferred_logger);
return;
}
}
if (!group.isProductionGroup() || currentGroupControl == Group::ProductionCMode::NONE) {
if (!group.isProductionGroup()) {
// use bhp as control eq and let the updateControl code find a vallied control
const auto& controls = well.productionControls(summaryState);
control_eq = getBhp() - controls.bhp_limit;
return;
}
const auto& groupcontrols = group.productionControls(summaryState);
// ------------------------------- New code start --------------------------------
// 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.
wellGroupHelpers::TargetCalculator tcalc(currentGroupControl, pu, Base::rateConverter_, Base::pvtRegionIdx_);
wellGroupHelpers::FractionCalculator fcalc(schedule, well_state, current_step_, Base::guide_rate_, tcalc.guideTargetMode());
auto localFraction = [&](const std::string& child) {
return fcalc.localFraction(child, "");
};
auto localReduction = [&](const std::string& group_name) {
const std::vector<double>& groupTargetReductions = well_state.currentProductionGroupReductionRates(group_name);
return tcalc.calcModeRateFromRates(groupTargetReductions);
};
const double orig_target = tcalc.groupTarget(group.productionControls(summaryState));
// Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP.
// Then ...
// TODO finish explanation.
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) {
target -= localReduction(chain[ii]);
// Next lines: different from in WellGroupHelpers.hpp
// if (ii == num_ancestors - 1) {
// // Final level. Add my reduction back.
// target += current_rate*efficiencyFactor;
// }
target *= localFraction(chain[ii+1]);
}
const double target_rate = target / efficiencyFactor;
std::vector<EvalWell> rates(pu.num_phases);
const int compIndices[3] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx };
const BlackoilPhases::PhaseIndex phases[3] = { BlackoilPhases::Aqua, BlackoilPhases::Liquid, BlackoilPhases::Vapour };
for (int canonical_phase = 0; canonical_phase < 3; ++canonical_phase) {
const auto phase = phases[canonical_phase];
if (pu.phase_used[phase]) {
const auto compIdx = compIndices[canonical_phase];
rates[pu.phase_pos[phase]] = getQs(Indices::canonicalToActiveComponentIndex(compIdx));
}
}
const auto current_rate = -tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
control_eq = current_rate - target_rate;
// ------------------------------- New code end --------------------------------
#if 0
const auto& groupcontrols = group.productionControls(summaryState);
const std::vector<double>& groupTargetReductions = well_state.currentProductionGroupReductionRates(group.name());
switch(currentGroupControl) {
@ -1174,10 +1238,9 @@ namespace Opm
case Group::ProductionCMode::ORAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Oil]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::OIL, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::OIL, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::OIL));
const double rate_target = std::max(0.0, groupcontrols.oil_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.oil_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx));
EvalWell rate = -getQs(Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx));
control_eq = rate - fraction * rate_target;
@ -1186,10 +1249,9 @@ namespace Opm
case Group::ProductionCMode::WRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Water]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::WAT, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::WAT, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::WAT));
const double rate_target = std::max(0.0, groupcontrols.water_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.water_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx));
EvalWell rate = -getQs(Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx));
control_eq = rate - fraction * rate_target;
@ -1198,10 +1260,9 @@ namespace Opm
case Group::ProductionCMode::GRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Gas]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::GAS, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::GAS, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::GAS));
const double rate_target = std::max(0.0, groupcontrols.gas_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.gas_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::gasCompIdx));
EvalWell rate = -getQs(Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx));
control_eq = rate - fraction * rate_target;
@ -1210,10 +1271,9 @@ namespace Opm
case Group::ProductionCMode::LRAT:
{
double groupTargetReduction = groupTargetReductions[pu.phase_pos[Oil]] + groupTargetReductions[pu.phase_pos[Water]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::LIQ, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::LIQ, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::LIQ));
const double rate_target = std::max(0.0, groupcontrols.liquid_target / efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.liquid_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx));
EvalWell rate = -getQs(Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx))
@ -1232,8 +1292,7 @@ namespace Opm
+ groupTargetReductions[pu.phase_pos[Gas]]
+ groupTargetReductions[pu.phase_pos[Water]];
double fraction = wellGroupHelpers::wellFractionFromGuideRates(well, schedule, well_state, current_step_, Base::guide_rate_, Well::GuideRateTarget::RES, /*isInjector*/false);
wellGroupHelpers::accumulateGroupFractionsFromGuideRates(well.groupName(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, Group::GuideRateTarget::RES, fraction);
double fraction = wellGroupHelpers::fractionFromGuideRates(well.name(), group.name(), schedule, well_state, current_step_, Base::guide_rate_, GuideRateModel::convert_target(Well::GuideRateTarget::RES));
EvalWell total_rate(numWellEq_ + numEq, 0.); // reservoir rate
std::vector<double> convert_coeff(number_of_phases_, 1.0);
@ -1242,7 +1301,7 @@ namespace Opm
total_rate -= getQs( flowPhaseToEbosCompIdx(phase) ) * convert_coeff[phase];
}
const double rate_target = std::max(0.0, groupcontrols.resv_target/ efficiencyFactor - groupTargetReduction);
const double rate_target = std::max(0.0, groupcontrols.resv_target - groupTargetReduction) / efficiencyFactor;
assert(FluidSystem::phaseIsActive(FluidSystem::gasCompIdx));
control_eq = total_rate - fraction * rate_target;
break;
@ -1262,6 +1321,7 @@ namespace Opm
default:
OPM_DEFLOG_THROW(std::runtime_error, "Unvallied group control specified for group " + well.groupName(), deferred_logger );
}
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -201,7 +201,9 @@ namespace Opm
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const = 0;
void updateWellControl(const Simulator& ebos_simulator,
enum class IndividualOrGroup { Individual, Group, Both };
bool updateWellControl(const Simulator& ebos_simulator,
const IndividualOrGroup iog,
WellState& well_state,
Opm::DeferredLogger& deferred_logger) /* const */;
@ -478,10 +480,34 @@ namespace Opm
// index calculations
int well_productivity_index_logger_counter_;
bool checkConstraints(WellState& well_state, const SummaryState& summaryState);
bool checkConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkIndividualConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkGroupConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
};

View File

@ -461,17 +461,19 @@ namespace Opm
template<typename TypeTag>
void
bool
WellInterface<TypeTag>::
updateWellControl(const Simulator& ebos_simulator,
const IndividualOrGroup iog,
WellState& well_state,
Opm::DeferredLogger& deferred_logger) /* const */
{
if (this->wellIsStopped()) {
return;
return false;
}
const auto& summaryState = ebos_simulator.vanguard().summaryState();
const auto& schedule = ebos_simulator.vanguard().schedule();
const auto& well = well_ecl_;
std::string from;
if (well.isInjector()) {
@ -480,7 +482,15 @@ namespace Opm
from = Well::ProducerCMode2String(well_state.currentProductionControls()[index_of_well_]);
}
bool changed = checkConstraints(well_state, summaryState);
bool changed = false;
if (iog == IndividualOrGroup::Individual) {
changed = checkIndividualConstraints(well_state, schedule, summaryState, deferred_logger);
} else if (iog == IndividualOrGroup::Group) {
changed = checkGroupConstraints(well_state, schedule, summaryState, deferred_logger);
} else {
assert(iog == IndividualOrGroup::Both);
changed = checkConstraints(well_state, schedule, summaryState, deferred_logger);
}
auto cc = Dune::MPIHelper::getCollectiveCommunication();
@ -503,6 +513,8 @@ namespace Opm
updateWellStateWithTarget(ebos_simulator, well_state, deferred_logger);
updatePrimaryVariables(well_state, deferred_logger);
}
return changed;
}
@ -1436,20 +1448,40 @@ namespace Opm
return operability_status_.isOperable();
}
template<typename TypeTag>
bool
WellInterface<TypeTag>::
checkConstraints(WellState& well_state, const SummaryState& summaryState) {
template <typename TypeTag>
bool
WellInterface<TypeTag>::checkConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
const bool ind_broken = checkIndividualConstraints(well_state, schedule, summaryState, deferred_logger);
if (ind_broken) {
return true;
} else {
return checkGroupConstraints(well_state, schedule, summaryState, deferred_logger);
}
}
template <typename TypeTag>
bool
WellInterface<TypeTag>::checkIndividualConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
const auto& well = well_ecl_;
const PhaseUsage& pu = phaseUsage();
const int well_index = index_of_well_;
const auto wellrate_index = well_index * pu.num_phases;
// bool changed = false;
// // Stopped wells can not change control
// if (currentControl == "STOP")
// return newControl;
if (well.isInjector()) {
const auto controls = well.injectionControls(summaryState);
@ -1633,4 +1665,155 @@ namespace Opm
}
}
template <typename TypeTag>
bool
WellInterface<TypeTag>::checkGroupConstraints(WellState& well_state,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
const auto& well = well_ecl_;
const int well_index = index_of_well_;
if (well.isInjector()) {
const auto controls = well.injectionControls(summaryState);
Opm::Well::InjectorCMode& currentControl = well_state.currentInjectionControls()[well_index];
if (currentControl != Well::InjectorCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup( well.groupName(), current_step_ );
const double efficiencyFactor = well.getEfficiencyFactor();
const bool group_constraint_broken = checkGroupConstraintsInj(
group, well_state, efficiencyFactor, schedule, summaryState, deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint_broken) {
well_state.currentInjectionControls()[index_of_well_] = Well::InjectorCMode::GRUP;
}
return group_constraint_broken;
}
}
if (well.isProducer( )) {
const auto controls = well.productionControls(summaryState);
Well::ProducerCMode& currentControl = well_state.currentProductionControls()[well_index];
if (currentControl != Well::ProducerCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup( well.groupName(), current_step_ );
const double efficiencyFactor = well.getEfficiencyFactor();
const bool group_constraint_broken = checkGroupConstraintsProd(
group, well_state, efficiencyFactor, schedule, summaryState, deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint_broken) {
well_state.currentProductionControls()[index_of_well_] = Well::ProducerCMode::GRUP;
}
return group_constraint_broken;
}
}
return false;
}
template <typename TypeTag>
bool
WellInterface<TypeTag>::checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
// Translate injector type from control to Phase.
const auto& well_controls = well_ecl_.injectionControls(summaryState);
auto injectorType = well_controls.injector_type;
Phase injectionPhase;
switch (injectorType) {
case InjectorType::WATER:
{
injectionPhase = Phase::WATER;
break;
}
case InjectorType::OIL:
{
injectionPhase = Phase::OIL;
break;
}
case InjectorType::GAS:
{
injectionPhase = Phase::GAS;
break;
}
default:
throw("Expected WATER, OIL or GAS as type for injector " + name());
}
// Call check for the well's injection phase.
return wellGroupHelpers::checkGroupConstraintsInj(name(),
well_ecl_.groupName(),
group,
well_state,
current_step_,
guide_rate_,
well_state.wellRates().data() + index_of_well_ * phaseUsage().num_phases,
injectionPhase,
phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
rateConverter_,
pvtRegionIdx_,
deferred_logger);
}
template <typename TypeTag>
bool
WellInterface<TypeTag>::checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
return wellGroupHelpers::checkGroupConstraintsProd(name(),
well_ecl_.groupName(),
group,
well_state,
current_step_,
guide_rate_,
well_state.wellRates().data() + index_of_well_ * phaseUsage().num_phases,
phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
rateConverter_,
pvtRegionIdx_,
deferred_logger);
}
} // namespace Opm

View File

@ -883,24 +883,37 @@ namespace Opm
}
template<class Comm>
void updateGlobalIsGrup(const Schedule& schedule, const int reportStepIdx, const Comm& comm) {
int global_well_index = -1;
void updateGlobalIsGrup(const Schedule& schedule, const int reportStepIdx, const Comm& comm)
{
std::fill(globalIsInjectionGrup_.begin(), globalIsInjectionGrup_.end(), 0);
std::fill(globalIsProductionGrup_.begin(), globalIsProductionGrup_.end(), 0);
int global_well_index = 0;
const auto& end = wellMap().end();
for (const auto& well : schedule.getWells(reportStepIdx)) {
global_well_index ++;
// Build global name->index map.
wellNameToGlobalIdx_[well.name()] = global_well_index;
// For wells on this process...
const auto& it = wellMap().find( well.name());
if (it == end) // the well is not found
continue;
int well_index = it->second[0];
if (well.isInjector())
globalIsInjectionGrup_[global_well_index] = (currentInjectionControls()[well_index] == Well::InjectorCMode::GRUP);
else
globalIsProductionGrup_[global_well_index] = (currentProductionControls()[well_index] == Well::ProducerCMode::GRUP);
if (it != end) {
// ... set the GRUP/not GRUP states.
const int well_index = it->second[0];
if (!this->open_for_output_[well_index]) {
// Well is shut.
if (well.isInjector()) {
globalIsInjectionGrup_[global_well_index] = 0;
} else {
globalIsProductionGrup_[global_well_index] = 0;
}
} else {
if (well.isInjector()) {
globalIsInjectionGrup_[global_well_index] = (currentInjectionControls()[well_index] == Well::InjectorCMode::GRUP);
} else {
globalIsProductionGrup_[global_well_index] = (currentProductionControls()[well_index] == Well::ProducerCMode::GRUP);
}
}
}
++global_well_index;
}
comm.sum(globalIsInjectionGrup_.data(), globalIsInjectionGrup_.size());
comm.sum(globalIsProductionGrup_.data(), globalIsProductionGrup_.size());