diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 518dab212e..6796105877 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -232,6 +232,7 @@ public: const SummaryState& summaryState() const { return summaryState_; } const GuideRate& guideRate() const { return guideRate_; } + GuideRate& guideRate() { return guideRate_; } const std::map& wellOpenTimes() const { return well_open_times_; } const std::map& wellCloseTimes() const { return well_close_times_; } diff --git a/opm/simulators/wells/BlackoilWellModelGuideRates.cpp b/opm/simulators/wells/BlackoilWellModelGuideRates.cpp index f597a13210..f294cfcbb6 100644 --- a/opm/simulators/wells/BlackoilWellModelGuideRates.cpp +++ b/opm/simulators/wells/BlackoilWellModelGuideRates.cpp @@ -388,9 +388,9 @@ getGuideRateInjectionGroupValues(const Group& group) const } template -void BlackoilWellModelGuideRates:: -assignWellGuideRates(data::Wells& wsrpt, - const int reportStepIdx) const +std::unordered_map +BlackoilWellModelGuideRates:: +calculateWellGuideRates(const int reportStepIdx) const { auto all = std::unordered_map{}; auto retrieve = std::unordered_map{}; @@ -470,7 +470,15 @@ assignWellGuideRates(data::Wells& wsrpt, // Upon completion, 'all' contains guide rate values for all wells // reachable from 'FIELD' at this time/report step. walker.traversePreOrder(); + return all; +} +template +void BlackoilWellModelGuideRates:: +assignWellGuideRates(data::Wells& wsrpt, + const int reportStepIdx) const +{ + auto all = calculateWellGuideRates(reportStepIdx); for (const auto* well : wellModel_.genericWells()) { auto xwPos = wsrpt.find(well->name()); if (xwPos == wsrpt.end()) { // No well results. Unexpected. diff --git a/opm/simulators/wells/BlackoilWellModelGuideRates.hpp b/opm/simulators/wells/BlackoilWellModelGuideRates.hpp index 33530464f9..7d43335c7c 100644 --- a/opm/simulators/wells/BlackoilWellModelGuideRates.hpp +++ b/opm/simulators/wells/BlackoilWellModelGuideRates.hpp @@ -50,6 +50,10 @@ public: : wellModel_(wellModel) {} + //! \brief Calculate guide rate values for all wells. + std::unordered_map + calculateWellGuideRates(const int reportStepIdx) const; + //! \brief Assign well guide rates. void assignWellGuideRates(data::Wells& wsrpt, const int reportStepIdx) const; diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index a0c10ee037..c632c432c9 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -79,16 +79,11 @@ namespace Opm { phase_usage, simulator.gridView().comm()) , simulator_(simulator) - , guide_rate_handler_{simulator.vanguard().schedule(), - // NOTE: The reference phase_usage passed to this constructor should be copied - // as it will be destroyed by the caller. This is also what is done in - // the parent class BlackoilWellModelGeneric and why we below use a reference - // to that copy (this->phase_usage_) instead of the the constructor parameter - // phase_usage - this->phase_usage_, + , guide_rate_handler_{ + *this, + simulator.vanguard().schedule(), simulator.vanguard().summaryState(), - simulator.vanguard().grid().comm(), - this->guideRate_ + simulator.vanguard().grid().comm() } , gaslift_(this->terminal_output_, this->phase_usage_) { @@ -1295,7 +1290,6 @@ namespace Opm { this->guide_rate_handler_.updateGuideRates( reportStepIdx, simulationTime, this->wellState(), this->groupState() ); - } // we need to re-iterate the network when the well group controls changed or gaslift/alq is changed or // the inner iterations are did not converge diff --git a/opm/simulators/wells/GuideRateHandler.cpp b/opm/simulators/wells/GuideRateHandler.cpp index a65da74e8e..36e3fefbae 100644 --- a/opm/simulators/wells/GuideRateHandler.cpp +++ b/opm/simulators/wells/GuideRateHandler.cpp @@ -17,11 +17,17 @@ along with OPM. If not, see . */ #include +#include +#include #include #include #include #include +#include + +#include + namespace Opm { // --------------------------------------------- @@ -29,18 +35,19 @@ namespace Opm { // --------------------------------------------- template GuideRateHandler::GuideRateHandler( + BlackoilWellModelGeneric& well_model, const Schedule& schedule, - const PhaseUsage& phase_usage, const SummaryState& summary_state, - const Parallel::Communication& comm, - GuideRate& guide_rate + const Parallel::Communication& comm ) : - schedule_{schedule} - , phase_usage_{phase_usage} + well_model_{well_model} + , schedule_{schedule} , summary_state_{summary_state} , comm_{comm} - , guide_rate_{guide_rate} -{ } + , phase_usage_{well_model_.phaseUsage()} + , guide_rate_{well_model_.guideRate()} +{ +} // ---------------------------------------------------------- @@ -56,6 +63,31 @@ deferredLogger() return *this->deferred_logger_; } +// This is an alternative to plotting the summary keywords: +// - GOPGR (group oil production guide rate), +// - WOPGR (well oil production guide rate), +// - GWPGR (group water production guide rate), +// - WWPGR (well water production guide rate), +// - GGPGR (group gas production guide rate), +// - WGPGR (well gas production guide rate), +// - GGIGR (group gas injection guide rate), +// - WGIGR (well gas injection guide rate), +// - GWIGR (group water injection guide rate), +// - WWIGR (well water injection guide rate), +// - GVPGR (group reservoir volume production guide rate), +// - WVPGR (well reservoir volume production guide rate), +template +void +GuideRateHandler:: +debugDumpGuideRates(const int report_step_idx, const double sim_time) +{ + if (this->comm_.rank() == 0) { + GuideRateDumper dumper{*this, report_step_idx, sim_time}; + dumper.dumpGuideRates(); + } +} + + #ifdef RESERVOIR_COUPLING_ENABLED template void @@ -137,6 +169,266 @@ updateGuideRates( } +// ------------------------------------------ +// Inner class GuideRateDumper constructor +// ------------------------------------------ + +template +GuideRateHandler::GuideRateDumper:: +GuideRateDumper( + GuideRateHandler &parent, const int report_step_idx, const double sim_time +) : parent_{parent} + , report_step_idx_{report_step_idx} + , sim_time_{sim_time} + , well_model_{parent.wellModel()} + , schedule_{parent.schedule()} + , comm_{parent.getComm()} +{ +} + +// --------------------------------------------------------------------- +// Public methods for inner class GuideRateDumper sorted alphabetically +// --------------------------------------------------------------------- + +template +void +GuideRateHandler::GuideRateDumper:: +dumpGuideRates() +{ + if (this->comm_.rank() == 0) { + auto calcGR = BlackoilWellModelGuideRates{this->well_model_}; + this->well_guide_rates_ = calcGR.calculateWellGuideRates(this->report_step_idx_); + this->group_guide_rates_ = calcGR.calculateAllGroupGuideRates(this->report_step_idx_); + const auto& group = this->schedule_.getGroup("FIELD", this->report_step_idx_); + printHeader_(); + int level = 0; // 0 is the root level + this->dumpGuideRatesRecursive_(group, level); + printTrailer_(); + } +} + +// ---------------------------------------------------------- +// Private methods for GuideRateHandler sorted alphabetically +// ----------------------------------------------------------- + + +template +void +GuideRateHandler::GuideRateDumper:: +dumpGuideRatesRecursive_(const Group& group, int level) +{ + if (group.name() != "FIELD") { + this->printGroupGuideRates_(group, level); + } + for (const std::string& group_name : group.groups()) { + const Group& group_tmp = this->schedule_.getGroup(group_name, this->report_step_idx_); + this->dumpGuideRatesRecursive_(group_tmp, level+1); + } + for (const std::string& well_name : group.wells()) { + const auto& well_tmp = this->schedule_.getWell(well_name, this->report_step_idx_); + printWellGuideRates_(well_tmp, level+1); + } +} + +template +void +GuideRateHandler::GuideRateDumper:: +getGroupGuideRatesInjection_( + const Group& group, + const data::GroupGuideRates& group_guide_rate, + std::vector& msg_items +) const +{ + // NOTE: See comment in getGroupGuideRatesProduction_() for a discussion of the + // different types of group guiderate enums. + const auto& wm_guide_rate = this->well_model_.guideRate(); + const auto& name = group.name(); + using Value = data::GuideRateValue::Item; + constexpr std::pair phase_value_pairs[] = { + {Phase::OIL, Value::Oil}, + {Phase::GAS, Value::Gas}, + {Phase::WATER, Value::Water} + }; + const auto& guide_rate_value = group_guide_rate.production; + for (const auto& [phase, value] : phase_value_pairs) { + if (wm_guide_rate.has(name, phase)) { + if (guide_rate_value.has(value)) { + msg_items.push_back( + fmt::format( + "{}(Group Inj, {}): {}", + guide_rate_value.itemName(value), + guide_rate_value.get(value) + ) + ); + } + } + } +} + +template +void +GuideRateHandler::GuideRateDumper:: +getGroupGuideRatesProduction_( + const Group& group, + const data::GroupGuideRates& group_guide_rate, + std::vector& msg_items +) const +{ + // NOTE: There are many different types of group guide rate phase target enums that are + // used in different contexts: + // - Group.hpp defines Group::GuideRateProdTarget and Group::GuideRateInjTarget + // - Production: OIL, WAT, GAS, LIQ, RES, COMB, WGA, CVAL, INJV, POTN, FORM + // - These are defined by item 9 of GCONPROD and used if item 10 of GCONPROD is not + // set to FORM. + // - Injection: RATE, VOID, NETV, RESV + // - GuideRateModel.hpp defines GuideRateModel::Target + // - OIL, LIQ, GAS, WAT, RES, COMB, NONE + // - These are defined by item 2 of GUIDERAT. + // - These are used if item 10 of GCONPROD is set to FORM, then the guide rate set in + // item 9 of GCONPROD is ignored. + // - Phase.hpp defines the Phase enum which is used by BlackoilWellModelGuideRates.cpp and + // GuideRate.cpp + // - OIL, GAS, WATER, SOLVENT, POLYMER, ENERGY, POLYMW, FOAM, BRINE + // - Only OIL, GAS, WATER are used in the context of guide rates and only for + // injection groups. And only GAS and WATER are checked for in + // getGuideRateInjectionGroupValues() in BlackoilWellModelGuideRates.cpp. + // - GuideRateValue.hpp defines GuideRateValue::Item which is used by + // BlackoilWellModelGuideRates.cpp to assign guide rates. The values are: + // - Oil, Gas, Water, ResV + // - However, ResV is not implemented, see getGuideRateValues() in + // BlackoilWellModelGuideRates.cpp. This, despite the summary keywords GVPGR and WVPGR + // are using it, see Summary.cpp. TODO: Check if this is a bug. + const auto& wm_guide_rate = this->well_model_.guideRate(); + const auto& name = group.name(); + if (wm_guide_rate.has(name)) { // Check if group has production guiderates + constexpr data::GuideRateValue::Item value_types[] = { + data::GuideRateValue::Item::Oil, + data::GuideRateValue::Item::Gas, + data::GuideRateValue::Item::Water, + data::GuideRateValue::Item::ResV + }; + const auto& guide_rate_value = group_guide_rate.production; + for (const auto& value_type : value_types) { + if (guide_rate_value.has(value_type)) { + msg_items.push_back( + fmt::format( + "{}(Group Prod, {}): {}", + name, + guide_rate_value.itemName(value_type), + guide_rate_value.get(value_type) + ) + ); + } + } + } +} + + +template +void +GuideRateHandler::GuideRateDumper:: +printGroupGuideRates_(const Group& group, int level) +{ + const auto& name = group.name(); + assert( level >= 1 ); + std::string indent(level - 1, ' '); + auto gr_itr = this->group_guide_rates_.find(name); + if (gr_itr == this->group_guide_rates_.end()) { + this->deferredLogger().debug( + fmt::format("{}{}: ", indent, name) + ); + return; + } + const auto& group_guide_rate = gr_itr->second; + std::vector msg_items; + getGroupGuideRatesProduction_(group, group_guide_rate, msg_items); + getGroupGuideRatesInjection_(group, group_guide_rate, msg_items); + if (msg_items.empty()) { + this->deferredLogger().debug( + fmt::format("{}{}(Group): ", indent, name) + ); + return; + } + this->deferredLogger().debug( + fmt::format("{}{}", indent, fmt::join(msg_items, ", ")) + ); +} + +template +void +GuideRateHandler::GuideRateDumper:: +printHeader_() +{ + this->deferredLogger().debug( + fmt::format( + "\n---- GUIDE RATE REPORT: step {}, simtime {} ----", + this->report_step_idx_, + this->sim_time_ + ) + ); +} + +template +void +GuideRateHandler::GuideRateDumper:: +printTrailer_() +{ + this->deferredLogger().debug( + fmt::format( + "---- END GUIDE RATE REPORT: step {}, simtime {} ----\n", + this->report_step_idx_, + this->sim_time_ + ) + ); +} + +template +void +GuideRateHandler::GuideRateDumper:: +printWellGuideRates_(const Well& well, int level) +{ + const auto& name = well.name(); + assert( level >= 1 ); + std::string indent(level - 1, ' '); + auto gr_itr = this->well_guide_rates_.find(name); + if (gr_itr == this->well_guide_rates_.end()) { + this->deferredLogger().debug( + fmt::format("{}{}: ", indent, name) + ); + return; + } + const auto& guide_rate_value = gr_itr->second; + std::vector msg_items; + constexpr data::GuideRateValue::Item value_types[] = { + data::GuideRateValue::Item::Oil, + data::GuideRateValue::Item::Gas, + data::GuideRateValue::Item::Water + }; + const std::string well_type = well.isInjector() ? "Inj" : "Prod"; + for (const auto& value_type : value_types) { + if (guide_rate_value.has(value_type)) { + msg_items.push_back( + fmt::format( + "{}(Well {}, {}): {}", + name, + well_type, + guide_rate_value.itemName(value_type), + guide_rate_value.get(value_type) + ) + ); + } + } + if (msg_items.empty()) { + this->deferredLogger().debug( + fmt::format("{}{}(Well {}): ", indent, name, well_type) + ); + return; + } + this->deferredLogger().debug( + fmt::format("{}{}", indent, fmt::join(msg_items, ", ")) + ); +} + // ------------------------------------------ // Inner class UpdateGuideRates constructor // ------------------------------------------ diff --git a/opm/simulators/wells/GuideRateHandler.hpp b/opm/simulators/wells/GuideRateHandler.hpp index fdb900fbd3..e2ad1c7639 100644 --- a/opm/simulators/wells/GuideRateHandler.hpp +++ b/opm/simulators/wells/GuideRateHandler.hpp @@ -29,8 +29,12 @@ #include #endif #include +#include +#include #include #include +#include +#include #include #include namespace Opm { @@ -40,6 +44,41 @@ class GuideRateHandler { public: using Potentials = ReservoirCoupling::Potentials; + class GuideRateDumper { + public: + GuideRateDumper( + GuideRateHandler &parent, const int report_step_idx, const double sim_time + ); + + DeferredLogger &deferredLogger() { return this->parent_.deferredLogger(); } + void dumpGuideRates(); + private: + void dumpGuideRatesRecursive_(const Group& group, int level); + void getGroupGuideRatesInjection_( + const Group& group, + const data::GroupGuideRates& group_guide_rate, + std::vector& msg_items + ) const; + void getGroupGuideRatesProduction_( + const Group& group, + const data::GroupGuideRates& group_guide_rate, + std::vector& msg_items + ) const; + void printGroupGuideRates_(const Group& group, int level); + void printHeader_(); + void printTrailer_(); + void printWellGuideRates_(const Well& well, int level); + + GuideRateHandler &parent_; + const int report_step_idx_; + const double sim_time_; + const BlackoilWellModelGeneric& well_model_; + const Schedule& schedule_; + const Parallel::Communication& comm_; + std::unordered_map well_guide_rates_; + std::unordered_map group_guide_rates_; + }; + class UpdateGuideRates { public: UpdateGuideRates( @@ -87,11 +126,10 @@ public: }; GuideRateHandler( + BlackoilWellModelGeneric& well_model, const Schedule& schedule, - const PhaseUsage& phase_usage, const SummaryState& summary_state, - const Parallel::Communication& comm, - GuideRate& guide_rate + const Parallel::Communication& comm ); #ifdef RESERVOIR_COUPLING_ENABLED @@ -113,18 +151,24 @@ public: } #endif DeferredLogger& deferredLogger(); + void debugDumpGuideRates(const int report_step_idx, const double sim_time); + const Parallel::Communication& getComm() const { return comm_; } void setLogger(DeferredLogger *deferred_logger); + const Schedule& schedule() const { return schedule_; } void updateGuideRates( const int report_step_idx, const double sim_time, WellState &well_state, GroupState &group_state ); + const BlackoilWellModelGeneric& wellModel() const { return well_model_; } private: + void debugDumpGuideRatesRecursive_(const Group& group) const; + BlackoilWellModelGeneric& well_model_; const Schedule& schedule_; - const PhaseUsage& phase_usage_; const SummaryState& summary_state_; const Parallel::Communication& comm_; + const PhaseUsage& phase_usage_; GuideRate& guide_rate_; DeferredLogger *deferred_logger_ = nullptr; #ifdef RESERVOIR_COUPLING_ENABLED