Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions opm/input/eclipse/EclipseState/Runspec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ NetworkDims::NetworkDims(const Deck& deck)
}
else if (deck.hasKeyword<ParserKeywords::GRUPNET>()) {
this->type_ = Type::Standard;
} else if (deck.hasKeyword<ParserKeywords::GNETINJE>()) {
this->type_ = Type::Standard;
}
}

Expand Down
97 changes: 63 additions & 34 deletions opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
#include <opm/input/eclipse/Schedule/MSW/WellSegments.hpp>
#include <opm/input/eclipse/EclipseState/Phase.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
Expand Down Expand Up @@ -707,31 +708,67 @@ namespace {
});
}

std::vector<std::string> collect_node_names(const Schedule& sched, const bool add_wells = false)
/// Node names of the production network (optionally with the wells of its
/// groups) and of the gas and water injection networks (GNETINJE), over all
/// report steps.
struct NetworkNodeNames
{
auto node_names = std::vector<std::string>{};
auto names = std::unordered_set<std::string>{};
std::vector<std::string> production {};
std::vector<std::string> production_with_wells {};
std::vector<std::string> gas_injection {};
std::vector<std::string> water_injection {};
};

NetworkNodeNames collect_node_names(const Schedule& sched)
{
auto prod = std::unordered_set<std::string>{};
auto prod_wells = std::unordered_set<std::string>{};
auto gas = std::unordered_set<std::string>{};
auto water = std::unordered_set<std::string>{};

const auto nstep = sched.size() - 1;
for (auto step = 0*nstep; step < nstep; ++step) {
const auto& nodes = sched[step].network.get().node_names();
names.insert(nodes.begin(), nodes.end());
if (!add_wells) continue;
prod.insert(nodes.begin(), nodes.end());
prod_wells.insert(nodes.begin(), nodes.end());

// Possibly insert wells belonging to groups in the network to be able to report network-computed THPs
for (const auto& node : nodes) {
if (!sched.hasGroup(node, step)) continue;
const auto& group = sched.getGroup(node, step);
for (const std::string& wellname : group.wells()) {
names.insert(wellname);
prod_wells.insert(wellname);
}
}

if (const auto gnet = sched[step].injectionNetwork.get_ptr(Phase::GAS); gnet != nullptr) {
const auto& gnodes = gnet->node_names();
gas.insert(gnodes.begin(), gnodes.end());
}
if (const auto wnet = sched[step].injectionNetwork.get_ptr(Phase::WATER); wnet != nullptr) {
const auto& wnodes = wnet->node_names();
water.insert(wnodes.begin(), wnodes.end());
}
}

node_names.assign(names.begin(), names.end());
std::ranges::sort(node_names);
auto sorted = [](const std::unordered_set<std::string>& names)
{
std::vector<std::string> v(names.begin(), names.end());
std::ranges::sort(v);
return v;
};

return { sorted(prod), sorted(prod_wells), sorted(gas), sorted(water) };
}

bool is_gas_injection_node_keyword(const std::string& keyword)
{
return keyword == "GPRG";
}

return node_names;
bool is_water_injection_node_keyword(const std::string& keyword)
{
return keyword == "GPRW";
}

