move assignWellGuideRates into BlackoilWellModelGuideRates

This commit is contained in:
Arne Morten Kvarving 2022-10-24 09:36:05 +02:00
parent f19c7b2ee6
commit 01dfe23a50
5 changed files with 349 additions and 158 deletions

View File

@ -49,6 +49,7 @@
#include <opm/simulators/timestepping/SimulatorReport.hpp>
#include <opm/simulators/flow/countGlobalCells.hpp>
#include <opm/simulators/wells/BlackoilWellModelGeneric.hpp>
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
#include <opm/simulators/wells/GasLiftSingleWell.hpp>
#include <opm/simulators/wells/GasLiftWellState.hpp>
#include <opm/simulators/wells/GasLiftSingleWellGeneric.hpp>
@ -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;

View File

@ -59,52 +59,6 @@
#include <fmt/format.h>
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<std::string, data::GuideRateValue>{};
auto retrieve = std::unordered_map<std::string, RetrieveWellGuideRate>{};
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,

View File

@ -271,8 +271,6 @@ protected:
const int pvtreg,
std::vector<double>& 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,

View File

@ -23,12 +23,253 @@
#include <config.h>
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/output/data/GuideRateValue.hpp>
#include <opm/simulators/wells/BlackoilWellModelGeneric.hpp>
#include <opm/simulators/wells/WellGroupHelpers.hpp>
#include <opm/simulators/wells/WellInterfaceGeneric.hpp>
#include <fmt/format.h>
#include <cstddef>
#include <functional>
#include <stack>
#include <stdexcept>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
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<void(const Opm::Group&)>;
using WellOp = std::function<void(const Opm::Well&)>;
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<const Opm::Schedule> sched_;
int reportStepIdx_;
GroupOp visitGroup_{};
WellOp visitWell_{};
std::stack<std::string_view, std::vector<std::string_view>> dfsGroupStack_{};
std::unordered_set<std::size_t> 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<std::string, data::GuideRateValue>{};
auto retrieve = std::unordered_map<std::string, RetrieveWellGuideRate>{};
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

View File

@ -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
};