Various fixes and refactoring.

- Communicate all well rates.
 - When changing controls, modify rates to satisfy failed constraint.
 - Ensure targets are positive.
 - Always solve for potentials for MSW (temporary fix).
This commit is contained in:
Tor Harald Sandve 2020-03-24 09:24:45 +01:00 committed by Atgeirr Flø Rasmussen
parent 3a5a8c23df
commit 66931b9cb7
8 changed files with 458 additions and 311 deletions

View File

@ -86,6 +86,7 @@ namespace Opm
: status_{AllGood}
, res_failures_{}
, well_failures_{}
, groupConverged_(true)
{
}
@ -94,6 +95,7 @@ namespace Opm
status_ = AllGood;
res_failures_.clear();
well_failures_.clear();
groupConverged_ = true;
}
void setReservoirFailed(const ReservoirFailure& rf)
@ -107,7 +109,12 @@ namespace Opm
status_ = static_cast<Status>(status_ | WellFailed);
well_failures_.push_back(wf);
}
void setGroupConverged(const bool groupConverged)
{
groupConverged_ = groupConverged;
}
ConvergenceReport& operator+=(const ConvergenceReport& other)
{
status_ = static_cast<Status>(status_ | other.status_);
@ -122,7 +129,7 @@ namespace Opm
bool converged() const
{
return status_ == AllGood;
return status_ == AllGood && groupConverged_;
}
bool reservoirFailed() const
@ -167,6 +174,7 @@ namespace Opm
Status status_;
std::vector<ReservoirFailure> res_failures_;
std::vector<WellFailure> well_failures_;
bool groupConverged_;
};
} // namespace Opm

View File

@ -424,7 +424,11 @@ namespace Opm {
const Well& getWellEcl(const std::string& well_name) const;
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 updateGroupIndividualControl(const Group& group, Opm::DeferredLogger& deferred_logger, std::set<std::string>& switched_groups);
bool checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
Group::ProductionCMode checkGroupProductionConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const;
Group::InjectionCMode checkGroupInjectionConstraints(const Group& group, const Phase& phase, Opm::DeferredLogger& deferred_logger) const;
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);

View File