SummaryConfigNode::Category
Expand Down Expand Up @@ -1160,7 +1197,8 @@ void keyword_node(SummaryConfig::keyword_list& list,
if (node_names.empty()) {
const auto msg = std::string {
"The network node keyword {keyword} is not "
"supported in runs without networks\n"
"supported in runs without a network of the corresponding kind "
"(production: GPR/GPRB..., gas injection: GPRG, water injection: GPRW)\n"
"In {file} line {line}"
};

Expand Down Expand Up @@ -1984,8 +2022,7 @@ void connectionKeyword(const bool isGeomechWithFracturingRun,
}
}

void handleKW(const std::vector<std::string>& node_names,
const std::vector<std::string>& node_names_with_wells,
void handleKW(const NetworkNodeNames& node_names,
const std::vector<int>& analyticAquiferIDs,
const std::vector<int>& numericAquiferIDs,
const bool isGeomechWithFracturingRun,
Expand Down Expand Up @@ -2068,10 +2105,14 @@ void handleKW(const std::vector<std::string>& node_names,
break;

case Cat::Node:
if (is_node_keyword_with_wells(keyword.name())) {
keyword_node(list, node_names_with_wells, parseContext, errors, keyword);
if (is_gas_injection_node_keyword(keyword.name())) {
keyword_node(list, node_names.gas_injection, parseContext, errors, keyword);
} else if (is_water_injection_node_keyword(keyword.name())) {
keyword_node(list, node_names.water_injection, parseContext, errors, keyword);
} else if (is_node_keyword_with_wells(keyword.name())) {
keyword_node(list, node_names.production_with_wells, parseContext, errors, keyword);
} else {
keyword_node(list, node_names, parseContext, errors, keyword);
keyword_node(list, node_names.production, parseContext, errors, keyword);
}
break;

Expand Down Expand Up @@ -2418,14 +2459,9 @@ SummaryConfig::SummaryConfig(const Deck& deck,
declaredMaxRegionID(Runspec { deck })
};

const bool node_names_needed = need_node_names(section);
const auto node_names = node_names_needed
const auto node_names = need_node_names(section)
? collect_node_names(schedule)
: std::vector<std::string> {};

const auto node_names_with_wells = node_names_needed
? collect_node_names(schedule, /*with_wells=*/true)
: std::vector<std::string> {};
: NetworkNodeNames {};

const auto analyticAquifers = analyticAquiferIDs(aquiferConfig);
const auto numericAquifers = numericAquiferIDs(aquiferConfig);
Expand All @@ -2439,7 +2475,7 @@ SummaryConfig::SummaryConfig(const Deck& deck,
handleProcessingInstruction(kw.name());
}
else {
handleKW(node_names, node_names_with_wells,
handleKW(node_names,
analyticAquifers, numericAquifers,
isGeomechWithFracturingRun,
kw, schedule, field_props, gridDims,
Expand Down Expand Up @@ -2622,16 +2658,9 @@ SummaryConfig::registerRequisiteUDQorActionSummaryKeys(const std::vector<std::st
{
const auto excludeFieldFromGroupKw = false;

const bool node_names_needed = std::ranges::any_of(extraKeys, &is_node_keyword);
const auto node_names =
node_names_needed
? collect_node_names(sched)
: std::vector<std::string>{};

const auto node_names_with_wells =
node_names_needed
? collect_node_names(sched, /*with_wells=*/true)
: std::vector<std::string>{};
const auto node_names = std::ranges::any_of(extraKeys, &is_node_keyword)
? collect_node_names(sched)
: NetworkNodeNames {};

const auto analyticAquifers = analyticAquiferIDs(es.aquifer());
const auto numericAquifers = numericAquiferIDs(es.aquifer());
Expand All @@ -2651,7 +2680,7 @@ SummaryConfig::registerRequisiteUDQorActionSummaryKeys(const std::vector<std::st
};

for (const auto& vector_name : extraKeys) {
handleKW(node_names, node_names_with_wells,
handleKW(node_names,
analyticAquifers, numericAquifers,
isGeomechWithFracturingRun,
DeckKeyword { KeywordLocation{}, vector_name },
Expand Down
35 changes: 33 additions & 2 deletions opm/output/data/Groups.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,16 @@ namespace Opm { namespace data {
class GroupAndNetworkValues {
public:
std::map<std::string, GroupData> groupData {};
// Production network (GPR, GPRB, ...).
std::map<std::string, NodeData> nodeData {};
std::map<std::string, BranchData> branchData {};
std::map<std::string, BranchData> convergedBranchData {};
// Gas and water injection networks (GNETINJE; GPRG / GPRW). Kept apart from the
// production network because the same group can be a node of all three.
std::map<std::string, NodeData> gasInjNodeData {};
std::map<std::string, BranchData> gasInjBranchData {};
std::map<std::string, NodeData> waterInjNodeData {};
std::map<std::string, BranchData> waterInjBranchData {};

template <class MessageBufferType>
void write(MessageBufferType& buffer) const
Expand All @@ -243,6 +250,10 @@ namespace Opm { namespace data {
this->writeMap(this->nodeData, buffer);
this->writeMap(this->branchData, buffer);
this->writeMap(this->convergedBranchData, buffer);
this->writeMap(this->gasInjNodeData, buffer);
this->writeMap(this->gasInjBranchData, buffer);
this->writeMap(this->waterInjNodeData, buffer);
this->writeMap(this->waterInjBranchData, buffer);
}

template <class MessageBufferType>
Expand All @@ -252,14 +263,22 @@ namespace Opm { namespace data {
this->readMap(buffer, this->nodeData);
this->readMap(buffer, this->branchData);
this->readMap(buffer, this->convergedBranchData);
this->readMap(buffer, this->gasInjNodeData);
this->readMap(buffer, this->gasInjBranchData);
this->readMap(buffer, this->waterInjNodeData);
this->readMap(buffer, this->waterInjBranchData);
}

bool operator==(const GroupAndNetworkValues& other) const
{
return (this->groupData == other.groupData)
&& (this->nodeData == other.nodeData)
&& (this->branchData == other.branchData)
&& (this->convergedBranchData == other.convergedBranchData);
&& (this->convergedBranchData == other.convergedBranchData)
&& (this->gasInjNodeData == other.gasInjNodeData)
&& (this->gasInjBranchData == other.gasInjBranchData)
&& (this->waterInjNodeData == other.waterInjNodeData)
&& (this->waterInjBranchData == other.waterInjBranchData);
}

void clear()
Expand All @@ -268,6 +287,10 @@ namespace Opm { namespace data {
this->nodeData.clear();
this->branchData.clear();
this->convergedBranchData.clear();
this->gasInjNodeData.clear();
this->gasInjBranchData.clear();
this->waterInjNodeData.clear();
this->waterInjBranchData.clear();
}

template<class Serializer>
Expand All @@ -277,6 +300,10 @@ namespace Opm { namespace data {
serializer(nodeData);
serializer(branchData);
serializer(convergedBranchData);
serializer(gasInjNodeData);
serializer(gasInjBranchData);
serializer(waterInjNodeData);
serializer(waterInjBranchData);
}

static GroupAndNetworkValues serializationTestObject()
Expand All @@ -285,7 +312,11 @@ namespace Opm { namespace data {
{{"test_data", GroupData::serializationTestObject()}},
{{"test_node", NodeData::serializationTestObject()}},
{{"test_branch", BranchData::serializationTestObject()}},
{{"test_converged_branch", BranchData::serializationTestObject()}}
{{"test_converged_branch", BranchData::serializationTestObject()}},
{{"test_gas_inj_node", NodeData::serializationTestObject()}},
{{"test_gas_inj_branch", BranchData::serializationTestObject()}},
{{"test_water_inj_node", NodeData::serializationTestObject()}},
{{"test_water_inj_branch", BranchData::serializationTestObject()}}
};
}

Expand Down
22 changes: 22 additions & 0 deletions opm/output/eclipse/Summary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,26 @@ inline quantity converged_node_pressure(const fn_args& args)
return { nodePos->second.converged_pressure, measure::pressure };
}

inline quantity gas_inj_node_pressure(const fn_args& args)
{
auto nodePos = args.grp_nwrk.gasInjNodeData.find(args.group_name);
if (nodePos == args.grp_nwrk.gasInjNodeData.end()) {
return { 0.0, measure::pressure };
}

return { nodePos->second.pressure, measure::pressure };
}

inline quantity water_inj_node_pressure(const fn_args& args)
{
auto nodePos = args.grp_nwrk.waterInjNodeData.find(args.group_name);
if (nodePos == args.grp_nwrk.waterInjNodeData.end()) {
return { 0.0, measure::pressure };
}

return { nodePos->second.pressure, measure::pressure };
}

inline quantity branch_pressure(const fn_args& args)
{
auto nodePos = args.grp_nwrk.branchData.find(args.group_name);
Expand Down Expand Up @@ -3119,6 +3139,8 @@ static const auto funs = std::unordered_map<std::string, ofun> {


{ "GPR", node_pressure },
{ "GPRG", gas_inj_node_pressure },
{ "GPRW", water_inj_node_pressure },
{ "GPR2", converged_node_pressure },
{ "NPR", converged_node_pressure },
{ "GNETPR", converged_node_pressure },
Expand Down
9 changes: 9 additions & 0 deletions tests/summary_deck.DATA
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,15 @@ WELSPECS
'W_5' 'G_3' 6 6 3.92 'OIL' 7* /
/

-- Gas and water injection networks (GPRG / GPRW): FIELD is the terminal node,
-- G_2 (which holds the injectors) a leaf.
GNETINJE
'FIELD' 'GAS' 30.0 /
'G_2' 'GAS' 1* 4 /
'FIELD' 'WAT' 15.0 /
'G_2' 'WAT' 1* 4 /
/

-- Completion data.
COMPDAT
-- Passing 0 to I/J means they'll get the well head I/J
Expand Down
17 changes: 17 additions & 0 deletions tests/test_Summary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,13 @@ data::GroupAndNetworkValues result_group_nwrk()
grp_nwrk.nodeData["G_2"].converged_pressure = 23.46*Opm::unit::barsa;
grp_nwrk.nodeData["PLAT-A"].converged_pressure = 21.0*Opm::unit::barsa;

// Injection networks (GNETINJE in the deck): the same group is a node of the
// production and both injection networks, with different pressures.
grp_nwrk.gasInjNodeData["FIELD"].pressure = 30.0*Opm::unit::barsa;
grp_nwrk.gasInjNodeData["G_2"].pressure = 44.0*Opm::unit::barsa;
grp_nwrk.waterInjNodeData["FIELD"].pressure = 15.0*Opm::unit::barsa;
grp_nwrk.waterInjNodeData["G_2"].pressure = 55.0*Opm::unit::barsa;

grp_nwrk.branchData["G_1"].pressure_drop = 12.44*Opm::unit::barsa;
grp_nwrk.branchData["G_1"].oil_rate = 123.456*sm3_pr_day();
grp_nwrk.branchData["G_1"].water_rate = 23.456*sm3_pr_day();
Expand Down Expand Up @@ -3274,6 +3281,16 @@ BOOST_AUTO_TEST_CASE(NODE_VARIABLES)
BOOST_CHECK_CLOSE( 33.45, ecl_sum_get_group_var( resp, 1, "G_1", "GPR2" ), 1e-5 );
BOOST_CHECK_CLOSE( 23.46, ecl_sum_get_group_var( resp, 1, "G_2", "GPR2" ), 1e-5 );

// Injection network node pressures, kept apart from the production network's.
BOOST_CHECK( ecl_sum_has_key( resp, "GPRG:G_2" ) );
BOOST_CHECK( ecl_sum_has_key( resp, "GPRG:FIELD" ) );
BOOST_CHECK( !ecl_sum_has_key( resp, "GPRG:G_1" ) ); // not a gas injection node
BOOST_CHECK_CLOSE( 44.0, ecl_sum_get_group_var( resp, 1, "G_2", "GPRG" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.0, ecl_sum_get_group_var( resp, 1, "FIELD", "GPRG" ), 1e-5 );
BOOST_CHECK_CLOSE( 55.0, ecl_sum_get_group_var( resp, 1, "G_2", "GPRW" ), 1e-5 );
BOOST_CHECK_CLOSE( 15.0, ecl_sum_get_group_var( resp, 1, "FIELD", "GPRW" ), 1e-5 );
BOOST_CHECK_CLOSE( 23.45, ecl_sum_get_group_var( resp, 1, "G_2", "GPR" ), 1e-5 );

BOOST_CHECK_CLOSE( 12.44 , ecl_sum_get_group_var( resp, 1, "G_1", "GPRB" ), 1e-5 );
BOOST_CHECK_CLOSE( 12.45, ecl_sum_get_group_var( resp, 1, "G_1", "GPRB2" ), 1e-5 );

Expand Down