Skip to content

Commit 5b83fb1

Browse files
committed
move WGHelper::computeNetworkPressures to BlackoilWellModelNetworkGeneric
it is the only consumer
1 parent 84837df commit 5b83fb1

File tree

4 files changed

+182
-170
lines changed

4 files changed

+182
-170
lines changed

opm/simulators/wells/BlackoilWellModelNetworkGeneric.cpp

Lines changed: 171 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
#include <opm/input/eclipse/Schedule/Schedule.hpp>
3131
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
32-
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
3332

3433
#include <opm/simulators/wells/BlackoilWellModelGeneric.hpp>
3534
#include <opm/simulators/wells/VFPProperties.hpp>
@@ -144,10 +143,10 @@ updatePressures(const int reportStepIdx,
144143

145144
const auto previous_node_pressures = node_pressures_;
146145

147-
node_pressures_ = well_model_.wgHelper().
148-
computeNetworkPressures(network,
149-
*well_model_.getVFPProperties().getProd(),
150-
well_model_.comm());
146+
node_pressures_ = this->computePressures(network,
147+
*well_model_.getVFPProperties().getProd(),
148+
reportStepIdx,
149+
well_model_.comm());
151150

152151
// here, the network imbalance is the difference between the previous nodal pressure and the new nodal pressure
153152
Scalar network_imbalance = 0.;
@@ -233,10 +232,10 @@ assignNodeValues(std::map<std::string, data::NodeData>& nodevalues,
233232
return;
234233
}
235234

236-
auto converged_pressures =
237-
well_model_.wgHelper().computeNetworkPressures(network,
238-
*well_model_.getVFPProperties().getProd(),
239-
well_model_.comm());
235+
auto converged_pressures = this->computePressures(network,
236+
*well_model_.getVFPProperties().getProd(),
237+
reportStepIdx,
238+
well_model_.comm());
240239
for (const auto& [node, converged_pressure] : converged_pressures) {
241240
auto it = nodevalues.find(node);
242241
assert(it != nodevalues.end() );
@@ -284,6 +283,169 @@ initializeWell(WellInterfaceGeneric<Scalar,IndexTraits>& well)
284283
}
285284
}
286285

