diff --git a/pandapipes/pf/pipeflow_setup.py b/pandapipes/pf/pipeflow_setup.py index 4034bbb39..1b314a462 100644 --- a/pandapipes/pf/pipeflow_setup.py +++ b/pandapipes/pf/pipeflow_setup.py @@ -6,6 +6,7 @@ import inspect import numpy as np +from pandapower.auxiliary import ppException from scipy.sparse import coo_matrix, csgraph from pandapipes.idx_branch import FROM_NODE, TO_NODE, branch_cols, \ @@ -22,6 +23,7 @@ numba_installed = True except ImportError: from pandapower.pf.no_numba import jit + numba_installed = False try: @@ -496,9 +498,13 @@ def identify_active_nodes_branches(net, branch_pit, node_pit, hydraulic=True): # here, any value between 0 and 1 should work, excluding 0 and 1) nodes_connected[fn_tn] = nodes_connected[fn_tn] & (flow > 0.1) mode = "hydraulics" if hydraulic else "heat_transfer" + if np.all(~nodes_connected): + mode = 'hydraulic' if hydraulic else 'heat transfer' + raise PipeflowNotConverged(" All nodes are set out of service. Probably they are not supplied." + " Therefore, the %s pipeflow did not converge. " + " Have you forgotten to define an external grid?" % mode) net["_lookups"]["node_active_" + mode] = nodes_connected net["_lookups"]["branch_active_" + mode] = branches_connected - return node_pit[nodes_connected], branch_pit[branches_connected] def branches_connected_flow(branch_pit): @@ -552,7 +558,7 @@ def check_connectivity(net, branch_pit, node_pit, mode="hydraulics"): else: active_branch_lookup = branches_connected_flow(branch_pit) \ & get_lookup(net, "branch", "active_hydraulics") - active_node_lookup = node_pit[:, ACTIVE_ND].astype(np.bool_)\ + active_node_lookup = node_pit[:, ACTIVE_ND].astype(np.bool_) \ & get_lookup(net, "node", "active_hydraulics") slacks = np.where((node_pit[:, NODE_TYPE_T] == T) & active_node_lookup)[0] @@ -635,7 +641,7 @@ def get_table_index_list(net, pit_array, pit_indices, pit_type="node"): tables = np.unique(int_pit[:, TABLE_IDX_ND]) table_lookup = get_lookup(net, pit_type, "table") return [(get_table_name(table_lookup, tbl), list(int_pit[int_pit[:, TABLE_IDX_ND] == tbl, - ELEMENT_IDX_ND].astype(np.int32))) + ELEMENT_IDX_ND].astype(np.int32))) for tbl in tables] @@ -710,3 +716,10 @@ def reduce_pit(net, node_pit, branch_pit, mode="hydraulics"): from_to_active_lookup[table] = (count, count + len_new) count += len_new net["_lookups"]["%s_from_to_active_%s" % (el, mode)] = from_to_active_lookup + + +class PipeflowNotConverged(ppException): + """ + Exception being raised in case pipeflow did not converge. + """ + pass diff --git a/pandapipes/pipeflow.py b/pandapipes/pipeflow.py index 886ed571e..4dab2f9f1 100644 --- a/pandapipes/pipeflow.py +++ b/pandapipes/pipeflow.py @@ -13,9 +13,8 @@ from pandapipes.pf.pipeflow_setup import get_net_option, get_net_options, set_net_option, \ init_options, create_internal_results, write_internal_results, get_lookup, create_lookups, \ initialize_pit, reduce_pit, set_user_pf_options, init_all_result_tables, \ - identify_active_nodes_branches + identify_active_nodes_branches, PipeflowNotConverged from pandapipes.pf.result_extraction import extract_all_results, extract_results_active_pit -from pandapower.auxiliary import ppException try: import pandaplan.core.pplog as logging @@ -80,12 +79,9 @@ def pipeflow(net, sol_vec=None, **kwargs): calculate_hydraulics = calculation_mode in ["hydraulics", "all"] calculate_heat = calculation_mode in ["heat", "all"] - active_node_pit, active_branch_pit = identify_active_nodes_branches(net, branch_pit, node_pit) - - if (len(active_node_pit) == 0): - logger.warning(" All nodes are out of service. Probably they are not supplied." - " Have you forgotten to define an external grid?") - return + # cannot be moved to calculate_hydraulics as the active node/branch hydraulics lookup is also required to + # determine the active node/branch heat transfer lookup + identify_active_nodes_branches(net, branch_pit, node_pit) if calculation_mode == "heat": if not net.user_pf_options["hyd_flag"]: @@ -364,10 +360,3 @@ def log_final_results(net, niter, residual_norm, hyraulic_mode=True): logger.debug("Norm of residual: %s" % residual_norm) for out in outputs: logger.debug("%s: %s" % (out, get_net_option(net, out))) - - -class PipeflowNotConverged(ppException): - """ - Exception being raised in case pipeflow did not converge. - """ - pass diff --git a/pandapipes/test/pipeflow_internals/test_inservice.py b/pandapipes/test/pipeflow_internals/test_inservice.py index 54acfaf78..f7521d0db 100644 --- a/pandapipes/test/pipeflow_internals/test_inservice.py +++ b/pandapipes/test/pipeflow_internals/test_inservice.py @@ -126,7 +126,7 @@ def create_mixed_indexing_grid(): @pytest.fixture -def create_net_wo_external_hydraulic_grid(): +def create_net_wo_ext_grid(): net = pandapipes.create_empty_network("net", add_stdtypes=False) pandapipes.create_fluid_from_lib(net, "hgas", overwrite=True) pandapipes.create_junction(net, index=3, pn_bar=16, tfluid_k=283, height_m=0, @@ -144,7 +144,6 @@ def create_net_wo_external_hydraulic_grid(): pandapipes.create_source(net, junction=10, mdot_kg_per_s=0.04, name="Source 3") pandapipes.create_compressor(net, from_junction=9, to_junction=3, pressure_ratio=1.1, name="Compressor 0", index=None, in_service=True) - pandapipes.create_ext_grid(net, junction=3, t_k=300) return net @@ -606,15 +605,27 @@ def test_mixed_indexing_oos6(create_mixed_indexing_grid, use_numba): @pytest.mark.parametrize("use_numba", [True, False]) -def test_pipeflow_cancellation(create_net_wo_external_hydraulic_grid, use_numba): - net = create_net_wo_external_hydraulic_grid - pandapipes.pipeflow(net) - assert np.all(np.isnan(net.res_junction)) - assert np.all(np.isnan(net.res_pipe)) - assert np.all(np.isnan(net.res_ext_grid)) - assert np.all(np.isnan(net.res_sink)) - assert np.all(np.isnan(net.res_source)) - assert np.all(np.isnan(net.res_compressor)) +def test_pipeflow_all_oos(create_net_wo_ext_grid, use_numba): + net = create_net_wo_ext_grid + ex1 = pandapipes.create_ext_grid(net, junction=3, t_k=300) + ex2 = pandapipes.create_ext_grid(net, junction=3, p_bar=1) + with pytest.raises(PipeflowNotConverged): + net.ext_grid.at[ex2, 'in_service'] = False + pandapipes.pipeflow(net, iter=100, tol_p=1e-7, tol_v=1e-7, friction_model="nikuradse", + use_numba=use_numba, check_connectivity=True) + assert ~net.converged + net.ext_grid.at[ex1, 'in_service'] = False + net.ext_grid.at[ex2, 'in_service'] = True + + pandapipes.pipeflow(net, iter=100, tol_p=1e-7, tol_v=1e-7, friction_model="nikuradse", + use_numba=use_numba, check_connectivity=True) + assert not np.all(np.isnan(net.res_junction.p_bar.values)) + assert net.converged + + with pytest.raises(PipeflowNotConverged): + pandapipes.pipeflow(net, mode='all', iter=100, tol_p=1e-7, tol_v=1e-7, friction_model="nikuradse", + use_numba=use_numba, check_connectivity=True) + assert ~net.converged if __name__ == "__main__": diff --git a/pandapipes/timeseries/run_time_series.py b/pandapipes/timeseries/run_time_series.py index beab805e1..590608df4 100644 --- a/pandapipes/timeseries/run_time_series.py +++ b/pandapipes/timeseries/run_time_series.py @@ -5,20 +5,19 @@ import tempfile from pandapower.control import NetCalculationNotConverged - -from pandapipes.pipeflow import PipeflowNotConverged, pipeflow from pandapower.control.util.diagnostic import control_diagnostic from pandapower.timeseries.output_writer import OutputWriter -from pandapower.timeseries.run_time_series import init_time_series as init_time_series_pp, cleanup,\ +from pandapower.timeseries.run_time_series import init_time_series as init_time_series_pp, cleanup, \ run_loop +from pandapipes.pipeflow import PipeflowNotConverged, pipeflow + try: import pandaplan.core.pplog as logging except ImportError: import logging logger = logging.getLogger(__name__) -logger.setLevel(level=logging.WARNING) def init_default_outputwriter(net, time_steps, **kwargs):