Merge pull request #6355 from totto82/replaceGroupControlsWellsAndFix

Replace group controls wells and fix
This commit is contained in:
Tor Harald Sandve authored and GitHub committed 2025-08-08 12:40:57 +02:00
commit cb049fcd65
6 files changed
+185 -34

No files matched your search

@@ -1372,10 +1372,24 @@ updateAndCommunicateGroupData(const int reportStepIdx,
}
}
}
auto& well_state = this->wellState();
const auto& well_state_nupcol = this->nupcolWellState();
constexpr int num_configs = 4;
constexpr std::array<bool, num_configs> is_production_group = {true, false, false, false};
constexpr std::array<Phase, num_configs> phases = { Phase::OIL, Phase::WATER, Phase::OIL, Phase::GAS };
for (int i = 0; i < num_configs; i++) {
WellGroupHelpers<Scalar>::updateGroupControlledWells(schedule(),
well_state,
this->groupState(),
summaryState_,
&guideRate_,
reportStepIdx,
"FIELD",
is_production_group[i],
phases[i]);
}
// the group target reduction rates needs to be update since wells may have switched to/from GRUP control
// The group target reduction does not honor NUPCOL.
std::vector<Scalar> groupTargetReduction(numPhases(), 0.0);
@@ -2186,9 +2200,12 @@ reportGroupSwitching(DeferredLogger& local_deferredLogger) const
const Group::InjectionCMode& oldControl =
this->prevWGState().group_state.injection_control(grname, phase);
if (ctrls.back() != oldControl) {
std::ostringstream ss;
ss << phase;
const std::string msg =
fmt::format(" Injection Group {} control model changed from {} to {}",
fmt::format(" Injection Group {} (phase = {}) control model changed from {} to {}",
grname,
ss.str(),
Group::InjectionCMode2String(oldControl),
Group::InjectionCMode2String(ctrls.back()));
local_deferredLogger.info(msg);
@@ -190,8 +190,6 @@ groupControlledWells(const std::string& group_name,
return WellGroupHelpers<Scalar>::groupControlledWells(schedule_,
well_state_,
this->group_state_,
this->summary_state_,
this->guide_rate_,
report_step_,
group_name,
always_included_child,
+46
View File
@@ -54,6 +54,8 @@ GroupState<Scalar> GroupState<Scalar>::serializationTestObject()
result.injection_controls = {{{Phase::FOAM, "test12"}, Group::InjectionCMode::REIN}};
result.gpmaint_state.add("foo", GPMaint::State::serializationTestObject());
result.m_gconsump_rates = {{"testA", {0.2, 0.1}}};
result.m_number_of_wells_under_group_control = {{"test13", 3}};
result.m_number_of_wells_under_inj_group_control = {{ {Phase::WATER, "test14"}, 3}};
return result;
}
@@ -72,6 +74,8 @@ bool GroupState<Scalar>::operator==(const GroupState& other) const
this->inj_surface_rates == other.inj_surface_rates &&
this->m_grat_sales_target == other.m_grat_sales_target &&
this->injection_controls == other.injection_controls &&
this->m_number_of_wells_under_group_control == m_number_of_wells_under_group_control &&
this->m_number_of_wells_under_inj_group_control == m_number_of_wells_under_inj_group_control &&
this->gpmaint_state == other.gpmaint_state &&
this->m_gconsump_rates == other.m_gconsump_rates;
}
@@ -416,6 +420,48 @@ injection_control(const std::string& gname, Phase phase) const
return group_iter->second;
}
//-------------------------------------------------------------------------
template<class Scalar>
void GroupState<Scalar>::
update_number_of_wells_under_group_control(const std::string& gname, int number)
{
this->m_number_of_wells_under_group_control[gname] = number;
}
template<class Scalar>
int GroupState<Scalar>::
number_of_wells_under_group_control(const std::string& gname) const
{
auto group_iter = this->m_number_of_wells_under_group_control.find(gname);
if (group_iter == this->m_number_of_wells_under_group_control.end())
throw std::logic_error("No such group");
return group_iter->second;
}
//-------------------------------------------------------------------------
template<class Scalar>
void GroupState<Scalar>::
update_number_of_wells_under_inj_group_control(const std::string& gname, Phase phase, int number)
{
this->m_number_of_wells_under_inj_group_control[{phase, gname}] = number;
}
template<class Scalar>
int GroupState<Scalar>::
number_of_wells_under_inj_group_control(const std::string& gname, Phase phase) const
{
auto group_iter = this->m_number_of_wells_under_inj_group_control.find({phase, gname});
if (group_iter == this->m_number_of_wells_under_inj_group_control.end())
throw std::logic_error("No such group");
return group_iter->second;
}
//-------------------------------------------------------------------------
template<class Scalar>
+12
View File
@@ -104,6 +104,13 @@ public:
void injection_control(const std::string& gname, Phase phase, Group::InjectionCMode cmode);
Group::InjectionCMode injection_control(const std::string& gname, Phase phase) const;
void update_number_of_wells_under_group_control(const std::string& gname, int number);
int number_of_wells_under_group_control(const std::string& gname) const;
void update_number_of_wells_under_inj_group_control(const std::string& gname, Phase phase, int number);
int number_of_wells_under_inj_group_control(const std::string& gname, Phase phase) const;
void update_gconsump(const Schedule& schedule, const int report_step, const SummaryState& summary_state);
const std::pair<Scalar, Scalar>& gconsump_rates(const std::string& gname) const;
@@ -217,6 +224,8 @@ public:
serializer(injection_controls);
serializer(gpmaint_state);
serializer(m_gconsump_rates);
serializer(m_number_of_wells_under_group_control);
serializer(m_number_of_wells_under_inj_group_control);
}
private:
@@ -234,6 +243,9 @@ private:
std::map<std::string, Scalar> m_gpmaint_target;
std::map<std::string, Scalar> group_thp;
std::map<std::string, GroupPotential> production_group_potentials;
std::map<std::string, int> m_number_of_wells_under_group_control;
std::map<std::pair<Phase, std::string>, int> m_number_of_wells_under_inj_group_control;
std::map<std::pair<Phase, std::string>, Group::InjectionCMode> injection_controls;
WellContainer<GPMaint::State> gpmaint_state;
+86 -27
View File
@@ -392,7 +392,7 @@ updateGroupTargetReduction(const Group& group,
const bool individual_control = (currentGroupControl != Group::InjectionCMode::FLD
&& currentGroupControl != Group::InjectionCMode::NONE);
const int num_group_controlled_wells
= groupControlledWells(schedule, wellState, group_state, summaryState, &guide_rate, reportStepIdx, subGroupName, "", !isInjector, phase);
= groupControlledWells(schedule, wellState, group_state, reportStepIdx, subGroupName, "", !isInjector, phase);
if (individual_control || num_group_controlled_wells == 0) {
groupTargetReduction[phase_pos]
+= subGroupEfficiency * sumWellSurfaceRates(subGroup, schedule, wellState, reportStepIdx, phase_pos, isInjector);
@@ -408,7 +408,7 @@ updateGroupTargetReduction(const Group& group,
const bool individual_control = (currentGroupControl != Group::ProductionCMode::FLD
&& currentGroupControl != Group::ProductionCMode::NONE);
const int num_group_controlled_wells
= groupControlledWells(schedule, wellState, group_state, summaryState, &guide_rate, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
= groupControlledWells(schedule, wellState, group_state, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
if (individual_control || num_group_controlled_wells == 0) {
for (int phase = 0; phase < np; phase++) {
groupTargetReduction[phase]
@@ -1112,23 +1112,22 @@ getGuideRateInj(const std::string& name,
template<class Scalar>
int WellGroupHelpers<Scalar>::
groupControlledWells(const Schedule& schedule,
const WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
const SummaryState& summary_state,
const GuideRate* guideRate,
const int report_step,
const std::string& group_name,
const std::string& always_included_child,
const bool is_production_group,
const Phase injection_phase)
updateGroupControlledWells(const Schedule& schedule,
const WellState<Scalar>& well_state,
GroupState<Scalar>& group_state,
const SummaryState& summary_state,
const GuideRate* guideRate,
const int report_step,
const std::string& group_name,
const bool is_production_group,
const Phase injection_phase)
{
OPM_TIMEFUNCTION();
const Group& group = schedule.getGroup(group_name, report_step);
int num_wells = 0;
for (const std::string& child_group : group.groups()) {
bool included = (child_group == always_included_child);
bool included = false;
if (is_production_group) {
const auto ctrl = group_state.production_control(child_group);
included = included || (ctrl == Group::ProductionCMode::FLD) || (ctrl == Group::ProductionCMode::NONE);
@@ -1139,15 +1138,25 @@ groupControlledWells(const Schedule& schedule,
if (included) {
num_wells
+= groupControlledWells(schedule, well_state, group_state, summary_state, guideRate, report_step, child_group, always_included_child, is_production_group, injection_phase);
+= updateGroupControlledWells(schedule, well_state, group_state, summary_state, guideRate, report_step, child_group, is_production_group, injection_phase);
} else {
updateGroupControlledWells(schedule, well_state, group_state, summary_state, guideRate, report_step, child_group, is_production_group, injection_phase);
}
}
for (const std::string& child_well : group.wells()) {
bool included = (child_well == always_included_child);
if (is_production_group) {
included = included || well_state.isProductionGrup(child_well) || group.as_choke();
} else {
included = included || well_state.isInjectionGrup(child_well);
bool included = false;
const Well& well = schedule.getWell(child_well, report_step);
if (is_production_group && well.isProducer()) {
included = included || well_state.isProductionGrup(child_well) || group.as_choke();
} else if (!is_production_group && !well.isProducer()) {
const auto& well_controls = well.injectionControls(summary_state);
auto injectorType = well_controls.injector_type;
if ( (injection_phase == Phase::WATER && injectorType == InjectorType::WATER ) ||
(injection_phase == Phase::OIL && injectorType == InjectorType::OIL ) ||
(injection_phase == Phase::GAS && injectorType == InjectorType::GAS ))
{
included = included || well_state.isInjectionGrup(child_well);
}
}
const auto ctrl1 = group_state.production_control(group.name());
if (group.as_choke() && ((ctrl1 == Group::ProductionCMode::FLD) || (ctrl1 == Group::ProductionCMode::NONE))){
@@ -1218,6 +1227,37 @@ groupControlledWells(const Schedule& schedule,
++num_wells;
}
}
if (is_production_group) {
group_state.update_number_of_wells_under_group_control(group_name, num_wells);
} else {
group_state.update_number_of_wells_under_inj_group_control(group_name, injection_phase, num_wells);
}
return num_wells;
}
template<class Scalar>
int WellGroupHelpers<Scalar>::
groupControlledWells(const Schedule& schedule,
const WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
const int report_step,
const std::string& group_name,
const std::string& always_included_child,
const bool is_production_group,
const Phase injection_phase)
{
auto num_wells = is_production_group ? group_state.number_of_wells_under_group_control(group_name)
: group_state.number_of_wells_under_inj_group_control(group_name, injection_phase);
if (schedule.hasWell(always_included_child, report_step)) {
const bool isInGroup = isInGroupChainTopBot(always_included_child, group_name, schedule, report_step);
const bool already_included = is_production_group ? well_state.isProductionGrup(always_included_child)
: well_state.isInjectionGrup(always_included_child);
if (!already_included && isInGroup) {
num_wells++;
}
}
return num_wells;
}
@@ -1252,6 +1292,33 @@ groupChainTopBot(const std::string& bottom,
return chain;
}
template<class Scalar>
bool
WellGroupHelpers<Scalar>::
isInGroupChainTopBot(const std::string& bottom,
const std::string& top,
const Schedule& schedule,
const int report_step)
{
// Get initial parent, 'bottom' can be a well or a group.
std::string parent;
if (schedule.hasWell(bottom, report_step)) {
parent = schedule.getWell(bottom, report_step).groupName();
} else {
parent = schedule.getGroup(bottom, report_step).parent();
}
while (parent != top) {
parent = schedule.getGroup(parent, report_step).parent();
if (parent == top) {
return true;
} else if (parent == "FIELD") {
return false;
}
}
return true;
}
template<class Scalar>
std::string
WellGroupHelpers<Scalar>::
@@ -1431,8 +1498,6 @@ checkGroupConstraintsProd(const std::string& name,
const int num_gr_ctrl = groupControlledWells(schedule,
wellState,
group_state,
summaryState,
guideRate,
reportStepIdx,
chain[ii],
"",
@@ -1583,8 +1648,6 @@ getWellGroupTargetProducer(const std::string& name,
const int num_gr_ctrl = groupControlledWells(schedule,
wellState,
group_state,
summaryState,
guideRate,
reportStepIdx,
chain[ii],
"",
@@ -1737,8 +1800,6 @@ checkGroupConstraintsInj(const std::string& name,
const int num_gr_ctrl = groupControlledWells(schedule,
wellState,
group_state,
summaryState,
guideRate,
reportStepIdx,
chain[ii],
"",
@@ -1933,8 +1994,6 @@ getWellGroupTargetInjector(const std::string& name,
const int num_gr_ctrl = groupControlledWells(schedule,
wellState,
group_state,
summaryState,
guideRate,
reportStepIdx,
chain[ii],
"",
+21 -2
View File
@@ -262,11 +262,22 @@ public:
const Phase& injectionPhase,
const PhaseUsage& pu);
/// update the number of wells that are actively under group control for a given group with name given by group_name
/// its main usage is to detect cases where there is no wells under group control
static int updateGroupControlledWells(const Schedule& schedule,
const WellState<Scalar>& well_state,
GroupState<Scalar>& group_state,
const SummaryState& summary_state,
const GuideRate* guideRate,
const int report_step,
const std::string& group_name,
const bool is_production_group,
const Phase injection_phase);
/// returns the number of wells that are actively under group control for a given group with name given by group_name
static int groupControlledWells(const Schedule& schedule,
const WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
const SummaryState& summary_state,
const GuideRate* guideRate,
const int report_step,
const std::string& group_name,
const std::string& always_included_child,
@@ -314,6 +325,14 @@ public:
const Schedule& schedule,
const int report_step);
// check if well/group bottom is a sub well/group of the group top
static bool
isInGroupChainTopBot(const std::string& bottom,
const std::string& top,
const Schedule& schedule,
const int report_step);
static std::string
control_group(const Group& group,
const GroupState<Scalar>& group_state,