20 #ifndef OPM_BLACKOIL_WELL_MODEL_NETWORK_PRESSURE_COMPUTATION_HPP 21 #define OPM_BLACKOIL_WELL_MODEL_NETWORK_PRESSURE_COMPUTATION_HPP 23 #include <opm/common/TimingMacros.hpp> 25 #include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp> 26 #include <opm/input/eclipse/Schedule/Schedule.hpp> 27 #include <opm/input/eclipse/Schedule/VFPProdTable.hpp> 29 #include <opm/output/data/Groups.hpp> 31 #include <opm/simulators/wells/BlackoilWellModelGeneric.hpp> 32 #include <opm/simulators/wells/VFPInjProperties.hpp> 33 #include <opm/simulators/wells/VFPProdProperties.hpp> 48 template<
typename Scalar,
typename IndexTraits,
typename VfpProperties>
52 template<
typename Scalar,
typename IndexTraits>
55 static void prepareRates(std::vector<Scalar>& rates)
58 std::ranges::transform(rates, rates.begin(), [](
const auto r) {
return -r; });
61 template <
class GroupState>
62 static const std::vector<Scalar>
63 leafNodeRate(
const GroupState& group_state,
const std::string& node)
65 return group_state.network_leaf_node_production_rates(node);
68 template<
typename Branch>
71 const std::vector<Scalar>& rates,
72 const Scalar up_press,
73 const Branch& upbranch,
74 const UnitSystem& unit_system)
79 const auto alq_type = vfp_props.
getTable(table_id).getALQType();
80 const auto dimension = VFPProdTable::ALQDimension(alq_type, unit_system);
81 const Scalar alq = upbranch.alq_value(dimension).value_or(0.0);
83 return vfp_props.
bhp(table_id,
84 rates[IndexTraits::waterPhaseIdx],
85 rates[IndexTraits::oilPhaseIdx],
86 rates[IndexTraits::gasPhaseIdx],
96 template<
typename Scalar,
typename IndexTraits>
99 static void prepareRates(std::vector<Scalar>&)
103 template <
class GroupState>
104 static const std::vector<Scalar>
105 leafNodeRate(
const GroupState& group_state,
const std::string& node)
107 return group_state.network_leaf_node_injection_rates(node);
110 template<
typename Branch>
113 const std::vector<Scalar>& rates,
114 const Scalar up_press,
118 return vfp_props.
bhp(table_id,
119 rates[IndexTraits::waterPhaseIdx],
120 rates[IndexTraits::oilPhaseIdx],
121 rates[IndexTraits::gasPhaseIdx],
129 template<
typename GenericWellModel,
typename VfpProperties,
typename Communication = Parallel::Communication>
134 const Network::ExtNetwork& network,
135 const VfpProperties& vfp_props,
136 const UnitSystem& unit_system,
137 const int report_step_idx,
138 const Communication& comm)
139 : well_model_(well_model)
141 , vfp_props_(vfp_props)
142 , unit_system_(unit_system)
143 , report_step_idx_(report_step_idx)
148 using Scalar =
typename GenericWellModel::Scalar;
149 using IndexTraits = GenericWellModel::IndexTraits;
150 std::pair<std::map<std::string, Scalar>, std::map<std::string, data::BranchData>> run()
152 const auto roots = network_.roots();
153 for (
const auto& root : roots) {
159 const auto [root_to_child_nodes, leaf_nodes] = collectTreeNodes(root.get().name());
163 auto node_inflows = initializeLeafInflows(leaf_nodes);
169 accumulateInflows(root_to_child_nodes, node_inflows);
173 computeNodePressures(root_to_child_nodes, node_inflows);
176 return {node_pressures_, branch_data_};
180 std::pair<std::vector<std::string>, std::set<std::string>>
181 collectTreeNodes(
const std::string& root)
const 183 std::stack<std::string> children;
184 std::set<std::string> leaf_nodes;
185 std::vector<std::string> root_to_child_nodes;
187 while (!children.empty()) {
188 const auto node = children.top();
190 root_to_child_nodes.push_back(node);
191 auto branches = network_.downtree_branches(node);
192 if (branches.empty()) {
193 leaf_nodes.insert(node);
195 for (
const auto& branch : branches) {
196 children.push(branch.downtree_node());
200 assert(children.empty());
201 return {root_to_child_nodes, leaf_nodes};
204 std::map<std::string, std::vector<Scalar>>
205 initializeLeafInflows(
const std::set<std::string>& leaf_nodes)
const 207 std::map<std::string, std::vector<Scalar>> node_inflows;
208 const std::vector<Scalar> zero_rates(3, 0.0);
210 for (
const auto& node : leaf_nodes) {
212 if (!well_model_.groupStateHelper().groupState().has_production_rates(node)) {
213 node_inflows[node] = zero_rates;
218 node_inflows[node] = Calc::leafNodeRate(well_model_.groupStateHelper().groupState(), node);
219 if (network_.node(node).add_gas_lift_gas()) {
220 addGasLiftGas(node, node_inflows[node]);
227 void addGasLiftGas(
const std::string& node,
228 std::vector<Scalar>& rates)
const 230 const auto& group = well_model_.schedule().getGroup(node, report_step_idx_);
231 const auto& well_state = well_model_.groupStateHelper().wellState();
234 for (
const std::string& wellname : group.wells()) {
235 const Well& well = well_model_.schedule().getWell(wellname, report_step_idx_);
236 if (well.isInjector() || !well_state.isOpen(wellname)) {
240 const Scalar efficiency = well.getEfficiencyFactor(
true)
241 * well_state.getGlobalEfficiencyScalingFactor(wellname);
242 const auto& well_index = well_state.index(wellname);
243 if (well_index.has_value() &&
244 well_state.wellIsOwned(well_index.value(), wellname))
246 alq += well_state.well(wellname).alq_state.get() * efficiency;
255 alq = comm_.sum(alq);
258 if (group.hasSatelliteProduction()) {
259 const auto& gsat_prod = well_model_.schedule()[report_step_idx_].gsatprod().get(node, well_model_.summaryState());
260 alq += gsat_prod.rate[GSatProd::GSatProdGroupProp::Rate::GLift];
263 rates[IndexTraits::gasPhaseIdx] += alq;
266 void accumulateInflows(
const std::vector<std::string>& root_to_child_nodes,
267 std::map<std::string, std::vector<Scalar>>& node_inflows)
const 269 const auto child_to_root_nodes = std::ranges::reverse_view(root_to_child_nodes);
271 for (
const auto& node : child_to_root_nodes) {
272 const auto upbranch = network_.uptree_branch(node);
276 std::vector<Scalar>& up = node_inflows[(*upbranch).uptree_node()];
277 const std::vector<Scalar>& down = node_inflows[node];
279 const Scalar efficiency = network_.node(node).efficiency();
281 up = std::vector<Scalar>(down.size(), 0.0);
283 assert(up.size() == down.size());
284 for (std::size_t ii = 0; ii < up.size(); ++ii) {
285 up[ii] += efficiency * down[ii];
290 void computeNodePressures(
const std::vector<std::string>& root_to_child_nodes,
291 const std::map<std::string, std::vector<Scalar>>& node_inflows)
293 for (
const auto& node : root_to_child_nodes) {
295 if (node_pressures_.find(node) != node_pressures_.end()) {
299 const auto terminal_pressure = network_.node(node).terminal_pressure();
300 const auto upbranch = network_.uptree_branch(node);
301 assert(upbranch || terminal_pressure);
304 if (terminal_pressure) {
305 node_pressures_[node] = *terminal_pressure;
308 const Scalar up_press = node_pressures_[(*upbranch).uptree_node()];
309 auto rates = node_inflows.at(node);
310 branch_data_.try_emplace(node,
311 *terminal_pressure - up_press,
312 rates[IndexTraits::oilPhaseIdx],
313 rates[IndexTraits::waterPhaseIdx],
314 rates[IndexTraits::gasPhaseIdx]);
317 branch_data_.emplace(node, data::BranchData{0.0, 0.0, 0.0, 0.0});
322 const Scalar up_press = node_pressures_[(*upbranch).uptree_node()];
323 const auto vfp_table = (*upbranch).vfp_table();
326 if (network_.node(node).as_choke()) {
328 node_pressures_[node] = well_model_.groupStateHelper().groupState().well_group_thp(node);
330 node_pressures_[node] = up_press;
332 auto rates = node_inflows.at(node);
333 branch_data_.try_emplace(node,
334 node_pressures_[node] - up_press,
335 rates[IndexTraits::oilPhaseIdx],
336 rates[IndexTraits::waterPhaseIdx],
337 rates[IndexTraits::gasPhaseIdx]);
341 OPM_TIMEBLOCK(NetworkVfpCalculations);
342 auto rates = node_inflows.at(node);
343 assert(rates.size() == 3);
344 Calc::prepareRates(rates);
345 auto node_pressure = Calc::compute(vfp_props_, *vfp_table, rates, up_press, *upbranch, unit_system_);
346 node_pressures_[node] = node_pressure;
348 branch_data_.try_emplace(node,
349 node_pressure - up_press,
350 -rates[IndexTraits::oilPhaseIdx],
351 -rates[IndexTraits::waterPhaseIdx],
352 -rates[IndexTraits::gasPhaseIdx]);
356 const GenericWellModel& well_model_;
357 const Network::ExtNetwork& network_;
358 const VfpProperties& vfp_props_;
359 const UnitSystem& unit_system_;
360 const int report_step_idx_;
361 const Communication& comm_;
362 std::map<std::string, Scalar> node_pressures_;
363 std::map<std::string, data::BranchData> branch_data_;
368 #endif // OPM_BLACKOIL_WELL_MODEL_NETWORK_PRESSURE_COMPUTATION_HPP Helper class to insulate the NetworkPressureComputation class from the differences between production...
Definition: BlackoilWellModelNetworkPressureComputation.hpp:49
EvalWell bhp(const int table_id, const EvalWell &aqua, const EvalWell &liquid, const EvalWell &vapour, const Scalar thp, const Scalar alq, const Scalar explicit_wfr, const Scalar explicit_gfr, const bool use_expvfp) const
Linear interpolation of bhp as a function of the input parameters given as Evalutions Each entry corr...
Definition: VFPProdProperties.cpp:165
Class which linearly interpolates BHP as a function of rate, tubing head pressure, water fraction, gas fraction, and artificial lift for production VFP tables, and similarly the BHP as a function of the rate and tubing head pressure.
Definition: BlackoilWellModelNetworkGeneric.hpp:42
Definition: VFPInjProperties.hpp:34
Definition: BlackoilWellModelConstraints.hpp:34
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
const VFPProdTable & getTable(const int table_id) const
Returns the table associated with the ID, or throws an exception if the table does not exist...
Definition: VFPProdProperties.cpp:99
Class to compute network pressures using VFP tables, given flow rates for each group and fixed pressu...
Definition: BlackoilWellModelNetworkPressureComputation.hpp:130
EvalWell bhp(const int table_id, const EvalWell &aqua, const EvalWell &liquid, const EvalWell &vapour, const Scalar thp) const
Linear interpolation of bhp as a function of the input parameters given as Evaluation Each entry corr...
Definition: VFPInjProperties.cpp:103