mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-11-25 18:50:19 -06:00
Merge pull request #5172 from totto82/gconprod7
Implement WELL as group limit action
This commit is contained in:
commit
b1be391d4c
@ -97,7 +97,7 @@ partiallySupported()
|
||||
"GCONPROD",
|
||||
{
|
||||
{2,{true, allow_values<std::string> {"NONE", "FLD", "ORAT", "WRAT", "GRAT", "LRAT", "RESV"}, "GCONPROD(TARGET): valid option should be NONE/FLD/ORAT/WRAT/GRAT/LRAT or RESV"}}, // CONTROL_MODE
|
||||
{7,{true, allow_values<std::string> {"NONE", "RATE"}, "GCONPROD(ACTION): Only NONE and RATE are supported"}},
|
||||
{7,{true, allow_values<std::string> {"NONE", "RATE", "WELL"}, "GCONPROD(ACTION): Only NONE and RATE are supported"}},
|
||||
{11,{true, allow_values<std::string> {"NONE", "RATE"}, "GCONPROD(ACTWAT): Only NONE and RATE are supported"}}, // WATER_EXCEED_PROCEDURE
|
||||
{12,{true, allow_values<std::string> {"NONE", "RATE"}, "GCONPROD(ACTGAS): Only NONE and RATE are supported"}}, // GAS_EXCEED_PROCEDURE
|
||||
{13,{true, allow_values<std::string> {"NONE", "RATE"}, "GCONPROD(ACTLIQ): Only NONE and RATE are supported"}}, // LIQUID_EXCEED_PROCEDURE
|
||||
@ -330,7 +330,8 @@ partiallySupported()
|
||||
{
|
||||
"WTEST",
|
||||
{
|
||||
{3,{true, allow_values<std::string> {"E", "P", "EP", "PE", ""}, "WTEST(TEST): only the E (economic) and P (physical) reason is currently supported"}}, // REASON
|
||||
{3,{true, allow_values<std::string> {"E", "P", "G", "EP", "PE", "EG", "GE", "PG", "GP", "PEG", "PGE", "EPG", "EGP", "GEP", "GPE"},
|
||||
"WTEST(TEST): only the E (economic) and P (physical) and G (group) reason is currently supported"}}, // REASON
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -400,13 +400,18 @@ actionOnBrokenConstraints(const Group& group,
|
||||
}
|
||||
}
|
||||
|
||||
void BlackoilWellModelConstraints::
|
||||
bool BlackoilWellModelConstraints::
|
||||
actionOnBrokenConstraints(const Group& group,
|
||||
const int reportStepIdx,
|
||||
const Group::GroupLimitAction group_limit_action,
|
||||
const Group::ProductionCMode& newControl,
|
||||
const WellState& well_state,
|
||||
std::optional<std::string>& worst_offending_well,
|
||||
GroupState& group_state,
|
||||
DeferredLogger& deferred_logger) const
|
||||
{
|
||||
|
||||
bool changed = false;
|
||||
const Group::ProductionCMode oldControl = wellModel_.groupState().production_control(group.name());
|
||||
|
||||
std::string ss;
|
||||
@ -421,6 +426,8 @@ actionOnBrokenConstraints(const Group& group,
|
||||
group.name(),
|
||||
Group::ProductionCMode2String(oldControl),
|
||||
Group::ProductionCMode2String(newControl));
|
||||
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
ss = fmt::format("Procedure on exceeding {} limit is NONE for group {}. Nothing is done.",
|
||||
@ -439,7 +446,9 @@ actionOnBrokenConstraints(const Group& group,
|
||||
break;
|
||||
}
|
||||
case Group::ExceedAction::WELL: {
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GroupProductionExceedLimit WELL not implemented", deferred_logger);
|
||||
|
||||
std::tie(worst_offending_well, std::ignore) = WellGroupHelpers::worstOffendingWell(group, wellModel_.schedule(), reportStepIdx,
|
||||
newControl, wellModel_.phaseUsage(), wellModel_.comm(), well_state, deferred_logger);
|
||||
break;
|
||||
}
|
||||
case Group::ExceedAction::PLUG: {
|
||||
@ -454,6 +463,7 @@ actionOnBrokenConstraints(const Group& group,
|
||||
Group::ProductionCMode2String(oldControl),
|
||||
Group::ProductionCMode2String(newControl));
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -462,6 +472,8 @@ actionOnBrokenConstraints(const Group& group,
|
||||
|
||||
if (!ss.empty() && wellModel_.comm().rank() == 0)
|
||||
deferred_logger.debug(ss);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool BlackoilWellModelConstraints::
|
||||
@ -469,6 +481,7 @@ updateGroupIndividualControl(const Group& group,
|
||||
const int reportStepIdx,
|
||||
std::map<std::pair<std::string,Opm::Phase>,std::string>& switched_inj,
|
||||
std::map<std::string, std::string>& switched_prod,
|
||||
std::map<std::string, std::pair<std::string, std::string>>& closed_offending_wells,
|
||||
GroupState& group_state,
|
||||
WellState& well_state,
|
||||
DeferredLogger& deferred_logger) const
|
||||
@ -506,23 +519,30 @@ updateGroupIndividualControl(const Group& group,
|
||||
reportStepIdx,
|
||||
deferred_logger);
|
||||
const auto controls = group.productionControls(wellModel_.summaryState());
|
||||
|
||||
if (changed_this.first != Group::ProductionCMode::NONE)
|
||||
{
|
||||
switched_prod.insert_or_assign(group.name(),
|
||||
Group::ProductionCMode2String(changed_this.first));
|
||||
|
||||
this->actionOnBrokenConstraints(group,
|
||||
std::optional<std::string> worst_offending_well = std::nullopt;
|
||||
changed = this->actionOnBrokenConstraints(group, reportStepIdx,
|
||||
controls.group_limit_action,
|
||||
changed_this.first,
|
||||
changed_this.first, well_state,
|
||||
worst_offending_well,
|
||||
group_state, deferred_logger);
|
||||
WellGroupHelpers::updateWellRatesFromGroupTargetScale(changed_this.second,
|
||||
group,
|
||||
wellModel_.schedule(),
|
||||
reportStepIdx,
|
||||
/* isInjector */ false,
|
||||
wellModel_.groupState(),
|
||||
well_state);
|
||||
changed = true;
|
||||
|
||||
if(changed) {
|
||||
switched_prod.insert_or_assign(group.name(),
|
||||
Group::ProductionCMode2String(changed_this.first));
|
||||
WellGroupHelpers::updateWellRatesFromGroupTargetScale(changed_this.second,
|
||||
group,
|
||||
wellModel_.schedule(),
|
||||
reportStepIdx,
|
||||
/* isInjector */ false,
|
||||
wellModel_.groupState(),
|
||||
well_state);
|
||||
} else if (worst_offending_well) {
|
||||
closed_offending_wells.insert_or_assign(group.name(),
|
||||
std::make_pair(Group::ProductionCMode2String(changed_this.first), *worst_offending_well));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define OPM_BLACKOILWELLMODEL_CONSTRAINTS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace Opm {
|
||||
@ -59,18 +59,22 @@ public:
|
||||
GroupState& group_state,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
||||
//! \brief Execute action on broken constraint for a production well group.
|
||||
void actionOnBrokenConstraints(const Group& group,
|
||||
//! \brief Execute action on broken constraint for a production well group. Return true if a group control is changed
|
||||
bool actionOnBrokenConstraints(const Group& group,
|
||||
const int reportStepIdx,
|
||||
const Group::GroupLimitAction group_limit_action,
|
||||
const Group::ProductionCMode& newControl,
|
||||
const WellState& well_state,
|
||||
std::optional<std::string>& worst_offending_well,
|
||||
GroupState& group_state,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
||||
//! \brief Update the individual controls for wells in a group.
|
||||
//! \brief Update the individual controls for wells in a group. Return true if a group control is changed
|
||||
bool updateGroupIndividualControl(const Group& group,
|
||||
const int reportStepIdx,
|
||||
std::map<std::pair<std::string,Opm::Phase>,std::string>& switched_inj,
|
||||
std::map<std::string, std::string>& switched_prod,
|
||||
std::map<std::string, std::pair<std::string, std::string>>& closed_offending_wells,
|
||||
GroupState& group_state,
|
||||
WellState& well_state,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
@ -653,15 +653,20 @@ checkGroupHigherConstraints(const Group& group,
|
||||
resv_coeff,
|
||||
deferred_logger);
|
||||
if (is_changed) {
|
||||
switched_prod_groups_.insert_or_assign(group.name(), Group::ProductionCMode2String(Group::ProductionCMode::FLD));
|
||||
const auto group_limit_action = group.productionControls(summaryState_).group_limit_action;
|
||||
BlackoilWellModelConstraints(*this).
|
||||
actionOnBrokenConstraints(group, group_limit_action,
|
||||
std::optional<std::string> worst_offending_well = std::nullopt;
|
||||
changed = BlackoilWellModelConstraints(*this).
|
||||
actionOnBrokenConstraints(group, reportStepIdx, group_limit_action,
|
||||
Group::ProductionCMode::FLD,
|
||||
this->wellState(),
|
||||
worst_offending_well,
|
||||
this->groupState(),
|
||||
deferred_logger);
|
||||
WellGroupHelpers::updateWellRatesFromGroupTargetScale(scaling_factor, group, schedule(), reportStepIdx, /* isInjector */ false, this->groupState(), this->wellState());
|
||||
changed = true;
|
||||
|
||||
if (changed) {
|
||||
switched_prod_groups_.insert_or_assign(group.name(), Group::ProductionCMode2String(Group::ProductionCMode::FLD));
|
||||
WellGroupHelpers::updateWellRatesFromGroupTargetScale(scaling_factor, group, schedule(), reportStepIdx, /* isInjector */ false, this->groupState(), this->wellState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -772,10 +777,18 @@ bool
|
||||
BlackoilWellModelGeneric::
|
||||
wasDynamicallyShutThisTimeStep(const int well_index) const
|
||||
{
|
||||
return this->closed_this_step_.find(this->wells_ecl_[well_index].name()) !=
|
||||
return wasDynamicallyShutThisTimeStep(this->wells_ecl_[well_index].name());
|
||||
}
|
||||
|
||||
bool
|
||||
BlackoilWellModelGeneric::
|
||||
wasDynamicallyShutThisTimeStep(const std::string& well_name) const
|
||||
{
|
||||
return this->closed_this_step_.find(well_name) !=
|
||||
this->closed_this_step_.end();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BlackoilWellModelGeneric::
|
||||
updateWsolvent(const Group& group,
|
||||
|
@ -213,6 +213,7 @@ public:
|
||||
void updateClosedWellsThisStep(const std::string& well_name) const {
|
||||
this->closed_this_step_.insert(well_name);
|
||||
}
|
||||
bool wasDynamicallyShutThisTimeStep(const std::string& well_name) const;
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
@ -231,6 +232,7 @@ public:
|
||||
serializer(last_glift_opt_time_);
|
||||
serializer(switched_prod_groups_);
|
||||
serializer(switched_inj_groups_);
|
||||
serializer(closed_offending_wells_);
|
||||
}
|
||||
|
||||
bool operator==(const BlackoilWellModelGeneric& rhs) const
|
||||
@ -247,7 +249,8 @@ public:
|
||||
this->nupcol_wgstate_ == rhs.nupcol_wgstate_ &&
|
||||
this->last_glift_opt_time_ == rhs.last_glift_opt_time_ &&
|
||||
this->switched_prod_groups_ == rhs.switched_prod_groups_ &&
|
||||
this->switched_inj_groups_ == rhs.switched_inj_groups_;
|
||||
this->switched_inj_groups_ == rhs.switched_inj_groups_ &&
|
||||
this->closed_offending_wells_ == rhs.closed_offending_wells_;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -582,8 +585,12 @@ protected:
|
||||
|
||||
bool wellStructureChangedDynamically_{false};
|
||||
|
||||
// Store maps of group name and new group controls for output
|
||||
std::map<std::string, std::string> switched_prod_groups_;
|
||||
std::map<std::pair<std::string, Opm::Phase>, std::string> switched_inj_groups_;
|
||||
// Store map of group name and close offending well for output
|
||||
std::map<std::string, std::pair<std::string, std::string>> closed_offending_wells_;
|
||||
|
||||
|
||||
private:
|
||||
WellInterfaceGeneric* getGenWell(const std::string& well_name);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
||||
#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
|
||||
#include <opm/simulators/wells/ParallelPAvgDynamicSourceData.hpp>
|
||||
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
|
||||
@ -44,6 +44,7 @@
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
@ -1079,6 +1080,7 @@ namespace Opm {
|
||||
last_report_ = SimulatorReportSingle();
|
||||
Dune::Timer perfTimer;
|
||||
perfTimer.start();
|
||||
closed_offending_wells_.clear();
|
||||
|
||||
{
|
||||
const int episodeIdx = simulator_.episodeIndex();
|
||||
@ -2132,15 +2134,18 @@ namespace Opm {
|
||||
changed = true;
|
||||
updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
|
||||
}
|
||||
|
||||
bool changed_individual =
|
||||
BlackoilWellModelConstraints(*this).
|
||||
updateGroupIndividualControl(group,
|
||||
reportStepIdx,
|
||||
this->switched_inj_groups_,
|
||||
this->switched_prod_groups_,
|
||||
this->closed_offending_wells_,
|
||||
this->groupState(),
|
||||
this->wellState(),
|
||||
deferred_logger);
|
||||
|
||||
if (changed_individual) {
|
||||
changed = true;
|
||||
updateAndCommunicate(reportStepIdx, iterationIdx, deferred_logger);
|
||||
@ -2172,9 +2177,29 @@ namespace Opm {
|
||||
|
||||
const Opm::Parallel::Communication comm = grid().comm();
|
||||
DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger, comm);
|
||||
|
||||
for (const auto& [group_name, to] : closed_offending_wells_) {
|
||||
if (!this->wasDynamicallyShutThisTimeStep(to.second)) {
|
||||
wellTestState.close_well(
|
||||
to.second, WellTestConfig::Reason::GROUP, simulationTime);
|
||||
this->updateClosedWellsThisStep(to.second);
|
||||
std::string msg = fmt::format("Procedure on exceeding {} limit is WELL for group {}. Well {} is {}.",
|
||||
to.first,
|
||||
group_name,
|
||||
to.second,
|
||||
"shut");
|
||||
global_deferredLogger.info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (terminal_output_) {
|
||||
global_deferredLogger.logMessages();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1400,6 +1400,94 @@ namespace WellGroupHelpers
|
||||
return std::make_pair(current_rate > target_rate, scale);
|
||||
}
|
||||
|
||||
template <class Comm>
|
||||
std::pair<std::optional<std::string>, double> worstOffendingWell( const Group& group,
|
||||
const Schedule& schedule,
|
||||
const int reportStepIdx,
|
||||
const Group::ProductionCMode& offendedControl,
|
||||
const PhaseUsage& pu,
|
||||
const Comm& comm,
|
||||
const WellState& wellState,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
std::pair<std::optional<std::string>, double> offending_well {std::nullopt, 0.0};
|
||||
for (const std::string& child_group : group.groups()) {
|
||||
const auto& this_group = schedule.getGroup(child_group, reportStepIdx);
|
||||
const auto & offending_well_this = worstOffendingWell(this_group, schedule, reportStepIdx, offendedControl, pu, comm, wellState, deferred_logger);
|
||||
if (offending_well_this.second > offending_well.second) {
|
||||
offending_well = offending_well_this;
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& child_well : group.wells()) {
|
||||
|
||||
const auto& well_index = wellState.index(child_well);
|
||||
double violating_rate = 0.0;
|
||||
double prefered_rate = 0.0;
|
||||
if (well_index.has_value() && wellState.wellIsOwned(well_index.value(), child_well))
|
||||
{
|
||||
const auto& ws = wellState.well(child_well);
|
||||
switch (offendedControl){
|
||||
case Group::ProductionCMode::ORAT:
|
||||
violating_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
|
||||
break;
|
||||
case Group::ProductionCMode::GRAT:
|
||||
violating_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Vapour]];
|
||||
break;
|
||||
case Group::ProductionCMode::WRAT:
|
||||
violating_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
|
||||
break;
|
||||
case Group::ProductionCMode::LRAT:
|
||||
assert(pu.phase_used[BlackoilPhases::Liquid]);
|
||||
assert(pu.phase_used[BlackoilPhases::Aqua]);
|
||||
violating_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]] + ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
|
||||
break;
|
||||
case Group::ProductionCMode::RESV:
|
||||
for (int p = 0; p < pu.num_phases; ++p) {
|
||||
violating_rate += ws.reservoir_rates[p];
|
||||
}
|
||||
break;
|
||||
case Group::ProductionCMode::NONE:
|
||||
break;
|
||||
case Group::ProductionCMode::FLD:
|
||||
break;
|
||||
case Group::ProductionCMode::PRBL:
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GroupProductionCMode PRBL not implemented", deferred_logger);
|
||||
break;
|
||||
case Group::ProductionCMode::CRAT:
|
||||
OPM_DEFLOG_THROW(std::runtime_error, "Group " + group.name() + "GroupProductionCMode CRAT not implemented", deferred_logger);
|
||||
break;
|
||||
|
||||
}
|
||||
const auto preferred_phase = schedule.getWell(child_well, reportStepIdx).getPreferredPhase();
|
||||
switch (preferred_phase) {
|
||||
case Phase::OIL:
|
||||
prefered_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]];
|
||||
break;
|
||||
case Phase::GAS:
|
||||
prefered_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Vapour]];
|
||||
break;
|
||||
case Phase::WATER:
|
||||
prefered_rate = ws.surface_rates[pu.phase_pos[BlackoilPhases::Aqua]];
|
||||
break;
|
||||
default:
|
||||
// No others supported.
|
||||
break;
|
||||
}
|
||||
}
|
||||
violating_rate = comm.sum(violating_rate);
|
||||
if (violating_rate < 0 ) { // only check producing wells
|
||||
prefered_rate = comm.sum(prefered_rate);
|
||||
double fraction = prefered_rate < -1e-16 ? violating_rate / prefered_rate : 1.0;
|
||||
if ( fraction > offending_well.second) {
|
||||
offending_well = {child_well, fraction};
|
||||
}
|
||||
}
|
||||
}
|
||||
return offending_well;
|
||||
};
|
||||
|
||||
|
||||
template <class AverageRegionalPressureType>
|
||||
void setRegionAveragePressureCalculator(const Group& group,
|
||||
const Schedule& schedule,
|
||||
@ -1576,6 +1664,16 @@ namespace WellGroupHelpers
|
||||
const PhaseUsage&,
|
||||
AvgPMap&);
|
||||
|
||||
template
|
||||
std::pair<std::optional<std::string>, double> worstOffendingWell<Parallel::Communication>( const Group& group,
|
||||
const Schedule& schedule,
|
||||
const int reportStepIdx,
|
||||
const Group::ProductionCMode& offendedControl,
|
||||
const PhaseUsage& pu,
|
||||
const Parallel::Communication& comm,
|
||||
const WellState& wellState,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
} // namespace WellGroupHelpers
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -179,6 +179,19 @@ namespace WellGroupHelpers
|
||||
GroupState& group_state,
|
||||
bool sum_rank);
|
||||
|
||||
|
||||
/// Returns the name of the worst offending well and its fraction (i.e. violated_phase / preferred_phase)
|
||||
template <class Comm>
|
||||
std::pair<std::optional<std::string>, double> worstOffendingWell(const Group& group,
|
||||
const Schedule& schedule,
|
||||
const int reportStepIdx,
|
||||
const Group::ProductionCMode& offendedControl,
|
||||
const PhaseUsage& pu,
|
||||
const Comm& comm,
|
||||
const WellState& wellState,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
|
||||
template <class RegionalValues>
|
||||
void updateGpMaintTargetForGroups(const Group& group,
|
||||
const Schedule& schedule,
|
||||
|
@ -289,6 +289,7 @@ public:
|
||||
last_glift_opt_time_ = 5.0;
|
||||
switched_prod_groups_ = {{"test4", "test5"}};
|
||||
switched_inj_groups_ = {{{"test4", Phase::SOLVENT}, "test5"}};
|
||||
closed_offending_wells_ = {{"test4", {"test5", "test6"}}};
|
||||
}
|
||||
|
||||
void calcRates(const int, const int, const std::vector<double>&, std::vector<double>&) override
|
||||
|
Loading…
Reference in New Issue
Block a user