diff --git a/src/pandapipes/component_models/abstract_models/branch_models.py b/src/pandapipes/component_models/abstract_models/branch_models.py index a486faba..9a902986 100644 --- a/src/pandapipes/component_models/abstract_models/branch_models.py +++ b/src/pandapipes/component_models/abstract_models/branch_models.py @@ -5,7 +5,7 @@ import numpy as np from pandapipes.component_models.abstract_models.base_component import Component -from pandapipes.idx_branch import MDOTINIT, branch_cols, TEXT +from pandapipes.idx_branch import MDOTINIT, branch_cols, TEXT, VLRLCONNECT from pandapipes.pf.pipeflow_setup import get_table_number, get_lookup, get_net_option try: @@ -90,6 +90,7 @@ def create_pit_branch_entries(cls, net, branch_pit): branch_component_pit[:, :] = np.array([branch_table_nr] + [0] * (branch_cols - 1)) branch_component_pit[:, MDOTINIT] = 0.1 branch_component_pit[:, TEXT] = get_net_option(net, 'ambient_temperature') + branch_component_pit[:, VLRLCONNECT] = False return branch_component_pit, node_pit, from_nodes, to_nodes @classmethod diff --git a/src/pandapipes/component_models/flow_control_component.py b/src/pandapipes/component_models/flow_control_component.py index 78db23dc..9224694a 100644 --- a/src/pandapipes/component_models/flow_control_component.py +++ b/src/pandapipes/component_models/flow_control_component.py @@ -10,7 +10,7 @@ from pandapipes.component_models.component_toolbox import \ standard_branch_wo_internals_result_lookup, get_component_array from pandapipes.component_models.junction_component import Junction -from pandapipes.idx_branch import JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DM, MDOTINIT, LOAD_VEC_BRANCHES +from pandapipes.idx_branch import JAC_DERIV_DP, JAC_DERIV_DP1, JAC_DERIV_DM, MDOTINIT, LOAD_VEC_BRANCHES, VLRLCONNECT from pandapipes.pf.result_extraction import extract_branch_results_without_internals @@ -50,6 +50,7 @@ def create_pit_branch_entries(cls, net, branch_pit): """ fc_branch_pit = super().create_pit_branch_entries(net, branch_pit) fc_branch_pit[:, MDOTINIT] = net[cls.table_name()].controlled_mdot_kg_per_s.values + fc_branch_pit[net[cls.table_name()].control_active, VLRLCONNECT] = True @classmethod def create_component_array(cls, net, component_pits): diff --git a/src/pandapipes/component_models/heat_consumer_component.py b/src/pandapipes/component_models/heat_consumer_component.py index 2d7eac6a..666241b7 100644 --- a/src/pandapipes/component_models/heat_consumer_component.py +++ b/src/pandapipes/component_models/heat_consumer_component.py @@ -10,7 +10,7 @@ from pandapipes.component_models.junction_component import Junction from pandapipes.idx_branch import (MDOTINIT, QEXT, JAC_DERIV_DP1, JAC_DERIV_DM, JAC_DERIV_DP, LOAD_VEC_BRANCHES, TOUTINIT, JAC_DERIV_DT, - JAC_DERIV_DTOUT, LOAD_VEC_BRANCHES_T, ACTIVE) + JAC_DERIV_DTOUT, LOAD_VEC_BRANCHES_T, ACTIVE, VLRLCONNECT) from pandapipes.idx_node import TINIT from pandapipes.pf.internals_toolbox import get_from_nodes_corrected from pandapipes.pf.pipeflow_setup import get_lookup @@ -77,6 +77,7 @@ def create_pit_branch_entries(cls, net, branch_pit): hc_pit[~np.isnan(mdot), MDOTINIT] = mdot[~np.isnan(mdot)] treturn = net[cls.table_name()].treturn_k.values hc_pit[~np.isnan(treturn), TOUTINIT] = treturn[~np.isnan(treturn)] + hc_pit[:, VLRLCONNECT] = True mask_q0 = qext == 0 & np.isnan(mdot) if np.any(mask_q0): hc_pit[mask_q0, ACTIVE] = False diff --git a/src/pandapipes/idx_branch.py b/src/pandapipes/idx_branch.py index 58cc0f9f..151b1fc4 100644 --- a/src/pandapipes/idx_branch.py +++ b/src/pandapipes/idx_branch.py @@ -10,43 +10,43 @@ TABLE_IDX = 0 # number of the table that this branch belongs to ELEMENT_IDX = 1 # index of the element that this branch belongs to (within the given table) BRANCH_TYPE = 2 # branch type relevant for the pressure controller -PUMP_TYPE = 3 -FROM_NODE = 4 # f, from bus number -TO_NODE = 5 # t, to bus number -ACTIVE = 6 -LENGTH = 7 # Pipe length in [m] -D = 8 # Diameter in [m] -AREA = 9 # Area in [m²] -K = 10 # Pipe roughness in [m] -RE = 11 # Reynolds number -LAMBDA = 12 # Lambda -LOSS_COEFFICIENT = 13 -ALPHA = 14 # Slot for heat transfer coefficient -QEXT = 15 # heat input into the branch [W] -TEXT = 16 # temperature of surrounding [K] -PL = 17 # Pressure lift [bar] -TL = 18 # Temperature lift [K] +FROM_NODE = 3 # f, from bus number +TO_NODE = 4 # t, to bus number +ACTIVE = 5 +LENGTH = 6 # Pipe length in [m] +D = 7 # Diameter in [m] +AREA = 8 # Area in [m²] +K = 9 # Pipe roughness in [m] +RE = 10 # Reynolds number +LAMBDA = 11 # Lambda +LOSS_COEFFICIENT = 12 +ALPHA = 13 # Slot for heat transfer coefficient +QEXT = 14 # heat input into the branch [W] +TEXT = 15 # temperature of surrounding [K] +PL = 16 # Pressure lift [bar] +TL = 17 # Temperature lift [K] -MDOTINIT = 19 # mass in [m/s] -MDOTINIT_T = 20 -FROM_NODE_T_SWITCHED = 21 # flag to indicate if the from and to node are switched in the thermal calculation -TOUTINIT = 22 # Internal slot for outlet pipe temperature +MDOTINIT = 18 # mass in [m/s] +MDOTINIT_T = 19 +FROM_NODE_T_SWITCHED = 20 # flag to indicate if the from and to node are switched in the thermal calculation +TOUTINIT = 21 # Internal slot for outlet pipe temperature -JAC_DERIV_DM = 23 # Slot for the derivative by mass -JAC_DERIV_DP = 24 # Slot for the derivative by pressure from_node -JAC_DERIV_DP1 = 25 # Slot for the derivative by pressure to_node -JAC_DERIV_DM_NODE = 26 # Slot for the derivative by mass for the nodes connected to branch -LOAD_VEC_BRANCHES = 27 # Slot for the load vector for the branches -LOAD_VEC_NODES_FROM = 28 # Slot for the load vector of the from nodes connected to branch -LOAD_VEC_NODES_TO = 29 # Slot for the load vector of the to nodes connected to branch +JAC_DERIV_DM = 22 # Slot for the derivative by mass +JAC_DERIV_DP = 23 # Slot for the derivative by pressure from_node +JAC_DERIV_DP1 = 24 # Slot for the derivative by pressure to_node +JAC_DERIV_DM_NODE = 25 # Slot for the derivative by mass for the nodes connected to branch +LOAD_VEC_BRANCHES = 26 # Slot for the load vector for the branches +LOAD_VEC_NODES_FROM = 27 # Slot for the load vector of the from nodes connected to branch +LOAD_VEC_NODES_TO = 28 # Slot for the load vector of the to nodes connected to branch +JAC_DERIV_DT = 29 +JAC_DERIV_DTOUT = 30 +JAC_DERIV_DT_NODE = 31 # Slot for the node equation derivative of T for the nodes branch is connected to +JAC_DERIV_DTOUT_NODE = 32 # Slot for the node equation derivative of T for the corresponding branch +LOAD_VEC_BRANCHES_T = 33 +LOAD_VEC_NODES_FROM_T = 34 # Slot for the load vector of the from nodes connected to branch +LOAD_VEC_NODES_TO_T = 35 # Slot for the load vector of the to nodes connected to branch -JAC_DERIV_DT = 30 -JAC_DERIV_DTOUT = 31 -JAC_DERIV_DT_NODE = 32 # Slot for the node equation derivative of T for the nodes branch is connected to -JAC_DERIV_DTOUT_NODE = 33 # Slot for the node equation derivative of T for the corresponding branch -LOAD_VEC_BRANCHES_T = 34 -LOAD_VEC_NODES_FROM_T = 35 # Slot for the load vector of the from nodes connected to branch -LOAD_VEC_NODES_TO_T = 36 # Slot for the load vector of the to nodes connected to branch +VLRLCONNECT = 36 branch_cols = 37 diff --git a/src/pandapipes/pf/pipeflow_setup.py b/src/pandapipes/pf/pipeflow_setup.py index fe1e7dcd..30a6f7be 100644 --- a/src/pandapipes/pf/pipeflow_setup.py +++ b/src/pandapipes/pf/pipeflow_setup.py @@ -10,7 +10,7 @@ from scipy.sparse import coo_matrix, csgraph from pandapipes.idx_branch import FROM_NODE, TO_NODE, branch_cols, MDOTINIT, \ - ACTIVE as ACTIVE_BR + ACTIVE as ACTIVE_BR, VLRLCONNECT, ACTIVE, BRANCH_TYPE, CIRC from pandapipes.idx_node import NODE_TYPE, P, NODE_TYPE_T, node_cols, T, ACTIVE as ACTIVE_ND, \ TABLE_IDX as TABLE_IDX_ND, ELEMENT_IDX as ELEMENT_IDX_ND, INFEED from pandapipes.pf.internals_toolbox import _sum_by_group @@ -617,8 +617,24 @@ def check_connectivity(net, branch_pit, node_pit, mode="hydraulics"): active_branch_lookup, mode=mode) -def perform_connectivity_search(net, node_pit, branch_pit, slack_nodes, - active_node_lookup, active_branch_lookup, mode="hydraulics"): +def perform_connectivity_search(net, node_pit, branch_pit, slack_nodes, active_node_lookup, active_branch_lookup, + mode="hydraulics"): + connect = branch_pit[:, VLRLCONNECT].astype(bool) + circ = branch_pit[:, BRANCH_TYPE] == CIRC + if np.any(circ) and mode == 'hydraulics': + active_branch_lookup = active_branch_lookup & ~connect + nodes_connected, branches_connected = ( + _connectivity(net, branch_pit, node_pit, active_branch_lookup, active_node_lookup, slack_nodes, mode)) + if np.any(connect) and mode == 'hydraulics': + from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) + to_nodes = branch_pit[:, TO_NODE].astype(np.int32) + branch_active = branch_pit[:, ACTIVE].astype(bool) + active = nodes_connected[from_nodes] & nodes_connected[to_nodes] & branch_active + branches_connected[connect & active] = True + return nodes_connected, branches_connected + + +def _connectivity(net, branch_pit, node_pit, active_branch_lookup, active_node_lookup, slack_nodes, mode): len_nodes = len(node_pit) from_nodes = branch_pit[:, FROM_NODE].astype(np.int32) to_nodes = branch_pit[:, TO_NODE].astype(np.int32) @@ -775,7 +791,7 @@ def reduce_pit(net, mode="hydraulics"): def check_infeed_number(node_pit): slack_nodes = node_pit[:, NODE_TYPE_T] == T - if len(node_pit) == 1: + if len(node_pit) == np.sum(slack_nodes): node_pit[slack_nodes, INFEED] = True infeed_nodes = node_pit[:, INFEED] if np.sum(infeed_nodes) != np.sum(slack_nodes): diff --git a/src/pandapipes/test/api/test_special_networks.py b/src/pandapipes/test/api/test_special_networks.py index b04769f8..0d80f013 100644 --- a/src/pandapipes/test/api/test_special_networks.py +++ b/src/pandapipes/test/api/test_special_networks.py @@ -8,8 +8,8 @@ import pytest import pandapipes -from pandapipes.create import create_empty_network, create_junction, create_ext_grid, create_sink, \ - create_source +from pandapipes.create import create_empty_network, create_junction, create_ext_grid, create_sink, create_source +from pandapipes.pf.pipeflow_setup import get_net_option from pandapipes.test.pipeflow_internals.test_inservice import create_test_net from pandapipes.test.test_toolbox import create_net_changed_indices @@ -123,5 +123,62 @@ def test_wild_indexing(create_net_changed_indices): assert net.converged +def test_valve_flow_contrl_heat_consumer(): + net = pandapipes.create_empty_network(fluid='water') + j1, j2, j3, j4, j5, j6, j7, j8, j9 = pandapipes.create_junctions(net, 9, 5, 400) + pandapipes.create_circ_pump_const_pressure(net, j9, j1, 5, 2, 400) + pandapipes.create_valves(net, [j1, j4, j6, j8], [j2, j5, j7, j9], 0.1) + pandapipes.create_flow_control(net, j3, j2, 10) + pandapipes.create_heat_exchanger(net, j8, j3, -5000) + pandapipes.create_pipes_from_parameters(net, [j2, j7], [j4, j8], 0.1, 0.1) + pandapipes.create_heat_consumer(net, j5, j6, 10000, 10) + net.valve.loc[0, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + amb_temp = get_net_option(net, 'ambient_temperature') + + assert np.all(np.isclose(net.res_junction.loc[[j9, j8, j7, j6, j3], 'p_bar'].values, 3.)) + assert np.all(np.isnan(net.res_junction.loc[[j5, j4, j2], 'p_bar']).values) + assert np.all(np.isclose(net.res_junction.loc[[j1], 'p_bar'].values, 5.)) + assert np.all(np.isclose(net.res_junction.t_k.values[1:], amb_temp)) + + net.valve.loc[0, 'opened'] = True + net.valve.loc[3, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + assert np.all(np.isclose(net.res_junction.loc[[j9], 'p_bar'].values, 3.)) + assert np.all(np.isnan(net.res_junction.loc[[j8, j7, j6, j3], 'p_bar']).values) + assert np.all(np.isclose(net.res_junction.loc[[j1, j2, j4, j5], 'p_bar'].values, 5.)) + assert np.all(np.isclose(net.res_junction.t_k.values[1:], amb_temp)) + + net.valve.loc[3, 'opened'] = True + net.valve.loc[1, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + assert np.all(np.isclose(net.res_junction.loc[[j9, j8, j7, j6, j3], 'p_bar'].values, 3.)) + assert np.all(np.isnan(net.res_junction.loc[[j5], 'p_bar']).values) + assert np.all(np.isclose(net.res_junction.loc[[j1, j2, j4], 'p_bar'].values, 5.)) + assert np.all(np.isclose(net.res_junction.t_k.values[[j4, j5, j6, j7]], amb_temp)) + + net.valve.loc[1, 'opened'] = True + net.valve.loc[2, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + assert np.all(np.isclose(net.res_junction.loc[[j9, j8, j7, j3], 'p_bar'].values, 3.)) + assert np.all(np.isnan(net.res_junction.loc[[j6], 'p_bar']).values) + assert np.all(np.isclose(net.res_junction.loc[[j1, j2, j4, j5], 'p_bar'].values, 5.)) + assert np.all(np.isclose(net.res_junction.t_k.values[[j4, j5, j6, j7]], amb_temp)) + + net.valve.loc[1, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + assert np.all(np.isnan(net.res_junction.p_bar.values[4:6])) + + net.valve.loc[:, 'opened'] = False + pandapipes.pipeflow(net, mode='sequential') + + assert np.all(np.isnan(net.res_junction.p_bar.values[1:-1])) + + if __name__ == "__main__": pytest.main([r'pandapipes/test/api/test_special_networks.py'])