@ -1114,7 +1114,6 @@ namespace Opm {
local_report += well->getWellConvergence(well_state_, B_avg, local_deferredLogger);
}
}
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
@ -1132,7 +1131,11 @@ namespace Opm {
}
}
}
const int reportStepIdx = ebosSimulator_.episodeIndex();
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
bool violated = checkGroupConstraints(fieldGroup, global_deferredLogger);
report.setGroupConverged(!violated);
return report;
}
@ -1243,7 +1246,8 @@ namespace Opm {
wellGroupHelpers::updateVREPForGroups(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
wellGroupHelpers::updateReservoirRatesInjectionGroups(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
wellGroupHelpers::updateGroupProductionRates(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
wellGroupHelpers::updateWellRates(fieldGroup, schedule(), reportStepIdx, well_state_nupcol_, well_state_);
well_state_.communicateGroupRates(comm);
// compute wsolvent fraction for REIN wells
@ -1736,276 +1740,336 @@ namespace Opm {
{
const int reportStepIdx = ebosSimulator_.episodeIndex();
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
checkGroupConstraints(fieldGroup, deferred_logger, switched_groups);
updateGroupIndividualControl(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) {
updateGroupIndividualControl(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_;
const bool skip = switched_groups.count(group.name());
if (!skip && group.isInjectionGroup())
{
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
for (Phase phase : all) {
if (!group.hasInjectionControl(phase)) {
continue;
}
int phasePos;
if (phase == Phase::GAS && phase_usage_.phase_used[BlackoilPhases::Vapour] )
phasePos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
else if (phase == Phase::OIL && phase_usage_.phase_used[BlackoilPhases::Liquid])
phasePos = phase_usage_.phase_pos[BlackoilPhases::Liquid];
else if (phase == Phase::WATER && phase_usage_.phase_used[BlackoilPhases::Aqua] )
phasePos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
else
continue;
const auto& controls = group.injectionControls(phase, summaryState);
const Group::InjectionCMode& currentControl = well_state.currentInjectionGroupControl(phase, group.name());
if (controls.has_control(Group::InjectionCMode::RATE))
Group::InjectionCMode newControl = checkGroupInjectionConstraints(group, phase, deferred_logger);
if (newControl != Group::InjectionCMode::NONE)
{
if (currentControl != Group::InjectionCMode::RATE)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/true);
// sum over all nodes
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);
}
}
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, newControl, phase, reportStepIdx, deferred_logger);
}
if (controls.has_control(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);
// sum over all nodes
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 (currentControl != Group::InjectionCMode::REIN)
{
double production_Rate = 0.0;
const Group& groupRein = schedule().getGroup(controls.reinj_group, reportStepIdx);
production_Rate += wellGroupHelpers::sumWellRates(groupRein, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/false);
// sum over all nodes
production_Rate = comm.sum(production_Rate);
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/true);
// sum over all nodes
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 (currentControl != Group::InjectionCMode::VREP)
{
double voidage_rate = 0.0;
const Group& groupVoidage = schedule().getGroup(controls.voidage_group, reportStepIdx);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], false);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], false);
// sum over all nodes
voidage_rate = comm.sum(voidage_rate);
double total_rate = 0.0;
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], true);
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], true);
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], true);
// sum over all nodes
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);
}
}
}
// Handle GCONSALE
if (schedule().gConSale(reportStepIdx).has(group.name())) {
if (controls.phase != Phase::GAS)
OPM_THROW(std::runtime_error, "Group " + group.name() + " has GCONSALE control but is not a GAS group" );
const auto& gconsale = schedule().gConSale(reportStepIdx).get(group.name(), summaryState);
double sales_rate = 0.0;
int gasPos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
sales_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/false);
sales_rate -= wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/true);
// sum over all nodes
sales_rate = comm.sum(sales_rate);
// add import rate and substract consumption rate for group for gas
if (schedule().gConSump(reportStepIdx).has(group.name())) {
const auto& gconsump = schedule().gConSump(reportStepIdx).get(group.name(), summaryState);
if (phase_usage_.phase_used[BlackoilPhases::Vapour]) {
sales_rate += gconsump.import_rate;
sales_rate -= gconsump.consumption_rate;
}
}
if (sales_rate > gconsale.max_sales_rate) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate more then the maximum permitted value. Not implemented in Flow" );
}
if (sales_rate < gconsale.min_sales_rate) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate less then minimum permitted value. Not implemented in Flow" );
}
if (gconsale.sales_target < 0.0) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate target less then zero. Not implemented in Flow" );
}
}
}
}
if (!skip && group.isProductionGroup()) {
} else if (!skip && group.isProductionGroup())
{
Group::ProductionCMode newControl = checkGroupProductionConstraints(group, deferred_logger);
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
const auto controls = group.productionControls(summaryState);
const Group::ProductionCMode& currentControl = well_state.currentProductionGroupControl(group.name());
if (group.has_control(Group::ProductionCMode::ORAT))
if (newControl != Group::ProductionCMode::NONE)
{
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);
// sum over all nodes
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);
}
}
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, controls.exceed_action, newControl, reportStepIdx, deferred_logger);
}
if (group.has_control(Group::ProductionCMode::WRAT))
{
if (currentControl != Group::ProductionCMode::WRAT)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
// sum over all nodes
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 (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);
// 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 (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);
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
// sum over all nodes
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);
}
}
}
if (group.has_control(Group::ProductionCMode::CRAT))
{
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "CRAT control for production groups not implemented" , deferred_logger);
}
if (group.has_control(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);
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], true);
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], true);
// sum over all nodes
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);
}
}
}
if (group.has_control(Group::ProductionCMode::PRBL))
{
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "PRBL control for production groups not implemented", deferred_logger);
}
} else {
//neither production or injecting group FIELD?
}
// call recursively down the group hiearchy
for (const std::string& groupName : group.groups()) {
checkGroupConstraints( schedule().getGroup(groupName, reportStepIdx), deferred_logger, switched_groups);
updateGroupIndividualControl( schedule().getGroup(groupName, reportStepIdx), deferred_logger, switched_groups);
}
}
template<typename TypeTag>
bool
BlackoilWellModel<TypeTag>::
checkGroupConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const {
const int reportStepIdx = ebosSimulator_.episodeIndex();
if (group.isInjectionGroup())
{
const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS};
for (Phase phase : all) {
if (!group.hasInjectionControl(phase)) {
continue;
}
Group::InjectionCMode newControl = checkGroupInjectionConstraints(group, phase, deferred_logger);
if (newControl != Group::InjectionCMode::NONE)
{
return true;
}
}
} else if (group.isProductionGroup())
{
Group::ProductionCMode newControl = checkGroupProductionConstraints(group, deferred_logger);
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
const auto controls = group.productionControls(summaryState);
if (newControl != Group::ProductionCMode::NONE)
{
return true;
}
} else {
//neither production or injecting group FIELD?
}
// call recursively down the group hiearchy
bool violated = false;
for (const std::string& groupName : group.groups()) {
violated = violated || checkGroupConstraints( schedule().getGroup(groupName, reportStepIdx), deferred_logger);
}
return violated;
}
template<typename TypeTag>
Group::ProductionCMode
BlackoilWellModel<TypeTag>::
checkGroupProductionConstraints(const Group& group, Opm::DeferredLogger& deferred_logger) const {
const int reportStepIdx = ebosSimulator_.episodeIndex();
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
const auto& comm = ebosSimulator_.vanguard().grid().comm();
const auto& well_state = well_state_;
const auto controls = group.productionControls(summaryState);
const Group::ProductionCMode& currentControl = well_state.currentProductionGroupControl(group.name());
if (group.has_control(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);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.oil_target < current_rate ) {
return Group::ProductionCMode::ORAT;
}
}
}
if (group.has_control(Group::ProductionCMode::WRAT))
{
if (currentControl != Group::ProductionCMode::WRAT)
{
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.water_target < current_rate ) {
return Group::ProductionCMode::WRAT;
}
}
}
if (group.has_control(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);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.gas_target < current_rate ) {
return Group::ProductionCMode::GRAT;
}
}
}
if (group.has_control(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);
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.liquid_target < current_rate ) {
return Group::ProductionCMode::LRAT;
}
}
}
if (group.has_control(Group::ProductionCMode::CRAT))
{
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "CRAT control for production groups not implemented" , deferred_logger);
}
if (group.has_control(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);
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], true);
current_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], true);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.resv_target < current_rate ) {
return Group::ProductionCMode::RESV;
}
}
}
if (group.has_control(Group::ProductionCMode::PRBL))
{
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "PRBL control for production groups not implemented", deferred_logger);
}
return Group::ProductionCMode::NONE;
}
template<typename TypeTag>
Group::InjectionCMode
BlackoilWellModel<TypeTag>::
checkGroupInjectionConstraints(const Group& group, const Phase& phase, Opm::DeferredLogger& deferred_logger) const {
const int reportStepIdx = ebosSimulator_.episodeIndex();
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
const auto& comm = ebosSimulator_.vanguard().grid().comm();
const auto& well_state = well_state_;
int phasePos;
if (phase == Phase::GAS && phase_usage_.phase_used[BlackoilPhases::Vapour] )
phasePos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
else if (phase == Phase::OIL && phase_usage_.phase_used[BlackoilPhases::Liquid])
phasePos = phase_usage_.phase_pos[BlackoilPhases::Liquid];
else if (phase == Phase::WATER && phase_usage_.phase_used[BlackoilPhases::Aqua] )
phasePos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
else
OPM_THROW(std::runtime_error, "Unknown phase" );
const auto& controls = group.injectionControls(phase, summaryState);
const Group::InjectionCMode& currentControl = well_state.currentInjectionGroupControl(phase, group.name());
if (controls.has_control(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);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.surface_max_rate < current_rate) {
return Group::InjectionCMode::RATE;
}
}
}
if (controls.has_control(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);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.resv_max_rate < current_rate) {
return Group::InjectionCMode::RESV;
}
}
}
if (controls.has_control(Group::InjectionCMode::REIN))
{
if (currentControl != Group::InjectionCMode::REIN)
{
double production_Rate = 0.0;
const Group& groupRein = schedule().getGroup(controls.reinj_group, reportStepIdx);
production_Rate += wellGroupHelpers::sumWellRates(groupRein, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/false);
// sum over all nodes
production_Rate = comm.sum(production_Rate);
double current_rate = 0.0;
current_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, phasePos, /*isInjector*/true);
// sum over all nodes
current_rate = comm.sum(current_rate);
if (controls.target_reinj_fraction*production_Rate < current_rate) {
return Group::InjectionCMode::REIN;
}
}
}
if (controls.has_control(Group::InjectionCMode::VREP))
{
if (currentControl != Group::InjectionCMode::VREP)
{
double voidage_rate = 0.0;
const Group& groupVoidage = schedule().getGroup(controls.voidage_group, reportStepIdx);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], false);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], false);
voidage_rate += wellGroupHelpers::sumWellResRates(groupVoidage, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], false);
// sum over all nodes
voidage_rate = comm.sum(voidage_rate);
double total_rate = 0.0;
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Aqua], true);
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Liquid], true);
total_rate += wellGroupHelpers::sumWellResRates(group, schedule(), well_state, reportStepIdx, phase_usage_.phase_pos[BlackoilPhases::Vapour], true);
// sum over all nodes
total_rate = comm.sum(total_rate);
if (controls.target_void_fraction*voidage_rate < total_rate) {
return Group::InjectionCMode::VREP;
}
}
}
// Handle GCONSALE
if (schedule().gConSale(reportStepIdx).has(group.name())) {
if (controls.phase != Phase::GAS)
OPM_THROW(std::runtime_error, "Group " + group.name() + " has GCONSALE control but is not a GAS group" );
const auto& gconsale = schedule().gConSale(reportStepIdx).get(group.name(), summaryState);
double sales_rate = 0.0;
int gasPos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
sales_rate += wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/false);
sales_rate -= wellGroupHelpers::sumWellRates(group, schedule(), well_state, reportStepIdx, gasPos, /*isInjector*/true);
// sum over all nodes
sales_rate = comm.sum(sales_rate);
// add import rate and substract consumption rate for group for gas
if (schedule().gConSump(reportStepIdx).has(group.name())) {
const auto& gconsump = schedule().gConSump(reportStepIdx).get(group.name(), summaryState);
if (phase_usage_.phase_used[BlackoilPhases::Vapour]) {
sales_rate += gconsump.import_rate;
sales_rate -= gconsump.consumption_rate;
}
}
if (sales_rate > gconsale.max_sales_rate) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate more then the maximum permitted value. Not implemented in Flow" );
}
if (sales_rate < gconsale.min_sales_rate) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate less then minimum permitted value. Not implemented in Flow" );
}
if (gconsale.sales_target < 0.0) {
OPM_THROW(std::runtime_error, "Group " + group.name() + " has sale rate target less then zero. Not implemented in Flow" );
}
}
return Group::InjectionCMode::NONE;
}
template<typename TypeTag>
@ -2137,7 +2201,7 @@ namespace Opm {
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(
const std::pair<bool, double> changed = wellGroupHelpers::checkGroupConstraintsInj(
group.name(),
group.parent(),
parentGroup,
@ -2153,7 +2217,7 @@ namespace Opm {
*rateConverter_,
pvtreg,
deferred_logger);
if (changed) {
if (changed.first) {
switched_groups.insert(group.name());
actionOnBrokenConstraints(group, Group::InjectionCMode::FLD, phase, reportStepIdx, deferred_logger);
}
@ -2173,7 +2237,7 @@ namespace Opm {
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(
const std::pair<bool, double> changed = wellGroupHelpers::checkGroupConstraintsProd(
group.name(),
group.parent(),
parentGroup,
@ -2188,7 +2252,7 @@ namespace Opm {
*rateConverter_,
pvtreg,
deferred_logger);
if (changed) {
if (changed.first) {
switched_groups.insert(group.name());
const auto exceed_action = group.productionControls(summaryState).exceed_action;
actionOnBrokenConstraints(group, exceed_action, Group::ProductionCMode::FLD, reportStepIdx, deferred_logger);

View File

@ -675,7 +675,7 @@ namespace Opm
}
// If the well is pressure controlled the potential equals the rate.
{
/* {
bool pressure_controlled_well = false;
if (this->isInjector()) {
const Opm::Well::InjectorCMode& current = well_state.currentInjectionControls()[index_of_well_];
@ -695,7 +695,7 @@ namespace Opm
}
return;
}
}
} */
// creating a copy of the well itself, to avoid messing up the explicit informations
// during this copy, the only information not copied properly is the well controls

View File

@ -395,6 +395,39 @@ namespace Opm {
}
wellState.setCurrentInjectionGroupReservoirRates(group.name(), resv);
}
inline void updateWellRates(const Group& group, const Schedule& schedule, const int reportStepIdx, const WellStateFullyImplicitBlackoil& wellStateNupcol, WellStateFullyImplicitBlackoil& wellState) {
for (const std::string& groupName : group.groups()) {
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
updateWellRates(groupTmp, schedule, reportStepIdx, wellStateNupcol, wellState);
}
const int np = wellState.numPhases();
const auto& end = wellState.wellMap().end();
for (const std::string& wellName : group.wells()) {
std::vector<double> rates(np, 0.0);
const auto& it = wellState.wellMap().find(wellName);
if (it != end) { // the well is found on this node
int well_index = it->second[0];
for (int phase = 0; phase < np; ++phase) {
rates[phase] = wellStateNupcol.wellRates()[well_index*np + phase];
}
}
wellState.setCurrentWellRates(wellName, rates);
}
}
inline void updateGroupProductionRates(const Group& group, const Schedule& schedule, const int reportStepIdx, const WellStateFullyImplicitBlackoil& wellStateNupcol, WellStateFullyImplicitBlackoil& wellState) {
for (const std::string& groupName : group.groups()) {
const Group& groupTmp = schedule.getGroup(groupName, reportStepIdx);
updateGroupProductionRates(groupTmp, schedule, reportStepIdx, wellStateNupcol, wellState);
}
const int np = wellState.numPhases();
std::vector<double> rates(np, 0.0);
for (int phase = 0; phase < np; ++phase) {
rates[phase] = sumWellPhaseRates(wellStateNupcol.wellRates(), group, schedule, wellState, reportStepIdx, phase, /*isInjector*/ false);
}
wellState.setCurrentProductionGroupRates(group.name(), rates);
}
inline void updateREINForGroups(const Group& group, const Schedule& schedule, const int reportStepIdx, const PhaseUsage& pu, const SummaryState& st, const WellStateFullyImplicitBlackoil& wellStateNupcol, WellStateFullyImplicitBlackoil& wellState) {
const int np = wellState.numPhases();
@ -420,29 +453,22 @@ namespace Opm {
wellState.setCurrentInjectionREINRates(group.name(), rein);
}
inline GuideRate::RateVector getRateVector(const WellState& well_state, const PhaseUsage& pu, const std::string& name) {
const auto& end = well_state.wellMap().end();
const auto& it = well_state.wellMap().find( name);
if (it == end) // the well is not found
assert(false);
int well_index = it->second[0];
int np = well_state.numPhases();
double oilRate = 0.0;
if (pu.phase_used[BlackoilPhases::Liquid])
oilRate = well_state.wellRates()[ well_index*np + pu.phase_pos[BlackoilPhases::Liquid]];
inline GuideRate::RateVector getRateVector(const WellStateFullyImplicitBlackoil& well_state, const PhaseUsage& pu, const std::string& name) {
const std::vector<double>& rates = well_state.currentWellRates(name);
double oilRate = 0.0;
if (pu.phase_used[BlackoilPhases::Liquid])
oilRate = rates[pu.phase_pos[BlackoilPhases::Liquid]];
double gasRate = 0.0;
if (pu.phase_used[BlackoilPhases::Vapour])
gasRate = well_state.wellRates()[ well_index*np + pu.phase_pos[BlackoilPhases::Vapour]];
double gasRate = 0.0;
if (pu.phase_used[BlackoilPhases::Vapour])
gasRate = rates[pu.phase_pos[BlackoilPhases::Vapour]];
double waterRate = 0.0;
if (pu.phase_used[BlackoilPhases::Aqua])
waterRate = well_state.wellRates()[well_index*np + pu.phase_pos[BlackoilPhases::Aqua]];
double waterRate = 0.0;
if (pu.phase_used[BlackoilPhases::Aqua])
waterRate = rates[pu.phase_pos[BlackoilPhases::Aqua]];
return GuideRate::RateVector{oilRate, gasRate, waterRate};
}
return GuideRate::RateVector{oilRate, gasRate, waterRate};
}
inline double getGuideRate(const std::string& name,
@ -451,7 +477,7 @@ namespace Opm {
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu)
const PhaseUsage& pu)
{
if (schedule.hasWell(name, reportStepIdx) || guideRate->has(name)) {
return guideRate->get(name, target, getRateVector(wellState, pu, name));
@ -675,24 +701,23 @@ namespace Opm {
return ::Opm::wellGroupHelpers::groupControlledWells(schedule_, well_state_, report_step_, group_name, always_included_child);
}
inline GuideRate::RateVector getGroupRateVector(const std::string& group_name) {
inline GuideRate::RateVector getGroupRateVector(const std::string& group_name) {
#warning Does not work in parallell
const Group& group = schedule_.getGroup(group_name, report_step_);
double oilRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Liquid])
oilRate = sumWellPhaseRates(well_state_.wellRates(), group, schedule_, well_state_, report_step_, pu_.phase_pos[BlackoilPhases::Liquid], /*isInjector*/ false);
std::vector<double> groupRates = well_state_.currentProductionGroupRates(group_name);
double oilRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Liquid])
oilRate = groupRates[pu_.phase_pos[BlackoilPhases::Liquid]];
double gasRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Vapour])
gasRate = sumWellPhaseRates(well_state_.wellRates(), group, schedule_, well_state_, report_step_, pu_.phase_pos[BlackoilPhases::Vapour], /*isInjector*/ false);
double gasRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Vapour])
gasRate = groupRates[pu_.phase_pos[BlackoilPhases::Vapour]];
double waterRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Aqua])
waterRate = sumWellPhaseRates(well_state_.wellRates(), group, schedule_, well_state_, report_step_, pu_.phase_pos[BlackoilPhases::Aqua], /*isInjector*/ false);
return GuideRate::RateVector{oilRate, gasRate, waterRate};
}
double waterRate = 0.0;
if (pu_.phase_used[BlackoilPhases::Aqua])
waterRate = groupRates[pu_.phase_pos[BlackoilPhases::Aqua]];
return GuideRate::RateVector{oilRate, gasRate, waterRate};
}
const Schedule& schedule_;
@ -711,7 +736,7 @@ namespace Opm {
const int reportStepIdx,
const GuideRate* guideRate,
const GuideRateModel::Target target,
const PhaseUsage& pu,
const PhaseUsage& pu,
const bool alwaysIncludeThis = false)
{
FractionCalculator calc(schedule, wellState, reportStepIdx, guideRate, target, pu);
@ -743,7 +768,7 @@ namespace Opm {
template <class RateConverterType>
inline bool checkGroupConstraintsInj(const std::string& name,
inline std::pair<bool, double> checkGroupConstraintsInj(const std::string& name,
const std::string& parent,
const Group& group,
const WellStateFullyImplicitBlackoil& wellState,
@ -769,7 +794,7 @@ namespace Opm {
currentGroupControl == Group::InjectionCMode::NONE) {
// Return if we are not available for parent group.
if (!group.isAvailableForGroupControl()) {
return false;
return std::make_pair(false, 1.0);
}
// Otherwise: check injection share of parent's control.
const auto& parentGroup = schedule.getGroup(group.parent(), reportStepIdx);
@ -796,7 +821,7 @@ namespace Opm {
// This can be false for FLD-controlled groups, we must therefore
// check for FLD first (done above).
if (!group.isInjectionGroup()) {
return false;
return std::make_pair(false, 1.0);
}
int phasePos;
@ -831,7 +856,7 @@ namespace Opm {
const std::vector<double>& groupInjectionReductions = wellState.currentInjectionGroupReductionRates(group.name());
const double groupTargetReduction = groupInjectionReductions[phasePos];
double fraction = wellGroupHelpers::fractionFromInjectionPotentials(name, group.name(), schedule, wellState, reportStepIdx, guideRate, target, pu, injectionPhase, true);
double target_fraction = 1.0;
bool constraint_broken = false;
switch(currentGroupControl) {
case Group::InjectionCMode::RATE:
@ -840,6 +865,7 @@ namespace Opm {
const double target_rate = fraction * std::max(0.0, (groupcontrols.surface_max_rate - groupTargetReduction + current_rate*efficiencyFactor)) / efficiencyFactor;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
@ -852,6 +878,7 @@ namespace Opm {
const double target_rate = fraction * std::max(0.0, (groupcontrols.resv_max_rate/coeff - groupTargetReduction + current_rate*efficiencyFactor)) / efficiencyFactor;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
@ -862,6 +889,7 @@ namespace Opm {
const double target_rate = fraction * std::max(0.0, (groupcontrols.target_reinj_fraction*productionRate - groupTargetReduction + current_rate*efficiencyFactor)) / efficiencyFactor;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
@ -885,6 +913,7 @@ namespace Opm {
const double target_rate = fraction * std::max(0.0, ( voidageRate/coeff - groupTargetReduction + current_rate*efficiencyFactor)) / efficiencyFactor;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
@ -909,6 +938,7 @@ namespace Opm {
const double target_rate = fraction * std::max(0.0, (inj_rate - groupTargetReduction + current_rate*efficiencyFactor)) / efficiencyFactor;
if (current_rate > target_rate) {
constraint_broken = true;
target_fraction = target_rate / current_rate;
}
break;
}
@ -925,7 +955,7 @@ namespace Opm {
}
return constraint_broken;
return std::make_pair(constraint_broken, target_fraction);
}
template <class RateConverterType>
@ -1080,7 +1110,7 @@ namespace Opm {
template <class RateConverterType>
inline bool checkGroupConstraintsProd(const std::string& name,
inline std::pair<bool, double> checkGroupConstraintsProd(const std::string& name,
const std::string& parent,
const Group& group,
const WellStateFullyImplicitBlackoil& wellState,
@ -1106,7 +1136,7 @@ namespace Opm {
currentGroupControl == Group::ProductionCMode::NONE) {
// Return if we are not available for parent group.
if (!group.isAvailableForGroupControl()) {
return false;
return std::make_pair(false,1);
}
// Otherwise: check production share of parent's control.
const auto& parentGroup = schedule.getGroup(group.parent(), reportStepIdx);
@ -1129,7 +1159,7 @@ namespace Opm {
// This can be false for FLD-controlled groups, we must therefore
// check for FLD first (done above).
if (!group.isProductionGroup()) {
return false;
return std::make_pair(false,1.0);
}
// If we are here, we are at the topmost group to be visited in the recursion.
@ -1174,8 +1204,8 @@ namespace Opm {
}
target *= localFraction(chain[ii+1]);
}
const double target_rate = target / efficiencyFactor;
return current_rate > target_rate;
const double target_rate = std::max(0.0, target / efficiencyFactor);
return std::make_pair(current_rate > target_rate, target_rate / current_rate);
}

View File

@ -495,14 +495,14 @@ namespace Opm
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkGroupConstraintsProd(const Group& group,
std::pair<bool, double> 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,
std::pair<bool, double> checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
const Schedule& schedule,

View File

@ -1682,7 +1682,7 @@ namespace Opm
const auto controls = well.injectionControls(summaryState);
Opm::Well::InjectorCMode& currentControl = well_state.currentInjectionControls()[well_index];
if (currentControl != Well::InjectorCMode::GRUP) {
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,
@ -1691,22 +1691,26 @@ namespace Opm
// 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(
const std::pair<bool, double> group_constraint = 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) {
if (group_constraint.first) {
well_state.currentInjectionControls()[index_of_well_] = Well::InjectorCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
well_state.wellRates()[index_of_well_*np + p] *= group_constraint.second;
}
}
return group_constraint_broken;
}
return group_constraint.first;
}
}
if (well.isProducer( )) {
const auto controls = well.productionControls(summaryState);
Well::ProducerCMode& currentControl = well_state.currentProductionControls()[well_index];
if (currentControl != Well::ProducerCMode::GRUP) {
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,
@ -1715,15 +1719,19 @@ namespace Opm
// 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(
const std::pair<bool, double> group_constraint = 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) {
if (group_constraint.first) {
well_state.currentProductionControls()[index_of_well_] = Well::ProducerCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
well_state.wellRates()[index_of_well_*np + p] *= group_constraint.second;
}
}
return group_constraint_broken;
}
return group_constraint.first;
}
}
return false;
@ -1734,7 +1742,7 @@ namespace Opm
template <typename TypeTag>
bool
std::pair<bool, double>
WellInterface<TypeTag>::checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const double efficiencyFactor,
@ -1788,7 +1796,7 @@ namespace Opm
template <typename TypeTag>
bool
std::pair<bool, double>
WellInterface<TypeTag>::checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const double efficiencyFactor,

View File

@ -350,8 +350,33 @@ namespace Opm
return it->second;
}
void setCurrentWellRates(const std::string& wellName, const std::vector<double>& rates ) {
well_rates[wellName] = rates;
}
const std::vector<double>& currentWellRates(const std::string& wellName) const {
auto it = well_rates.find(wellName);
if (it == well_rates.end())
OPM_THROW(std::logic_error, "Could not find any rates for well " << wellName);
return it->second;
}
void setCurrentProductionGroupRates(const std::string& groupName, const std::vector<double>& rates ) {
production_group_rates[groupName] = rates;
}
const std::vector<double>& currentProductionGroupRates(const std::string& groupName) const {
auto it = production_group_rates.find(groupName);
if (it == production_group_rates.end())
OPM_THROW(std::logic_error, "Could not find any rates for productino group " << groupName);
return it->second;
}
void setCurrentProductionGroupReductionRates(const std::string& groupName, const std::vector<double>& target ) {
production_group_reduction_rates[groupName] = target;
}
@ -880,6 +905,12 @@ namespace Opm
for (auto& x : injection_group_reservoir_rates) {
comm.sum(x.second.data(), x.second.size());
}
for (auto& x : production_group_rates) {
comm.sum(x.second.data(), x.second.size());
}
for (auto& x : well_rates) {
comm.sum(x.second.data(), x.second.size());
}
}
template<class Comm>
@ -952,6 +983,8 @@ namespace Opm
std::map<std::string, Group::ProductionCMode> current_production_group_controls_;
std::map<std::pair<Opm::Phase, std::string>, Group::InjectionCMode> current_injection_group_controls_;
std::map<std::string, std::vector<double>> well_rates;
std::map<std::string, std::vector<double>> production_group_rates;
std::map<std::string, std::vector<double>> production_group_reduction_rates;
std::map<std::string, std::vector<double>> injection_group_reduction_rates;
std::map<std::string, std::vector<double>> injection_group_reservoir_rates;