Merge pull request #3695 from vkip/grupnet_reroute_hack

Allow rerouting in standard and extended network
This commit is contained in:
Kai Bao 2023-11-08 19:58:07 +01:00 committed by GitHub
commit 16c6ee3bbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 36 deletions

View File

@ -45,6 +45,7 @@ public:
const std::string& downtree_node() const;
const std::string& uptree_node() const;
void set_uptree_node(const std::string& new_uptree_node);
std::optional<int> vfp_table() const;
AlqEQ alq_eq() const;
std::optional<double> alq_value() const;

View File

@ -37,7 +37,10 @@ class ExtNetwork {
public:
ExtNetwork() = default;
bool active() const;
bool is_standard_network() const;
void set_standard_network(bool is_standard_network);
void add_branch(Branch branch);
void add_or_replace_branch(Branch branch);
void drop_branch(const std::string& uptree_node, const std::string& downtree_node);
bool has_node(const std::string& name) const;
void update_node(Node node);
@ -58,12 +61,14 @@ public:
serializer(m_branches);
serializer(insert_indexed_node_names);
serializer(m_nodes);
serializer(m_is_standard_network);
}
private:
std::vector<Branch> m_branches;
std::vector<std::string> insert_indexed_node_names;
std::map<std::string, Node> m_nodes;
bool m_is_standard_network{false};
bool has_indexed_node_name(const std::string& name) const;
void add_indexed_node_name(std::string name);
};

View File