286+
template <typename Scalar, typename IndexTraits>
287+
std::map<std::string, Scalar>
288+
BlackoilWellModelNetworkGeneric<Scalar, IndexTraits>::
289+
computePressures(const Network::ExtNetwork& network,
290+
const VFPProdProperties<Scalar>& vfp_prod_props,
291+
const int reportStepIdx,
292+
const Parallel::Communication& comm) const
293+
{
294+
// TODO: Only dealing with production networks for now.
295+
OPM_TIMEFUNCTION();
296+
if (!network.active()) {
297+
return {};
298+
}
299+
300+
const auto& group_state = well_model_.wgHelper().groupState();
301+
const auto& well_state = well_model_.wgHelper().wellState();
302+
303+
std::map<std::string, Scalar> node_pressures;
304+
auto roots = network.roots();
305+
for (const auto& root : roots) {
306+
// Fixed pressure nodes of the network are the roots of trees.
307+
// Leaf nodes must correspond to groups in the group structure.
308+
// Let us first find all leaf nodes of the network. We also
309+
// create a vector of all nodes, ordered so that a child is
310+
// always after its parent.
311+
std::stack<std::string> children;
312+
std::set<std::string> leaf_nodes;
313+
std::vector<std::string> root_to_child_nodes;
314+
// children.push(network.root().name());
315+
children.push(root.get().name());
316+
while (!children.empty()) {
317+
const auto node = children.top();
318+
children.pop();
319+
root_to_child_nodes.push_back(node);
320+
auto branches = network.downtree_branches(node);
321+
if (branches.empty()) {
322+
leaf_nodes.insert(node);
323+
}
324+
for (const auto& branch : branches) {
325+
children.push(branch.downtree_node());
326+
}
327+
}
328+
assert(children.empty());
329+
330+
// Starting with the leaf nodes of the network, get the flow rates
331+
// from the corresponding groups.
332+
std::map<std::string, std::vector<Scalar>> node_inflows;
333+
const std::vector<Scalar> zero_rates(3, 0.0);
334+
for (const auto& node : leaf_nodes) {
335+
// Guard against empty leaf nodes (may not be present in GRUPTREE)
336+
if (!well_model_.wgHelper().groupState().has_production_rates(node)) {
337+
node_inflows[node] = zero_rates;
338+
continue;
339+
}
340+
341+
node_inflows[node] = group_state.network_leaf_node_production_rates(node);
342+
// Add the ALQ amounts to the gas rates if requested.
343+
if (network.node(node).add_gas_lift_gas()) {
344+
const auto& group = well_model_.schedule().getGroup(node, reportStepIdx);
345+
Scalar alq = 0.0;
346+
for (const std::string& wellname : group.wells()) {
347+
const Well& well = well_model_.schedule().getWell(wellname, reportStepIdx);
348+
if (well.isInjector() || !well_state.isOpen(wellname))
349+
continue;
350+
const Scalar efficiency = well.getEfficiencyFactor(/*network*/ true)
351+
* well_state.getGlobalEfficiencyScalingFactor(wellname);
352+
const auto& well_index = well_state.index(wellname);
353+
if (well_index.has_value() &&
354+
well_state.wellIsOwned(well_index.value(), wellname))
355+
{
356+
alq += well_state.well(wellname).alq_state.get() * efficiency;
357+
}
358+
}
359+
alq = comm.sum(alq);
360+
node_inflows[node][IndexTraits::gasPhaseIdx] += alq;
361+
}
362+
}
363+
364+
// Accumulate in the network, towards the roots. Note that a
365+
// root (i.e. fixed pressure node) can still be contributing
366+
// flow towards other nodes in the network, i.e. a node is
367+
// the root of a subtree.
368+
auto child_to_root_nodes = root_to_child_nodes;
369+
std::reverse(child_to_root_nodes.begin(), child_to_root_nodes.end());
370+
for (const auto& node : child_to_root_nodes) {
371+
const auto upbranch = network.uptree_branch(node);
372+
if (upbranch) {
373+
// Add downbranch rates to upbranch.
374+
std::vector<Scalar>& up = node_inflows[(*upbranch).uptree_node()];
375+
const std::vector<Scalar>& down = node_inflows[node];
376+
// We now also support NEFAC
377+
const Scalar efficiency = network.node(node).efficiency();
378+
if (up.empty()) {
379+
up = std::vector<Scalar>(down.size(), 0.0);
380+
}
381+
assert(up.size() == down.size());
382+
for (std::size_t ii = 0; ii < up.size(); ++ii) {
383+
up[ii] += efficiency * down[ii];
384+
}
385+
}
386+
}
387+
388+
// Going the other way (from roots to leafs), calculate the pressure
389+
// at each node using VFP tables and rates.
390+
// std::map<std::string, double> node_pressures;
391+
for (const auto& node : root_to_child_nodes) {
392+
auto press = network.node(node).terminal_pressure();
393+
if (press) {
394+
node_pressures[node] = *press;
395+
} else {
396+
const auto upbranch = network.uptree_branch(node);
397+
assert(upbranch);
398+
const Scalar up_press = node_pressures[(*upbranch).uptree_node()];
399+
const auto vfp_table = (*upbranch).vfp_table();
400+
if (vfp_table) {
401+
OPM_TIMEBLOCK(NetworkVfpCalculations);
402+
// The rates are here positive, but the VFP code expects the
403+
// convention that production rates are negative, so we must
404+
// take a copy and flip signs.
405+
auto rates = node_inflows[node];
406+
std::transform(
407+
rates.begin(), rates.end(), rates.begin(), [](const auto r) { return -r; });
408+
assert(rates.size() == 3);
409+
// NB! ALQ in extended network is never implicitly the gas lift rate (GRAT), i.e., the
410+
// gas lift rates only enters the network pressure calculations through the rates
411+
// (e.g., in GOR calculations) unless a branch ALQ is set in BRANPROP.
412+
//
413+
// @TODO: Standard network
414+
Scalar alq = (*upbranch).alq_value().value_or(0.0);
415+
node_pressures[node]
416+
= vfp_prod_props.bhp(*vfp_table,
417+
rates[IndexTraits::waterPhaseIdx],
418+
rates[IndexTraits::oilPhaseIdx],
419+
rates[IndexTraits::gasPhaseIdx],
420+
up_press,
421+
alq,
422+
0.0, // explicit_wfr
423+
0.0, // explicit_gfr
424+
false); // use_expvfp we dont support explicit lookup
425+
#define EXTRA_DEBUG_NETWORK 0
426+
#if EXTRA_DEBUG_NETWORK
427+
std::ostringstream oss;
428+
oss << "parent: " << (*upbranch).uptree_node() << " child: " << node << " rates = [ "
429+
<< rates[0] * 86400 << ", " << rates[1] * 86400 << ", " << rates[2] * 86400 << " ]"
430+
<< " p(parent) = " << up_press / 1e5 << " p(child) = " << node_pressures[node] / 1e5
431+
<< std::endl;
432+
OpmLog::debug(oss.str());
433+
#endif
434+
} else {
435+
// Table number specified as 9999 in the deck, no pressure loss.
436+
if (network.node(node).as_choke()) {
437+
// Node pressure is set to the group THP.
438+
node_pressures[node] = well_model_.wgHelper().groupState().well_group_thp(node);
439+
} else {
440+
node_pressures[node] = up_press;
441+
}
442+
}
443+
}
444+
}
445+
}
446+
return node_pressures;
447+
}
448+
287449
template<typename Scalar, typename IndexTraits>
288450
bool BlackoilWellModelNetworkGeneric<Scalar, IndexTraits>::
289451
operator==(const BlackoilWellModelNetworkGeneric<Scalar,IndexTraits>& rhs) const

opm/simulators/wells/BlackoilWellModelNetworkGeneric.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
#ifndef OPM_BLACKOILWELLMODEL_NETWORK_GENERIC_HEADER_INCLUDED
2424
#define OPM_BLACKOILWELLMODEL_NETWORK_GENERIC_HEADER_INCLUDED
2525

26+
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
27+
2628
#include <opm/output/data/Groups.hpp>
29+
2730
#include <opm/simulators/utils/ParallelCommunication.hpp>
2831

2932
#include <map>
@@ -34,6 +37,7 @@ namespace Opm {
3437
class Schedule;
3538
template<class Scalar, class IndexTraits> class BlackoilWellModelGeneric;
3639
template<typename Scalar, typename IndexTraits> class WellInterfaceGeneric;
40+
template<typename Scalar> class VFPProdProperties;
3741
}
3842

3943
namespace Opm {
@@ -100,6 +104,13 @@ class BlackoilWellModelNetworkGeneric
100104
bool operator==(const BlackoilWellModelNetworkGeneric<Scalar,IndexTraits>& rhs) const;
101105

102106
protected:
107+
std::map<std::string, Scalar>
108+
computePressures(const Network::ExtNetwork& network,
109+
const VFPProdProperties<Scalar>& vfp_prod_props,
110+
const int reportStepIdx,
111+
const Parallel::Communication& comm) const;
112+
113+
103114
bool active_{false};
104115
BlackoilWellModelGeneric<Scalar,IndexTraits>& well_model_;
105116

0 commit comments

Comments
 (0)