|
1 |
+ |
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics |
|
2 |
+ |
# and Energy System Technology (IEE), Kassel. All rights reserved. |
|
3 |
+ |
# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. |
|
4 |
+ |
|
|
5 |
+ |
import numpy as np |
|
6 |
+ |
from numpy import dtype |
|
7 |
+ |
from pandapipes.constants import R_UNIVERSAL |
|
8 |
+ |
|
|
9 |
+ |
from pandapipes.component_models.abstract_models import BranchWZeroLengthComponent, get_fluid, \ |
|
10 |
+ |
TINIT_NODE |
|
11 |
+ |
from pandapipes.idx_branch import D, AREA, PL, TL, \ |
|
12 |
+ |
JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DV, BRANCH_TYPE, FROM_NODE, TO_NODE, VINIT, \ |
|
13 |
+ |
LOAD_VEC_NODES, ELEMENT_IDX, LOSS_COEFFICIENT as LC |
|
14 |
+ |
from pandapipes.idx_node import PINIT, NODE_TYPE, PC |
|
15 |
+ |
from pandapipes.internals_toolbox import _sum_by_group |
|
16 |
+ |
from pandapipes.pipeflow_setup import get_lookup, get_net_option |
|
17 |
+ |
|
|
18 |
+ |
|
|
19 |
+ |
class PressureControlComponent(BranchWZeroLengthComponent): |
|
20 |
+ |
""" |
|
21 |
+ |
|
|
22 |
+ |
""" |
|
23 |
+ |
|
|
24 |
+ |
@classmethod |
|
25 |
+ |
def table_name(cls): |
|
26 |
+ |
return "press_control" |
|
27 |
+ |
|
|
28 |
+ |
@classmethod |
|
29 |
+ |
def active_identifier(cls): |
|
30 |
+ |
return "in_service" |
|
31 |
+ |
|
|
32 |
+ |
@classmethod |
|
33 |
+ |
def from_to_node_cols(cls): |
|
34 |
+ |
return "from_junction", "to_junction" |
|
35 |
+ |
|
|
36 |
+ |
@classmethod |
|
37 |
+ |
def create_pit_node_entries(cls, net, node_pit, node_name): |
|
38 |
+ |
pcs = net[cls.table_name()] |
|
39 |
+ |
controlled = pcs.in_service & pcs.control_active |
|
40 |
+ |
juncts = pcs['controlled_junction'].values[controlled] |
|
41 |
+ |
press = pcs['controlled_p_bar'].values[controlled] |
|
42 |
+ |
junction_idx_lookups = get_lookup(net, "node", "index")[node_name] |
|
43 |
+ |
index_pc = junction_idx_lookups[juncts] |
|
44 |
+ |
node_pit[index_pc, NODE_TYPE] = PC |
|
45 |
+ |
node_pit[index_pc, PINIT] = press |
|
46 |
+ |
|
|
47 |
+ |
@classmethod |
|
48 |
+ |
def create_pit_branch_entries(cls, net, pc_pit, node_name): |
|
49 |
+ |
""" |
|
50 |
+ |
Function which creates pit branch entries with a specific table. |
|
51 |
+ |
:param net: The pandapipes network |
|
52 |
+ |
:type net: pandapipesNet |
|
53 |
+ |
:param pc_pit: |
|
54 |
+ |
:type pc_pit: |
|
55 |
+ |
:param node_name: |
|
56 |
+ |
:type node_name: |
|
57 |
+ |
:return: No Output. |
|
58 |
+ |
""" |
|
59 |
+ |
pc_pit = super().create_pit_branch_entries(net, pc_pit, node_name) |
|
60 |
+ |
pc_pit[:, D] = 0.1 |
|
61 |
+ |
pc_pit[:, AREA] = pc_pit[:, D] ** 2 * np.pi / 4 |
|
62 |
+ |
pc_pit[net[cls.table_name()].control_active.values, BRANCH_TYPE] = PC |
|
63 |
+ |
pc_pit[:, LC] = net[cls.table_name()].loss_coefficient.values |
|
64 |
+ |
|
|
65 |
+ |
@classmethod |
|
66 |
+ |
def calculate_derivatives_hydraulic(cls, net, branch_pit, node_pit, idx_lookups, options): |
|
67 |
+ |
press_pit = super().calculate_derivatives_hydraulic(net, branch_pit, node_pit, idx_lookups, |
|
68 |
+ |
options) |
|
69 |
+ |
pc_branch = press_pit[:, BRANCH_TYPE] == PC |
|
70 |
+ |
press_pit[pc_branch, JAC_DERIV_DP] = 0 |
|
71 |
+ |
press_pit[pc_branch, JAC_DERIV_DP1] = 0 |
|
72 |
+ |
press_pit[pc_branch, JAC_DERIV_DV] = 0 |
|
73 |
+ |
|
|
74 |
+ |
@classmethod |
|
75 |
+ |
def calculate_pressure_lift(cls, net, pc_pit, node_pit): |
|
76 |
+ |
""" |
|
77 |
+ |
|
|
78 |
+ |
:param net: The pandapipes network |
|
79 |
+ |
:type net: pandapipesNet |
|
80 |
+ |
:param pc_pit: |
|
81 |
+ |
:type pc_pit: |
|
82 |
+ |
:param node_pit: |
|
83 |
+ |
:type node_pit: |
|
84 |
+ |
:return: power stroke |
|
85 |
+ |
:rtype: float |
|
86 |
+ |
""" |
|
87 |
+ |
pc_pit[:, PL] = 0 |
|
88 |
+ |
|
|
89 |
+ |
@classmethod |
|
90 |
+ |
def calculate_temperature_lift(cls, net, pc_pit, node_pit): |
|
91 |
+ |
""" |
|
92 |
+ |
|
|
93 |
+ |
:param net: |
|
94 |
+ |
:type net: |
|
95 |
+ |
:param pc_pit: |
|
96 |
+ |
:type pc_pit: |
|
97 |
+ |
:param node_pit: |
|
98 |
+ |
:type node_pit: |
|
99 |
+ |
:return: |
|
100 |
+ |
:rtype: |
|
101 |
+ |
""" |
|
102 |
+ |
pc_pit[:, TL] = 0 |
|
103 |
+ |
|
|
104 |
+ |
@classmethod |
|
105 |
+ |
def extract_results(cls, net, options, node_name): |
|
106 |
+ |
""" |
|
107 |
+ |
Function that extracts certain results. |
|
108 |
+ |
|
|
109 |
+ |
:param net: The pandapipes network |
|
110 |
+ |
:type net: pandapipesNet |
|
111 |
+ |
:param options: |
|
112 |
+ |
:type options: |
|
113 |
+ |
:param node_name: |
|
114 |
+ |
:type node_name: |
|
115 |
+ |
:return: No Output. |
|
116 |
+ |
""" |
|
117 |
+ |
placement_table, pc_pit, res_table = cls.prepare_result_tables(net, options, node_name) |
|
118 |
+ |
|
|
119 |
+ |
node_pit = net["_active_pit"]["node"] |
|
120 |
+ |
node_active_idx_lookup = get_lookup(net, "node", "index_active")[node_name] |
|
121 |
+ |
junction_idx_lookup = get_lookup(net, "node", "index")[node_name] |
|
122 |
+ |
from_junction_nodes = node_active_idx_lookup[junction_idx_lookup[ |
|
123 |
+ |
net[cls.table_name()]["from_junction"].values[placement_table]]] |
|
124 |
+ |
to_junction_nodes = node_active_idx_lookup[junction_idx_lookup[ |
|
125 |
+ |
net[cls.table_name()]["to_junction"].values[placement_table]]] |
|
126 |
+ |
|
|
127 |
+ |
p_to = node_pit[to_junction_nodes, PINIT] |
|
128 |
+ |
p_from = node_pit[from_junction_nodes, PINIT] |
|
129 |
+ |
res_table['deltap_bar'].values[placement_table] = p_to - p_from |
|
130 |
+ |
|
|
131 |
+ |
from_nodes = pc_pit[:, FROM_NODE].astype(np.int32) |
|
132 |
+ |
to_nodes = pc_pit[:, TO_NODE].astype(np.int32) |
|
133 |
+ |
|
|
134 |
+ |
t0 = node_pit[from_nodes, TINIT_NODE] |
|
135 |
+ |
t1 = node_pit[to_nodes, TINIT_NODE] |
|
136 |
+ |
mf = pc_pit[:, LOAD_VEC_NODES] |
|
137 |
+ |
vf = pc_pit[:, LOAD_VEC_NODES] / get_fluid(net).get_density((t0 + t1) / 2) |
|
138 |
+ |
|
|
139 |
+ |
idx_active = pc_pit[:, ELEMENT_IDX] |
|
140 |
+ |
idx_sort, mf_sum, vf_sum, internal_pipes = \ |
|
141 |
+ |
_sum_by_group(idx_active, mf, vf, np.ones_like(idx_active)) |
|
142 |
+ |
res_table["mdot_to_kg_per_s"].values[placement_table] = -mf_sum / internal_pipes |
|
143 |
+ |
res_table["mdot_from_kg_per_s"].values[placement_table] = mf_sum / internal_pipes |
|
144 |
+ |
res_table["vdot_norm_m3_per_s"].values[placement_table] = vf_sum / internal_pipes |
|
145 |
+ |
|
|
146 |
+ |
if net.fluid.is_gas: |
|
147 |
+ |
compr = net.fluid.get_compressibility(t0) |
|
148 |
+ |
molar_mass = net.fluid.get_molar_mass() # [g/mol] |
|
149 |
+ |
R_spec = 1e3 * R_UNIVERSAL / molar_mass # [J/(kg * K)] |
|
150 |
+ |
# 'kappa' heat capacity ratio: |
|
151 |
+ |
k = 1.4 # TODO: implement proper calculation of kappa |
|
152 |
+ |
w_real_isentr = (k / (k - 1)) * compr * R_spec * t0 * \ |
|
153 |
+ |
(np.divide(p_to, p_from) ** ((k - 1) / k) - 1) |
|
154 |
+ |
res_table['id_isentropic_compr_w'].values[placement_table] = \ |
|
155 |
+ |
w_real_isentr * abs(mf_sum / internal_pipes) |
|
156 |
+ |
|
|
157 |
+ |
@classmethod |
|
158 |
+ |
def get_component_input(cls): |
|
159 |
+ |
""" |
|
160 |
+ |
|
|
161 |
+ |
Get component input. |
|
162 |
+ |
|
|
163 |
+ |
:return: |
|
164 |
+ |
:rtype: |
|
165 |
+ |
""" |
|
166 |
+ |
return [("name", dtype(object)), |
|
167 |
+ |
("from_junction", "u4"), |
|
168 |
+ |
("to_junction", "u4"), |
|
169 |
+ |
("controlled_junction", "u4"), |
|
170 |
+ |
("controlled_p_bar", "f8"), |
|
171 |
+ |
("control_active", "bool"), |
|
172 |
+ |
("loss_coefficient", "f8"), |
|
173 |
+ |
("in_service", 'bool'), |
|
174 |
+ |
("type", dtype(object))] |
|
175 |
+ |
|
|
176 |
+ |
@classmethod |
|
177 |
+ |
def get_result_table(cls, net): |
|
178 |
+ |
""" |
|
179 |
+ |
|
|
180 |
+ |
Gets the result table. |
|
181 |
+ |
|
|
182 |
+ |
:param net: The pandapipes network |
|
183 |
+ |
:type net: pandapipesNet |
|
184 |
+ |
:return: (columns, all_float) - the column names and whether they are all float type. Only |
|
185 |
+ |
if False, returns columns as tuples also specifying the dtypes |
|
186 |
+ |
:rtype: (list, bool) |
|
187 |
+ |
""" |
|
188 |
+ |
result_columns = ["deltap_bar", "mdot_from_kg_per_s", "mdot_to_kg_per_s", |
|
189 |
+ |
"vdot_norm_m3_per_s"] |
|
190 |
+ |
if net.fluid.is_gas: |
|
191 |
+ |
result_columns += ['id_isentropic_compr_w'] |
|
192 |
+ |
|
|
193 |
+ |
return result_columns, True |