@ -168,7 +168,11 @@ namespace {
void Schedule::handleBRANPROP(HandlerContext& handlerContext) {
auto ext_network = this->snapshots.back().network.get();
if (ext_network.active() && ext_network.is_standard_network()) {
std::string msg = "Cannot have standard and extended network defined simultaneously.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
ext_network.set_standard_network(false);
for (const auto& record : handlerContext.keyword) {
const auto& downtree_node = record.getItem<ParserKeywords::BRANPROP::DOWNTREE_NODE>().get<std::string>(0);
const auto& uptree_node = record.getItem<ParserKeywords::BRANPROP::UPTREE_NODE>().get<std::string>(0);
@ -181,9 +185,9 @@ namespace {
if (alq_eq == Network::Branch::AlqEQ::ALQ_INPUT) {
double alq_value = record.getItem<ParserKeywords::BRANPROP::ALQ>().get<double>(0);
ext_network.add_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_value));
ext_network.add_or_replace_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_value));
} else {
ext_network.add_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_eq));
ext_network.add_or_replace_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_eq));
}
}
}
@ -843,6 +847,11 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
void Schedule::handleGRUPNET(HandlerContext& handlerContext) {
auto network = this->snapshots.back().network.get();
if (network.active() && !network.is_standard_network()) {
std::string msg = "Cannot have standard and extended network defined simultaneously.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
network.set_standard_network(true);
std::vector<Network::Node> nodes;
for (const auto& record : handlerContext.keyword) {
const std::string& groupNamePattern = record.getItem<ParserKeywords::GRUPNET::NAME>().getTrimmedString(0);
@ -888,9 +897,9 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
const auto alq_eq = Network::Branch::AlqEqfromString(record.getItem<ParserKeywords::GRUPNET::ALQ_SURFACE_DENSITY>().get<std::string>(0));
if (alq_eq == Network::Branch::AlqEQ::ALQ_INPUT) {
const double alq_value = record.getItem<ParserKeywords::GRUPNET::ALQ>().get<double>(0);
network.add_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_value));
network.add_or_replace_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_value));
} else {
network.add_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_eq));
network.add_or_replace_branch(Network::Branch(downtree_node, uptree_node, vfp_table, alq_eq));
}
}
nodes.push_back(node);
@ -1008,6 +1017,10 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno)
void Schedule::handleNODEPROP(HandlerContext& handlerContext) {
auto ext_network = this->snapshots.back().network.get();
if (ext_network.active() && ext_network.is_standard_network()) {
std::string msg = "Cannot have standard and extended network defined simultaneously.";
throw OpmInputError(msg, handlerContext.keyword.location());
}
for (const auto& record : handlerContext.keyword) {
const auto& name = record.getItem<ParserKeywords::NODEPROP::NAME>().get<std::string>(0);

View File

@ -65,6 +65,10 @@ const std::string& Branch::downtree_node() const {
return this->m_downtree_node;
}
void Branch::set_uptree_node(const std::string& new_uptree_node) {
this->m_uptree_node = new_uptree_node;
}
bool Branch::operator==(const Branch& other) const {
return this->m_downtree_node == other.m_downtree_node &&
this->m_uptree_node == other.m_uptree_node &&

View File

@ -19,6 +19,7 @@
#include <algorithm>
#include <iterator>
#include <stdexcept>
#include <fmt/format.h>
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
@ -30,6 +31,7 @@ ExtNetwork ExtNetwork::serializationTestObject() {
object.m_branches = {Branch::serializationTestObject()};
object.insert_indexed_node_names = {"test1", "test2"};
object.m_nodes = {{"test3", Node::serializationTestObject()}};
object.m_is_standard_network = false;
return object;
}
@ -37,6 +39,14 @@ bool ExtNetwork::active() const {
return !this->m_branches.empty() && !this->m_nodes.empty();
}
bool ExtNetwork::is_standard_network() const {
return this->m_is_standard_network;
}
void ExtNetwork::set_standard_network(bool is_standard_network) {
this->m_is_standard_network = is_standard_network;
}
bool ExtNetwork::operator==(const ExtNetwork& rhs) const {
return this->m_branches == rhs.m_branches
&& this->insert_indexed_node_names == rhs.insert_indexed_node_names
@ -86,24 +96,47 @@ void ExtNetwork::add_branch(Branch branch)
this->m_branches.push_back( std::move(branch) );
}
void ExtNetwork::drop_branch(const std::string& uptree_node, const std::string& downtree_node) {
auto downtree_branches = this->downtree_branches( downtree_node );
if (downtree_branches.empty()) {
auto branch_iter = std::find_if(this->m_branches.begin(), this->m_branches.end(), [&uptree_node, &downtree_node](const Branch& b) { return (b.uptree_node() == uptree_node && b.downtree_node() == downtree_node); });
if (branch_iter != this->m_branches.end())
this->m_branches.erase( branch_iter );
void ExtNetwork::add_or_replace_branch(Branch branch)
{
const std::string& uptree_node = branch.uptree_node();
const std::string& downtree_node = branch.downtree_node();
this->m_nodes.erase( downtree_node );
} else {
for (const auto& branch : downtree_branches)
this->drop_branch(branch.uptree_node(), branch.downtree_node());
// Add any missing nodes
for (const std::string& nodename : { downtree_node, uptree_node }) {
if (!this->has_node(nodename)) {
this->m_nodes.insert_or_assign(nodename, Node{nodename});
}
if (!this->has_indexed_node_name(nodename)) {
this->add_indexed_node_name(nodename);
}
}
// Remove any existing branch uptree from downtree_node (gathering tree structure required)
// (If it is an existing branch that should be updated, it will be added again below)
auto uptree_link = this->uptree_branch( downtree_node );
if (uptree_link.has_value()){
const auto& old_uptree_node = uptree_link.value().uptree_node();
this->drop_branch(old_uptree_node, downtree_node);
}
this->m_branches.push_back( std::move(branch) );
}
void ExtNetwork::drop_branch(const std::string& uptree_node, const std::string& downtree_node) {
auto branch_iter = std::find_if(this->m_branches.begin(),
this->m_branches.end(),
[&uptree_node, &downtree_node](const Branch& b) { return (b.uptree_node() == uptree_node && b.downtree_node() == downtree_node); });
if (branch_iter != this->m_branches.end()) {
this->m_branches.erase(branch_iter);
}
}
std::optional<Branch> ExtNetwork::uptree_branch(const std::string& node) const {
if (!this->has_node(node))
throw std::out_of_range("No such node: " + node);
if (!this->has_node(node)) {
auto msg = fmt::format("Requesting uptree branch of undefined node: {}", node);
throw std::out_of_range(msg);
}
std::vector<Branch> branches;
std::copy_if(this->m_branches.begin(), this->m_branches.end(), std::back_inserter(branches), [&node](const Branch& b) { return b.downtree_node() == node; });
@ -113,13 +146,15 @@ std::optional<Branch> ExtNetwork::uptree_branch(const std::string& node) const {
if (branches.size() == 1)
return std::move(branches[0]);
throw std::logic_error("Bug - more than upstree branch for node: " + node);
throw std::logic_error("Bug - more than one uptree branch for node: " + node);
}
std::vector<Branch> ExtNetwork::downtree_branches(const std::string& node) const {
if (!this->has_node(node))
throw std::out_of_range("No such node: " + node);
if (!this->has_node(node)) {
auto msg = fmt::format("Requesting downtree branches of undefined node: {}", node);
throw std::out_of_range(msg);
}
std::vector<Branch> branches;
std::copy_if(this->m_branches.begin(), this->m_branches.end(), std::back_inserter(branches), [&node](const Branch& b) { return b.uptree_node() == node; });
@ -161,11 +196,7 @@ void ExtNetwork::update_node(Node node)
auto branch = std::find_if(this->m_branches.begin(), this->m_branches.end(),
[&name](const Branch& b) { return b.uptree_node() == name || b.downtree_node() == name;});
if (branch == this->m_branches.end())
throw std::invalid_argument("Node: " + name + " is not referenced by any branch and would be dangling.");
if (branch->downtree_node() == name) {
if (branch != this->m_branches.end() && branch->downtree_node() == name) {
if (node.as_choke() && branch->vfp_table().has_value())
throw std::invalid_argument("Node: " + name + " should serve as a choke => upstream branch can not have VFP table");
}

View File

@ -1395,6 +1395,21 @@ File {} line {}.)", pattern, location.keyword, location.filename, location.linen
new_child_group.updateParent(parent_name);
this->snapshots.back().groups.update( std::move(new_child_group) );
}
// Update standard network if required
auto network = this->snapshots.back().network.get();
if (!network.is_standard_network())
return;
if (network.has_node(child_name)) {
auto old_branch = network.uptree_branch(child_name);
if (old_branch.has_value()) {
auto new_branch = old_branch.value();
new_branch.set_uptree_node(parent_name);
network.add_or_replace_branch(new_branch);
this->snapshots.back().network.update( std::move(network));
}
// If no previous uptree branch the child is a fixed-pressure node, so no need to update network
}
}
void Schedule::addWellToGroup( const std::string& group_name, const std::string& well_name , std::size_t timeStep) {

View File

@ -37,6 +37,7 @@
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include <opm/input/eclipse/Units/Units.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <algorithm>
#include <cstddef>
@ -233,6 +234,9 @@ double nodePressure(const Opm::Schedule& sched,
// find fixed pressure higher in the node tree
bool fp_flag = false;
auto node_name = nodeName;
auto upt_br_opt = network.uptree_branch(node_name);
if (!upt_br_opt.has_value()) return 0.0; // Node not belonging to the network right now
auto upt_br = network.uptree_branch(node_name).value();
while (!fp_flag) {
if (fixedPressureNode(sched, upt_br.uptree_node(), lookup_step)) {
@ -243,8 +247,11 @@ double nodePressure(const Opm::Schedule& sched,
if (network.uptree_branch(node_name).has_value()) {
upt_br = network.uptree_branch(node_name).value();
} else {
auto msg = fmt::format("Node: {} has no uptree node with fixed pressure condition, uppermost node is: {} ", nodeName, node_name);
throw std::logic_error(msg);
auto msg = fmt::format("Node: {} does not belong to the network at report step: {} - node pressure set to zero.",
node_name,
lookup_step+1);
Opm::OpmLog::warning(msg);
return 0.0; // Subtree not belonging to the network right now
}
}
}
@ -407,7 +414,7 @@ int numberOfBranchesConnToNode(const Opm::Schedule& sched, const std::string& no
noBranches = (network.uptree_branch(nodeName).has_value()) ? noBranches+1 : noBranches;
return noBranches;
} else {
auto msg = fmt::format("Actual node: {} has not been defined at report time: {} ", nodeName, lookup_step+1);
auto msg = fmt::format("Trying to find number of branches connected to undefined node: {} at report time: {} ", nodeName, lookup_step+1);
throw std::logic_error(msg);
}
}
@ -438,6 +445,7 @@ template <class INodeArray>
void staticContrib(const Opm::Schedule& sched,
const std::string& nodeName,
const std::size_t lookup_step,
const std::size_t ngroups,
INodeArray& iNode)
{
//
@ -447,6 +455,9 @@ void staticContrib(const Opm::Schedule& sched,
if (sched.hasGroup(nodeName, lookup_step)) {
iNode[Ix::Group] = sched.getGroup(nodeName, lookup_step).insert_index();
}
if (nodeName == "FIELD") {
iNode[Ix::Group] = ngroups;
}
iNode[Ix::FixedPresNode] = (fixedPressureNode(sched, nodeName, lookup_step)) ? 1 : 0;
// the meaning of the value of item [4] is currently not known, the constant value used cover all cases so far
iNode[4] = 1;
@ -486,7 +497,7 @@ void staticContrib(const Opm::Schedule& sched,
auto uptr_nd_res = findInVector<std::string>(nodeNames, branch.uptree_node());
iBran[Ix::UpTreeNode] = (uptr_nd_res) ? uptr_nd_res.value() + 1 : 0 ;
iBran[Ix::VfpTableNo] = (branch.vfp_table().has_value()) ? branch.vfp_table().value() : 0;
iBran[Ix::VfpTableNo] = (branch.vfp_table().has_value()) ? branch.vfp_table().value() : 9999;
}
} // Ibran
@ -670,13 +681,14 @@ captureDeclaredNetworkData(const Opm::EclipseState& es,
const auto& networkNodePtrs = ndNmPt;
const auto& branchPtrs = sched[lookup_step].network().branches();
const std::size_t ngroups = inteHead[VI::NGMAXZ];
// Define Static Contributions to INode Array.
nodeLoop(networkNodePtrs, [&sched, lookup_step, this]
nodeLoop(networkNodePtrs, [&sched, lookup_step, ngroups, this]
(const std::string& nodeName, const std::size_t nodeID) -> void
{
auto ind = this->iNode_[nodeID];
INode::staticContrib(sched, nodeName, lookup_step, ind);
INode::staticContrib(sched, nodeName, lookup_step, ngroups, ind);
});
// Define Static Contributions to IBran Array.

View File

@ -96,7 +96,9 @@ NODEPROP
/
)";
BOOST_CHECK_THROW( make_schedule(deck_string), std::exception);
const auto& schedule = make_schedule(deck_string);
const auto& network = schedule[0].network.get();
BOOST_CHECK(network.has_node("B1X"));
}
@ -130,7 +132,9 @@ NODEPROP
/
)";
BOOST_CHECK_THROW( make_schedule(deck_string), std::exception);
const auto& schedule = make_schedule(deck_string);
const auto& network = schedule[0].network.get();
BOOST_CHECK(network.has_node("PLAT-AX"));
}
BOOST_AUTO_TEST_CASE(INVALID_VFP_NODE) {
@ -264,9 +268,9 @@ BRANPROP
BOOST_CHECK_EQUAL(B1_uptree->downtree_node(), "B1");
BOOST_CHECK_EQUAL(B1_uptree->uptree_node(), "PLAT-A");
BOOST_CHECK_THROW( network.uptree_branch("C1"), std::out_of_range);
BOOST_CHECK_THROW( network.node("C1"), std::out_of_range);
BOOST_CHECK( network.has_node("C1") );
BOOST_CHECK( !network.uptree_branch("C1") );
BOOST_CHECK(network.active());
}
}