Support Loading Extended Network Model From Restart

This commit adds a new helper class, RstNetwork, that loads the raw
data representing the extended network model from restart vectors
IBRAN, INODE, RNODE, and ZNODE.  We support loading the information
that is currently output to those restart vectors, but those do not
include every option supported by the input keywords BRANPROP and
NODEPROP.

The RstNetwork type supports querying whether or not the extended
network model is active and, if so, to get iterable collections of
branches and nodes that are geared towards constructing ExtNetwork
objects.
This commit is contained in:
Bård Skaflestad
2021-11-03 22:50:05 +01:00
parent c3b3ce4832
commit 19ec3b34f9
3 changed files with 347 additions and 0 deletions

View File

@@ -298,6 +298,7 @@ if(ENABLE_ECL_OUTPUT)
src/opm/io/eclipse/rst/connection.cpp
src/opm/io/eclipse/rst/group.cpp
src/opm/io/eclipse/rst/header.cpp
src/opm/io/eclipse/rst/network.cpp
src/opm/io/eclipse/rst/udq.cpp
src/opm/io/eclipse/rst/segment.cpp
src/opm/io/eclipse/rst/state.cpp
@@ -910,6 +911,7 @@ if(ENABLE_ECL_OUTPUT)
opm/io/eclipse/rst/connection.hpp
opm/io/eclipse/rst/group.hpp
opm/io/eclipse/rst/header.hpp
opm/io/eclipse/rst/network.hpp
opm/io/eclipse/rst/segment.hpp
opm/io/eclipse/rst/state.hpp
opm/io/eclipse/rst/udq.hpp

View File

