From 01dfe23a507f3fe2c1b4015d68bc31cc60d09f59 Mon Sep 17 00:00:00 2001 From: Arne Morten Kvarving Date: Mon, 24 Oct 2022 09:36:05 +0200 Subject: [PATCH] move assignWellGuideRates into BlackoilWellModelGuideRates --- opm/simulators/wells/BlackoilWellModel.hpp | 3 +- .../wells/BlackoilWellModelGeneric.cpp | 154 -------- .../wells/BlackoilWellModelGeneric.hpp | 2 - .../wells/BlackoilWellModelGuideRates.cpp | 339 ++++++++++++++++++ .../wells/BlackoilWellModelGuideRates.hpp | 9 +- 5 files changed, 349 insertions(+), 158 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index e25ff5ab3..b84ce54a7 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,7 @@ namespace Opm { this->assignWellTracerRates(wsrpt); - this->assignWellGuideRates(wsrpt, this->reportStepIndex()); + BlackoilWellModelGuideRates(*this).assignWellGuideRates(wsrpt, this->reportStepIndex()); this->assignShutConnections(wsrpt, this->reportStepIndex()); return wsrpt; diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index a31f63feb..17870ec23 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -59,52 +59,6 @@ #include namespace { - struct RetrieveWellGuideRate - { - RetrieveWellGuideRate() = default; - - explicit RetrieveWellGuideRate(const Opm::GuideRate& guideRate, - const std::string& wgname); - - explicit RetrieveWellGuideRate(const Opm::GuideRate& guideRate, - const Opm::Group& group); - - bool prod { false }; - bool inj_water { false }; - bool inj_gas { false }; - }; - - RetrieveWellGuideRate - operator||(RetrieveWellGuideRate lhs, const RetrieveWellGuideRate& rhs) - { - lhs.prod = lhs.prod || rhs.prod; - lhs.inj_water = lhs.inj_water || rhs.inj_water; - lhs.inj_gas = lhs.inj_gas || rhs.inj_gas; - - return lhs; - } - - RetrieveWellGuideRate::RetrieveWellGuideRate(const Opm::GuideRate& guideRate, - const std::string& wgname) - : prod { guideRate.has(wgname) } - , inj_water { guideRate.has(wgname, Opm::Phase::WATER) } - , inj_gas { guideRate.has(wgname, Opm::Phase::GAS) } - {} - - RetrieveWellGuideRate::RetrieveWellGuideRate(const Opm::GuideRate& guideRate, - const Opm::Group& group) - : RetrieveWellGuideRate{ guideRate, group.name() } - { - if (group.isProductionGroup()) { - this->prod = true; - } - - if (group.isInjectionGroup()) { - this->inj_water = this->inj_water || group.hasInjectionControl(Opm::Phase::WATER); - this->inj_gas = this->inj_gas || group.hasInjectionControl(Opm::Phase::GAS); - } - } - class GroupTreeWalker { public: @@ -135,7 +89,6 @@ namespace { this->visitWell_ = WellOp{}; } - void traversePreOrder(); void traversePostOrder(); private: @@ -169,14 +122,6 @@ namespace { const Opm::Well& getWell(std::string_view well) const; }; - void GroupTreeWalker::traversePreOrder() - { - this->preFinish_ = nullptr; - this->postDiscover_ = &GroupTreeWalker::visitGroup; - - this->traverse(); - } - void GroupTreeWalker::traversePostOrder() { this->preFinish_ = &GroupTreeWalker::visitGroup; @@ -929,105 +874,6 @@ setWsolvent(const Group& group, } } -void -BlackoilWellModelGeneric:: -assignWellGuideRates(data::Wells& wsrpt, - const int reportStepIdx) const -{ - auto all = std::unordered_map{}; - auto retrieve = std::unordered_map{}; - - auto walker = GroupTreeWalker{ this->schedule(), reportStepIdx }; - - // Populates 'retrieve'. - walker.groupOp([this, &retrieve](const Group& group) - { - const auto& gname = group.name(); - - const auto parent = (gname == "FIELD") - ? RetrieveWellGuideRate{} - : retrieve[group.parent()]; - - auto [elm, inserted] = - retrieve.emplace(std::piecewise_construct, - std::forward_as_tuple(gname), - std::forward_as_tuple(this->guideRate_, group)); - - if (inserted) { - elm->second = elm->second || parent; - } - }); - - // Populates 'all'. - walker.wellOp([this, &retrieve, &all](const Well& well) - { - const auto& wname = well.name(); - - const auto is_nontrivial = - this->guideRate_.has(wname) || this->guideRate_.hasPotentials(wname); - - if (! (is_nontrivial && this->wellState().has(wname))) { - all[wname].clear(); - return; - } - - auto parent_pos = retrieve.find(well.groupName()); - const auto parent = (parent_pos == retrieve.end()) - ? RetrieveWellGuideRate{} // No entry for 'parent'--unexpected. - : parent_pos->second; - - const auto get_gr = parent - || RetrieveWellGuideRate{ this->guideRate_, wname }; - - const auto qs = WellGroupHelpers:: - getWellRateVector(this->wellState(), this->phase_usage_, wname); - - auto getGR = [this, &wname, &qs](const GuideRateModel::Target t) - { - return this->guideRate_.getSI(wname, t, qs); - }; - - auto& grval = all[wname]; - - if (well.isInjector()) { - if (get_gr.inj_gas) { // Well supports WGIGR - grval.set(data::GuideRateValue::Item::Gas, - getGR(GuideRateModel::Target::GAS)); - } - if (get_gr.inj_water) { // Well supports WWIGR - grval.set(data::GuideRateValue::Item::Water, - getGR(GuideRateModel::Target::WAT)); - } - } - else if (get_gr.prod) { // Well is producer AND we want/support WxPGR - grval - .set(data::GuideRateValue::Item::Oil , getGR(GuideRateModel::Target::OIL)) - .set(data::GuideRateValue::Item::Gas , getGR(GuideRateModel::Target::GAS)) - .set(data::GuideRateValue::Item::Water, getGR(GuideRateModel::Target::WAT)); - } - }); - - // Visit groups before their children, meaning no well is visited until - // all of its upline parent groups--up to FIELD--have been visited. - // Upon completion, 'all' contains guide rate values for all wells - // reachable from 'FIELD' at this time/report step. - walker.traversePreOrder(); - - for (const auto& well : this->wells_ecl_) { - auto xwPos = wsrpt.find(well.name()); - if (xwPos == wsrpt.end()) { // No well results. Unexpected. - continue; - } - - auto grPos = all.find(well.name()); - if (grPos == all.end()) { - continue; - } - - xwPos->second.guide_rates = grPos->second; - } -} - void BlackoilWellModelGeneric:: assignShutConnections(data::Wells& wsrpt, diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index 35ffa9204..cde18dd5f 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -271,8 +271,6 @@ protected: const int pvtreg, std::vector& resv_coeff) = 0; - void assignWellGuideRates(data::Wells& wsrpt, - const int reportStepIdx) const; void assignShutConnections(data::Wells& wsrpt, const int reportStepIndex) const; void assignGroupControl(const Group& group, diff --git a/opm/simulators/wells/BlackoilWellModelGuideRates.cpp b/opm/simulators/wells/BlackoilWellModelGuideRates.cpp index 098f370ee..fd006795b 100644 --- a/opm/simulators/wells/BlackoilWellModelGuideRates.cpp +++ b/opm/simulators/wells/BlackoilWellModelGuideRates.cpp @@ -23,12 +23,253 @@ #include #include +#include #include #include #include #include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +struct RetrieveWellGuideRate +{ + RetrieveWellGuideRate() = default; + + explicit RetrieveWellGuideRate(const Opm::GuideRate& guideRate, + const std::string& wgname); + + explicit RetrieveWellGuideRate(const Opm::GuideRate& guideRate, + const Opm::Group& group); + + bool prod { false }; + bool inj_water { false }; + bool inj_gas { false }; +}; + +RetrieveWellGuideRate +operator||(RetrieveWellGuideRate lhs, const RetrieveWellGuideRate& rhs) +{ + lhs.prod = lhs.prod || rhs.prod; + lhs.inj_water = lhs.inj_water || rhs.inj_water; + lhs.inj_gas = lhs.inj_gas || rhs.inj_gas; + + return lhs; +} + +RetrieveWellGuideRate::RetrieveWellGuideRate(const Opm::GuideRate& guideRate, + const std::string& wgname) + : prod { guideRate.has(wgname) } + , inj_water { guideRate.has(wgname, Opm::Phase::WATER) } + , inj_gas { guideRate.has(wgname, Opm::Phase::GAS) } +{} + +RetrieveWellGuideRate::RetrieveWellGuideRate(const Opm::GuideRate& guideRate, + const Opm::Group& group) + : RetrieveWellGuideRate{ guideRate, group.name() } +{ + if (group.isProductionGroup()) { + this->prod = true; + } + + if (group.isInjectionGroup()) { + this->inj_water = this->inj_water || group.hasInjectionControl(Opm::Phase::WATER); + this->inj_gas = this->inj_gas || group.hasInjectionControl(Opm::Phase::GAS); + } +} + +class GroupTreeWalker +{ +public: + using GroupOp = std::function; + using WellOp = std::function; + + explicit GroupTreeWalker(const Opm::Schedule& sched, + const int reportStepIdx) + : sched_ (sched) + , reportStepIdx_(reportStepIdx) + {} + + GroupTreeWalker& groupOp(GroupOp visit) + { + this->visitGroup_ = std::move(visit); + return *this; + } + + GroupTreeWalker& wellOp(WellOp visit) + { + this->visitWell_ = std::move(visit); + return *this; + } + + void clear() + { + this->visitGroup_ = GroupOp{}; + this->visitWell_ = WellOp{}; + } + + void traversePreOrder(); + +private: + using NodeOp = void (GroupTreeWalker::*)(std::string_view) const; + + std::reference_wrapper sched_; + int reportStepIdx_; + + GroupOp visitGroup_{}; + WellOp visitWell_{}; + + std::stack> dfsGroupStack_{}; + std::unordered_set dfsGroupDiscovered_{}; + + NodeOp postDiscover_{nullptr}; + NodeOp preFinish_{nullptr}; + + void traverse(); + + void startWalk(); + void discover(std::string_view group); + void finish(std::string_view group); + + bool isSeen(std::string_view group) const; + std::size_t insertIndex(std::string_view group) const; + + void visitGroup(std::string_view group) const; + void visitWell(std::string_view well) const; + + const Opm::Group& getGroup(std::string_view group) const; + const Opm::Well& getWell(std::string_view well) const; +}; + +void GroupTreeWalker::traversePreOrder() +{ + this->preFinish_ = nullptr; + this->postDiscover_ = &GroupTreeWalker::visitGroup; + + this->traverse(); +} + +void GroupTreeWalker::traverse() +{ + this->startWalk(); + + while (! this->dfsGroupStack_.empty()) { + const auto gname = this->dfsGroupStack_.top(); + + if (this->isSeen(gname)) { + if (this->preFinish_ != nullptr) { + (this->*preFinish_)(gname); + } + + this->finish(gname); + continue; + } + + this->discover(gname); + + if (this->postDiscover_ != nullptr) { + (this->*postDiscover_)(gname); + } + + const auto& group = this->getGroup(gname); + + if (! group.wellgroup()) { // Node group. Register child groups. + for (const auto& child : group.groups()) { + if (! this->isSeen(child)) { + this->dfsGroupStack_.push(child); + } + } + } + else { // Group is a well group--visit its wells. + for (const auto& well : group.wells()) { + this->visitWell(well); + } + } + } +} + +void GroupTreeWalker::startWalk() +{ + this->dfsGroupDiscovered_.clear(); + + while (! this->dfsGroupStack_.empty()) { + this->dfsGroupStack_.pop(); + } + + this->dfsGroupStack_.push("FIELD"); +} + +void GroupTreeWalker::discover(std::string_view group) +{ + this->dfsGroupDiscovered_.insert(this->insertIndex(group)); +} + +void GroupTreeWalker::finish(std::string_view group) +{ + if (this->dfsGroupStack_.top() != group) { + throw std::invalid_argument { + fmt::format("Internal Error: Expected group '{}', but got '{}'", + group, this->dfsGroupStack_.top()) + }; + } + + this->dfsGroupStack_.pop(); +} + +bool GroupTreeWalker::isSeen(std::string_view group) const +{ + return this->dfsGroupDiscovered_.find(this->insertIndex(group)) + != this->dfsGroupDiscovered_.end(); +} + +std::size_t GroupTreeWalker::insertIndex(std::string_view group) const +{ + return this->getGroup(group).insert_index(); +} + +void GroupTreeWalker::visitGroup(std::string_view group) const +{ + if (! this->visitGroup_) { + return; + } + + this->visitGroup_(this->getGroup(group)); +} + +void GroupTreeWalker::visitWell(std::string_view well) const +{ + if (! this->visitWell_) { + return; + } + + this->visitWell_(this->getWell(well)); +} + +const Opm::Group& GroupTreeWalker::getGroup(std::string_view group) const +{ + return this->sched_.get().getGroup({group.data(), group.size()}, this->reportStepIdx_); +} + +const Opm::Well& GroupTreeWalker::getWell(std::string_view well) const +{ + return this->sched_.get().getWell({well.data(), well.size()}, this->reportStepIdx_); +} + +} // anonymous namespace namespace Opm { @@ -133,4 +374,102 @@ getGuideRateInjectionGroupValues(const Group& group) const return grval; } +void BlackoilWellModelGuideRates:: +assignWellGuideRates(data::Wells& wsrpt, + const int reportStepIdx) const +{ + auto all = std::unordered_map{}; + auto retrieve = std::unordered_map{}; + + auto walker = GroupTreeWalker{wellModel_.schedule(), reportStepIdx}; + + // Populates 'retrieve'. + walker.groupOp([this, &retrieve](const Group& group) + { + const auto& gname = group.name(); + + const auto parent = (gname == "FIELD") + ? RetrieveWellGuideRate{} + : retrieve[group.parent()]; + + auto [elm, inserted] = + retrieve.emplace(std::piecewise_construct, + std::forward_as_tuple(gname), + std::forward_as_tuple(wellModel_.guideRate(), group)); + + if (inserted) { + elm->second = elm->second || parent; + } + }); + + // Populates 'all'. + walker.wellOp([this, &retrieve, &all](const Well& well) + { + const auto& wname = well.name(); + + const auto is_nontrivial = + wellModel_.guideRate().has(wname) || wellModel_.guideRate().hasPotentials(wname); + + if (! (is_nontrivial && wellModel_.wellState().has(wname))) { + all[wname].clear(); + return; + } + + auto parent_pos = retrieve.find(well.groupName()); + const auto parent = (parent_pos == retrieve.end()) + ? RetrieveWellGuideRate{} // No entry for 'parent'--unexpected. + : parent_pos->second; + + const auto get_gr = parent + || RetrieveWellGuideRate{wellModel_.guideRate(), wname}; + + const auto qs = WellGroupHelpers:: + getWellRateVector(wellModel_.wellState(), wellModel_.phaseUsage(), wname); + + auto getGR = [this, &wname, &qs](const GuideRateModel::Target t) + { + return wellModel_.guideRate().getSI(wname, t, qs); + }; + + auto& grval = all[wname]; + + if (well.isInjector()) { + if (get_gr.inj_gas) { // Well supports WGIGR + grval.set(data::GuideRateValue::Item::Gas, + getGR(GuideRateModel::Target::GAS)); + } + if (get_gr.inj_water) { // Well supports WWIGR + grval.set(data::GuideRateValue::Item::Water, + getGR(GuideRateModel::Target::WAT)); + } + } + else if (get_gr.prod) { // Well is producer AND we want/support WxPGR + grval + .set(data::GuideRateValue::Item::Oil , getGR(GuideRateModel::Target::OIL)) + .set(data::GuideRateValue::Item::Gas , getGR(GuideRateModel::Target::GAS)) + .set(data::GuideRateValue::Item::Water, getGR(GuideRateModel::Target::WAT)); + } + }); + + // Visit groups before their children, meaning no well is visited until + // all of its upline parent groups--up to FIELD--have been visited. + // Upon completion, 'all' contains guide rate values for all wells + // reachable from 'FIELD' at this time/report step. + walker.traversePreOrder(); + + for (const auto* well : wellModel_.genericWells()) { + auto xwPos = wsrpt.find(well->name()); + if (xwPos == wsrpt.end()) { // No well results. Unexpected. + continue; + } + + auto grPos = all.find(well->name()); + if (grPos == all.end()) { + continue; + } + + xwPos->second.guide_rates = grPos->second; + } } + +} // namespace Opm diff --git a/opm/simulators/wells/BlackoilWellModelGuideRates.hpp b/opm/simulators/wells/BlackoilWellModelGuideRates.hpp index 41a3ec2d4..08c3486b2 100644 --- a/opm/simulators/wells/BlackoilWellModelGuideRates.hpp +++ b/opm/simulators/wells/BlackoilWellModelGuideRates.hpp @@ -30,7 +30,10 @@ namespace Opm { class BlackoilWellModelGeneric; -namespace data { class GuideRateValue; } +namespace data { +class GuideRateValue; +class Wells; +} class Group; class Well; @@ -58,6 +61,10 @@ public: //! \brief Obtain guide rate values for injection group. data::GuideRateValue getGuideRateInjectionGroupValues(const Group& group) const; + //! \brief Assign guide rates for a well. + void assignWellGuideRates(data::Wells& wsrpt, + const int reportStepIdx) const; + private: const BlackoilWellModelGeneric& wellModel_; //!< Reference to well model };