From 934134ec9ddcce832af073402df3fad3f603d8cc Mon Sep 17 00:00:00 2001 From: Stein Krogstad Date: Mon, 8 Sep 2025 15:38:16 +0200 Subject: [PATCH] Include satellite injection, update satellite production --- .../utils/PartiallySupportedFlowKeywords.cpp | 6 ++ .../utils/UnsupportedFlowKeywords.cpp | 1 - opm/simulators/wells/WellGroupHelpers.cpp | 99 ++++++++++++------- opm/simulators/wells/WellGroupHelpers.hpp | 15 ++- 4 files changed, 81 insertions(+), 40 deletions(-) diff --git a/opm/simulators/utils/PartiallySupportedFlowKeywords.cpp b/opm/simulators/utils/PartiallySupportedFlowKeywords.cpp index 14b6cc6155..00dd83dd28 100644 --- a/opm/simulators/utils/PartiallySupportedFlowKeywords.cpp +++ b/opm/simulators/utils/PartiallySupportedFlowKeywords.cpp @@ -577,6 +577,12 @@ partiallySupported() {20,{true, allow_values {}, "GCONPROD(COMBRATE): linearly combined rate is not used and should be defaulted (1*)"}}, // LINEAR_COMBINED_TARGET }, }, + { + "GSATINJE", + { + {4,{true, allow_values {.0}, "GSATINJE(RESV): reservoir volume rate is not supported and should be defaulted (1*)"}}, // RESERVOIR_VOLUME_RATE + }, + }, { "GUIDERAT", { diff --git a/opm/simulators/utils/UnsupportedFlowKeywords.cpp b/opm/simulators/utils/UnsupportedFlowKeywords.cpp index 657ee86cc9..af83de83c1 100644 --- a/opm/simulators/utils/UnsupportedFlowKeywords.cpp +++ b/opm/simulators/utils/UnsupportedFlowKeywords.cpp @@ -246,7 +246,6 @@ const KeywordValidation::UnsupportedKeywords& unsupportedKeywords() {"GRUPRIG", {true, std::nullopt}}, {"GRUPSLAV", {true, std::nullopt}}, {"GRUPTARG", {true, std::nullopt}}, - {"GSATINJE", {true, std::nullopt}}, {"GSEPCOND", {true, std::nullopt}}, {"GSSCPTST", {true, std::nullopt}}, {"GSWINGF", {true, std::nullopt}}, diff --git a/opm/simulators/wells/WellGroupHelpers.cpp b/opm/simulators/wells/WellGroupHelpers.cpp index f8bf5d5f85..2ec33a4628 100644 --- a/opm/simulators/wells/WellGroupHelpers.cpp +++ b/opm/simulators/wells/WellGroupHelpers.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -94,25 +95,27 @@ namespace Opm { const bool injector, const bool network) { - + // Only obtain satellite rates once (on rank 0) Scalar rate = 0.0; + if (wellState.isRank0() && (group.hasSatelliteProduction() || group.hasSatelliteInjection())) { + if (injector) { + rate = satelliteInjectionRate(schedule[reportStepIdx], group, wellState.phaseUsageInfo(), phasePos, res_rates); + } else { + const auto rateComp = selectRateComponent(wellState.phaseUsageInfo(), phasePos); + if (rateComp.has_value()) { + rate = satelliteProductionRate(summaryState, schedule[reportStepIdx], group, *rateComp, res_rates); + } + } + // Satellite groups have no sub groups/wells so we're done + return rate; + } + for (const std::string& groupName : group.groups()) { const auto& groupTmp = schedule.getGroup(groupName, reportStepIdx); const auto& gefac = groupTmp.getGroupEfficiencyFactor(network); rate += gefac * sumWellPhaseRates(res_rates, groupTmp, schedule, wellState, summaryState, reportStepIdx, phasePos, injector, network); } - // only sum satellite production once - // With the current treatment, satellite production must also explicitly be accounted for in - // updateGroupTargetReduction. A cleaner solution would perhaps be to let sumWellPhaseRates return - // the satellite production directly (it currently returns zero for satellite groups). - if (wellState.isRank0() && !injector) { - const auto rateComp = selectRateComponent(wellState.phaseUsageInfo(), phasePos); - if (rateComp.has_value()) { - rate += satelliteProduction(summaryState, schedule[reportStepIdx], group.groups(), *rateComp); - } - } - for (const std::string& wellName : group.wells()) { const auto well_index = wellState.index(wellName); if (!well_index.has_value()) @@ -152,20 +155,58 @@ namespace Opm { template Scalar WellGroupHelpers:: -satelliteProduction(const SummaryState& summaryState, - const ScheduleState& sched, - const std::vector& groups, - const GSatProd::GSatProdGroupProp::Rate rateComp) +satelliteInjectionRate(const ScheduleState& sched, + const Group& group, + const PhaseUsageInfo& pu, + const int phase_pos, + bool res_rates) { - auto gsatProdRate = Scalar{}; - const auto& gsatProd = sched.gsatprod(); - for (const auto& group : groups) { - if (! gsatProd.has(group)) { - continue; + Scalar rate = 0.0; + if (group.hasSatelliteInjection()) { + std::optional ph; + for (const auto& [bo_phase, phase] : std::array { + std::pair( IndexTraits::waterPhaseIdx, Phase::WATER), + std::pair( IndexTraits::oilPhaseIdx, Phase::OIL), + std::pair( IndexTraits::gasPhaseIdx, Phase::GAS) }) + { + if (pu.phaseIsActive(bo_phase) && (pu.canonicalToActivePhaseIdx(bo_phase) == phase_pos)) { + ph = phase; + } + } + if (ph.has_value()) { + const auto& satellite_inj = sched.satelliteInjection(group.name()); + const auto& rate_ix = satellite_inj.rateIndex(ph.value()); + if (rate_ix.has_value()) { + const auto& satrates = satellite_inj[*rate_ix]; + if (!res_rates) { // surface rates + if (const auto& qs = satrates.surface(); qs.has_value()) { + rate = *qs; + } + // We don't support reservoir rates for satellite injection groups + } + } } - gsatProdRate += gsatProd.get(group, summaryState).rate[rateComp]; } - return gsatProdRate; + return rate; +} + +template +Scalar WellGroupHelpers:: +satelliteProductionRate(const SummaryState& summaryState, + const ScheduleState& sched, + const Group& group, + const GSatProd::GSatProdGroupProp::Rate rateComp, + bool res_rates) +{ + Scalar rate = 0.0; + if (group.hasSatelliteProduction()) { + const auto& gsatProd = sched.gsatprod(); + if (!res_rates) { + rate = gsatProd.get(group.name(), summaryState).rate[rateComp]; + } + // We don't support reservoir rates for satellite production groups + } + return rate; } template @@ -439,18 +480,6 @@ updateGroupTargetReduction(const Group& group, } } - // only sum satellite production once - // With the current treatment, satellite rates here must be added to target reduction excactly the same - // way as in sumWellPhaseRates (see comment there) - if (wellState.isRank0()) { - for (int phase = 0; phase < np; phase++) { - const auto rateComp = selectRateComponent(wellState.phaseUsageInfo(), phase); - if (rateComp.has_value()) { - groupTargetReduction[phase] += satelliteProduction(summaryState, schedule[reportStepIdx], group.groups(), *rateComp); - } - } - } - for (const std::string& wellName : group.wells()) { const auto& wellTmp = schedule.getWell(wellName, reportStepIdx); diff --git a/opm/simulators/wells/WellGroupHelpers.hpp b/opm/simulators/wells/WellGroupHelpers.hpp index c0c1dfecf4..9b3cbb641b 100644 --- a/opm/simulators/wells/WellGroupHelpers.hpp +++ b/opm/simulators/wells/WellGroupHelpers.hpp @@ -63,10 +63,17 @@ public: const bool injector, const bool network = false); - static Scalar satelliteProduction(const SummaryState& summaryState, - const ScheduleState& sched, - const std::vector& groups, - const GSatProd::GSatProdGroupProp::Rate rateComp); + static Scalar satelliteInjectionRate(const ScheduleState& sched, + const Group& group, + const PhaseUsageInfo& pu, + const int phase_pos, + bool res_rates); + + static Scalar satelliteProductionRate(const SummaryState& summaryState, + const ScheduleState& sched, + const Group& group, + const GSatProd::GSatProdGroupProp::Rate rateComp, + bool res_rates); static std::optional selectRateComponent(const PhaseUsageInfo& pu, const int phasePos);