From 74fa148cd7c21a0c451b6e02b07f0a85bf51da2c Mon Sep 17 00:00:00 2001 From: Vegard Kippe Date: Thu, 14 Nov 2024 12:43:50 +0100 Subject: [PATCH] Support GCONSUMP on multiple levels in the group hierarchy --- .../wells/BlackoilWellModelGeneric.cpp | 20 +++--- opm/simulators/wells/GroupState.cpp | 65 ++++++++++++++++++- opm/simulators/wells/GroupState.hpp | 12 ++++ opm/simulators/wells/WellGroupHelpers.cpp | 10 ++- 4 files changed, 91 insertions(+), 16 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index 0a66a7467..28948c05f 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -489,14 +489,12 @@ checkGconsaleLimits(const Group& group, Scalar production_target = gconsale.sales_target + injection_rate; // add import rate and subtract consumption rate for group for gas - if (schedule()[reportStepIdx].gconsump().has(group.name())) { - const auto& gconsump = schedule()[reportStepIdx].gconsump().get(group.name(), summaryState_); - if (phase_usage_.phase_used[BlackoilPhases::Vapour]) { - sales_rate += gconsump.import_rate; - sales_rate -= gconsump.consumption_rate; - production_target -= gconsump.import_rate; - production_target += gconsump.consumption_rate; - } + if (phase_usage_.phase_used[BlackoilPhases::Vapour]) { + const auto& [consumption_rate, import_rate] = this->groupState().gconsump_rates(group.name()); + sales_rate += import_rate; + sales_rate -= consumption_rate; + production_target -= import_rate; + production_target += consumption_rate; } if (sales_rate > gconsale.max_sales_rate) { @@ -1192,6 +1190,11 @@ updateAndCommunicateGroupData(const int reportStepIdx, const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx); const int nupcol = schedule()[reportStepIdx].nupcol(); + // Update accumulated group consumption/import rates for current report step + if(iterationIdx == 0) { + this->groupState().update_gconsump(schedule(), reportStepIdx, this->summaryState_); + } + // This builds some necessary lookup structures, so it must be called // before we copy to well_state_nupcol_. this->wellState().updateGlobalIsGrup(comm_); @@ -1200,6 +1203,7 @@ updateAndCommunicateGroupData(const int reportStepIdx, this->updateNupcolWGState(); } + auto& well_state = this->wellState(); const auto& well_state_nupcol = this->nupcolWellState(); // the group target reduction rates needs to be update since wells may have switched to/from GRUP control diff --git a/opm/simulators/wells/GroupState.cpp b/opm/simulators/wells/GroupState.cpp index 05431d9ed..d4ed1eaad 100644 --- a/opm/simulators/wells/GroupState.cpp +++ b/opm/simulators/wells/GroupState.cpp @@ -24,9 +24,11 @@ #include #include - +#include +#include #include + namespace Opm { template @@ -50,6 +52,7 @@ GroupState GroupState::serializationTestObject() result.m_gpmaint_target = {{"test11", 15.0}}; 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}}}; return result; } @@ -67,7 +70,8 @@ bool GroupState::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->gpmaint_state == other.gpmaint_state; + this->gpmaint_state == other.gpmaint_state && + this->m_gconsump_rates == other.m_gconsump_rates; } //------------------------------------------------------------------------- @@ -419,6 +423,63 @@ has_gpmaint_target(const std::string& gname) const return (this->m_gpmaint_target.count(gname) > 0); } +template +void GroupState:: +update_gconsump(const Schedule& schedule, const int report_step, const SummaryState& summary_state) { + this->m_gconsump_rates.clear(); + const auto& sched_state = schedule[report_step]; + const auto& gconsump = sched_state.gconsump(); + auto gcr_recursive = + [this, &sched_state, &gconsump, &summary_state](auto self, + const std::string& group_name, + std::pair& rates, + const double parent_gefac = 1.0) -> bool + { + // If group already has been computed, update parent rates and return true + const auto it = this->m_gconsump_rates.find(group_name); + if (it != this->m_gconsump_rates.end()) { + rates.first += static_cast(it->second.first * parent_gefac); + rates.second += static_cast(it->second.second * parent_gefac); + return true; + } + + // Accumulate from sub-groups and keep track of any updates in 'has_values' + bool has_values = false; + if (sched_state.groups.has(group_name)) { + for (const auto& child_gname : sched_state.groups(group_name).groups()) { + const auto gefac = sched_state.groups(child_gname).getGroupEfficiencyFactor(); + has_values = has_values || self(self, child_gname, rates, gefac); + } + } + + // Add consumption/import rates at current level + if (gconsump.has(group_name)) { + const auto& group_gc = gconsump.get(group_name, summary_state); + rates.first += static_cast(group_gc.consumption_rate); + rates.second += static_cast(group_gc.import_rate); + has_values = true; + } + + // Update map if values are set + if (has_values) this->m_gconsump_rates[group_name] = rates; + return has_values; + }; + + std::pair rates = {0.0, 0.0}; + gcr_recursive(gcr_recursive, "FIELD", rates); +} + +template +const std::pair& GroupState:: +gconsump_rates(const std::string& gname) const { + const auto it = this->m_gconsump_rates.find(gname); + if (it != this->m_gconsump_rates.end()) { + return it->second; + } + return zero_pair; +} + + template class GroupState; #if FLOW_INSTANTIATE_FLOAT diff --git a/opm/simulators/wells/GroupState.hpp b/opm/simulators/wells/GroupState.hpp index cc22cde8b..70c0bf61e 100644 --- a/opm/simulators/wells/GroupState.hpp +++ b/opm/simulators/wells/GroupState.hpp @@ -31,9 +31,14 @@ #include #include +#include namespace Opm { + class GConSump; + class Schedule; + class SummaryState; + template class GroupState { public: @@ -95,6 +100,10 @@ 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_gconsump(const Schedule& schedule, const int report_step, const SummaryState& summary_state); + const std::pair& gconsump_rates(const std::string& gname) const; + + std::size_t data_size() const; std::size_t collect(Scalar* data) const; std::size_t distribute(const Scalar* data); @@ -189,6 +198,7 @@ public: serializer(m_gpmaint_target); serializer(injection_controls); serializer(gpmaint_state); + serializer(m_gconsump_rates); } private: @@ -207,6 +217,8 @@ private: std::map, Group::InjectionCMode> injection_controls; WellContainer gpmaint_state; + std::map> m_gconsump_rates; // Pair with {consumption_rate, import_rate} for each group + static constexpr std::pair zero_pair = {0.0, 0.0}; }; } diff --git a/opm/simulators/wells/WellGroupHelpers.cpp b/opm/simulators/wells/WellGroupHelpers.cpp index b47c36b30..0d822cdee 100644 --- a/opm/simulators/wells/WellGroupHelpers.cpp +++ b/opm/simulators/wells/WellGroupHelpers.cpp @@ -700,12 +700,10 @@ updateREINForGroups(const Group& group, // add import rate and subtract consumption rate for group for gas if (sum_rank) { - if (schedule[reportStepIdx].gconsump().has(group.name())) { - const auto& gconsump = schedule[reportStepIdx].gconsump().get(group.name(), st); - if (pu.phase_used[BlackoilPhases::Vapour]) { - rein[pu.phase_pos[BlackoilPhases::Vapour]] += gconsump.import_rate; - rein[pu.phase_pos[BlackoilPhases::Vapour]] -= gconsump.consumption_rate; - } + if (pu.phase_used[BlackoilPhases::Vapour]) { + const auto& [consumption_rate, import_rate] = group_state.gconsump_rates(group.name()); + rein[pu.phase_pos[BlackoilPhases::Vapour]] += import_rate; + rein[pu.phase_pos[BlackoilPhases::Vapour]] -= consumption_rate; } }