@@ -0,0 +1,95 @@
/*
Copyright 2021 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RST_NETWORK_HPP
#define RST_NETWORK_HPP
#include <memory>
#include <optional>
#include <string>
#include <vector>
namespace Opm {
class UnitSystem;
} // namespace Opm
namespace Opm { namespace EclIO {
class RestartFileView;
}} // namespace Opm::EclIO
namespace Opm { namespace RestartIO {
class RstNetwork
{
public:
/// Single branch in extended network model.
struct Branch
{
/// Downtree node. Index into 'nodes' array.
int down{-1};
/// Uptree node. Index into 'nodes' array.
int up{-1};
/// One-based VFP table ID.
int vfp{-1};
};
/// Single node in extended network model.
struct Node
{
/// Name of network node.
std::string name{};
/// Fixed pressure for terminal node. Nullopt if not terminal.
std::optional<double> terminal_pressure{};
/// Group whose rate target the choking mechanism attempts to
/// match. Nullopt if this node does not act as a choke or if
/// choking is disabled.
std::optional<std::string> as_choke{};
/// Whether or not to include lift gas of subordinate wells as
/// part of the produced gas entering the network at this node.
bool add_lift_gas{false};
};
explicit RstNetwork(std::shared_ptr<EclIO::RestartFileView> rstView,
const UnitSystem& usys);
bool isActive() const;
const std::vector<Branch>& branches() const
{
return this->branches_;
}
const std::vector<Node>& nodes() const
{
return this->nodes_;
}
private:
std::vector<Branch> branches_{};
std::vector<Node> nodes_{};
};
}} // namespace Opm::RestartIO
#endif // RST_NETWORK_HPP

View File

@@ -0,0 +1,250 @@
/*
Copyright 2021 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
OPM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/io/eclipse/rst/network.hpp>
#include <opm/io/eclipse/RestartFileView.hpp>
#include <opm/output/eclipse/VectorItems/intehead.hpp>
#include <opm/output/eclipse/VectorItems/network.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <boost/range.hpp>
namespace VI = ::Opm::RestartIO::Helpers::VectorItems;
namespace {
template <typename T>
boost::iterator_range<typename std::vector<T>::const_iterator>
getDataWindow(const std::vector<T>& arr,
const std::size_t windowSize,
const std::size_t entity)
{
const auto off = windowSize * entity;
auto begin = arr.begin() + off;
auto end = begin + windowSize;
return { begin, end };
}
}
// ---------------------------------------------------------------------------
class BranchVectors
{
public:
template <typename T>
using Window = boost::iterator_range<
typename std::vector<T>::const_iterator
>;
explicit BranchVectors(const std::vector<int>& intehead,
std::shared_ptr<Opm::EclIO::RestartFileView> rst_view);
std::size_t numActiveBranches() const
{
return this->numActiveBranches_;
}
Window<int> ibran(const std::size_t branchID) const;
private:
std::size_t numActiveBranches_;
std::size_t numIBranElem_;
std::shared_ptr<Opm::EclIO::RestartFileView> rstView_;
};
BranchVectors::BranchVectors(const std::vector<int>& intehead,
std::shared_ptr<Opm::EclIO::RestartFileView> rst_view)
: numActiveBranches_(intehead[VI::intehead::NOACTBR])
, numIBranElem_ (intehead[VI::intehead::NIBRAN])
, rstView_ (std::move(rst_view))
{}
BranchVectors::Window<int>
BranchVectors::ibran(const std::size_t branchID) const
{
return getDataWindow(this->rstView_->getKeyword<int>("IBRAN"),
this->numIBranElem_, branchID);
}
// ---------------------------------------------------------------------------
class NodeVectors
{
public:
template <typename T>
using Window = boost::iterator_range<
typename std::vector<T>::const_iterator
>;
explicit NodeVectors(const std::vector<int>& intehead,
std::shared_ptr<Opm::EclIO::RestartFileView> rst_view);
std::size_t numActiveNodes() const
{
return this->numActiveNodes_;
}
Window<int> inode(const std::size_t nodeID) const;
Window<double> rnode(const std::size_t nodeID) const;
Window<std::string> znode(const std::size_t nodeID) const;
private:
std::size_t numActiveNodes_;
std::size_t numINodeElem_;
std::size_t numRNodeElem_;
std::size_t numZNodeElem_;
std::shared_ptr<Opm::EclIO::RestartFileView> rstView_;
};
NodeVectors::NodeVectors(const std::vector<int>& intehead,
std::shared_ptr<Opm::EclIO::RestartFileView> rst_view)
: numActiveNodes_(intehead[VI::intehead::NOACTNOD])
, numINodeElem_ (intehead[VI::intehead::NINODE])
, numRNodeElem_ (intehead[VI::intehead::NRNODE])
, numZNodeElem_ (intehead[VI::intehead::NZNODE])
, rstView_ (std::move(rst_view))
{}
NodeVectors::Window<int>
NodeVectors::inode(const std::size_t nodeID) const
{
return getDataWindow(this->rstView_->getKeyword<int>("INODE"),
this->numINodeElem_, nodeID);
}
NodeVectors::Window<double>
NodeVectors::rnode(const std::size_t nodeID) const
{
return getDataWindow(this->rstView_->getKeyword<double>("RNODE"),
this->numRNodeElem_, nodeID);
}
NodeVectors::Window<std::string>
NodeVectors::znode(const std::size_t nodeID) const
{
return getDataWindow(this->rstView_->getKeyword<std::string>("ZNODE"),
this->numZNodeElem_, nodeID);
}
// ---------------------------------------------------------------------------
namespace {
int branch_vfp_no_pressure_loss()
{
return 9999;
}
template <typename IBranArray>
Opm::RestartIO::RstNetwork::Branch make_branch(const IBranArray ibran)
{
using Ix = VI::IBran::index;
auto branch = Opm::RestartIO::RstNetwork::Branch{};
branch.down = ibran[Ix::DownTreeNode] - 1; // Index into ZNODE
branch.up = ibran[Ix::UpTreeNode] - 1; // Index into ZNODE
branch.vfp = (ibran[Ix::VfpTableNo] > 0)
? ibran[Ix::VfpTableNo] // One-based VFP table ID
: branch_vfp_no_pressure_loss();
return branch;
}
template <typename INodeArray, typename RNodeArray>
Opm::RestartIO::RstNetwork::Node
make_node(const std::string& name,
const Opm::UnitSystem& usys,
const INodeArray inode,
const RNodeArray rnode)
{
auto node = Opm::RestartIO::RstNetwork::Node{};
node.name = name;
if (inode[VI::INode::index::FixedPresNode] != 0) {
node.terminal_pressure =
usys.to_si(Opm::UnitSystem::measure::pressure,
rnode[VI::RNode::index::PressureLimit]);
}
return node;
}
std::vector<Opm::RestartIO::RstNetwork::Branch>
create_branches(std::shared_ptr<Opm::EclIO::RestartFileView> rstView)
{
auto branches = std::vector<Opm::RestartIO::RstNetwork::Branch>{};
const auto branchData = BranchVectors { rstView->intehead(), rstView };
const auto numBranches = branchData.numActiveBranches();
branches.reserve(numBranches);
for (auto branchID = 0*numBranches; branchID < numBranches; ++branchID) {
branches.push_back(make_branch(branchData.ibran(branchID)));
}
return branches;
}
std::vector<Opm::RestartIO::RstNetwork::Node>
create_nodes(std::shared_ptr<Opm::EclIO::RestartFileView> rstView,
const Opm::UnitSystem& usys)
{
auto nodes = std::vector<Opm::RestartIO::RstNetwork::Node>{};
const auto nodeData = NodeVectors { rstView->intehead(), rstView };
const auto numNodes = nodeData.numActiveNodes();
nodes.reserve(numNodes);
for (auto nodeID = 0*numNodes; nodeID < numNodes; ++nodeID) {
const auto znode = nodeData.znode(nodeID);
nodes.push_back(make_node(znode[VI::ZNode::index::NodeName], usys,
nodeData.inode(nodeID),
nodeData.rnode(nodeID)));
}
return nodes;
}
}
Opm::RestartIO::RstNetwork::RstNetwork(std::shared_ptr<EclIO::RestartFileView> rstView,
const UnitSystem& usys)
: branches_{ create_branches(rstView) }
, nodes_ { create_nodes (rstView, usys) }
{}
bool Opm::RestartIO::RstNetwork::isActive() const
{
return ! (this->branches_.empty() ||
this->nodes_.empty());
}