@@ -31,7 +31,7 @@
Loading
31 31
        polys.append(RegularPolygon(centroid_tri1, numVertices=3, radius=size, orientation=-angle,
32 32
                                    ec=col, fc=face_col, lw=lw))
33 33
        polys.append(RegularPolygon(centroid_tri2, numVertices=3, radius=size,
34 -
                                    orientation=-angle+np.pi/3, ec=col, fc=face_col, lw=lw))
34 +
                                    orientation=-angle + np.pi / 3, ec=col, fc=face_col, lw=lw))
35 35
        lines.append([p1, p1 + diff / 2 - vec_size / 2 * 3])
36 36
        lines.append([p2, p1 + diff / 2 + vec_size / 2 * 3])
37 37
    return lines, polys, {"filled"}
@@ -45,16 +45,16 @@
Loading
45 45
    for geodata, col in zip(coords, colors):
46 46
        p1, p2 = np.array(geodata[0]), np.array(geodata[-1])
47 47
        diff = p2 - p1
48 -
        m = 3*size/4
49 -
        direc= diff/np.sqrt(diff[0]**2+diff[1]**2)
48 +
        m = 3 * size / 4
49 +
        direc = diff / np.sqrt(diff[0] ** 2 + diff[1] ** 2)
50 50
        normal = np.array([-direc[1], direc[0]])
51 -
        path1 = (p1 + diff / 2+ direc *m/2) + normal * (size * 9 / 8)
52 -
        path2 = p1 + diff / 2 + direc *m / 2
51 +
        path1 = (p1 + diff / 2 + direc * m / 2) + normal * (size * 9 / 8)
52 +
        path2 = p1 + diff / 2 + direc * m / 2
53 53
        path3 = p1 + diff / 2 + normal * size / 3
54 -
        path4 = p1 + diff / 2 - direc *m/2
55 -
        path5 = (p1 + diff / 2- direc *m/2)  + normal * (size * 9 / 8)
56 -
        path =[path1, path2, path3, path4, path5]
57 -
        radius = size #np.sqrt(diff[0]**2+diff[1]**2)/15
54 +
        path4 = p1 + diff / 2 - direc * m / 2
55 +
        path5 = (p1 + diff / 2 - direc * m / 2) + normal * (size * 9 / 8)
56 +
        path = [path1, path2, path3, path4, path5]
57 +
        radius = size  # np.sqrt(diff[0]**2+diff[1]**2)/15
58 58
59 59
        pa = Path(path)
60 60
        polys.append(Circle(p1 + diff / 2, radius=radius, edgecolor=col, facecolor="w", lw=lw))
@@ -111,15 +111,43 @@
Loading
111 111
        diff = p2 - p1
112 112
        angle = np.arctan2(*diff)
113 113
        vec_size = _rotate_dim2(np.array([0, size]), angle)
114 -
        line1 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle - np.pi/4)
115 -
        line2 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle + np.pi/4)
114 +
        line1 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle - np.pi / 4)
115 +
        line2 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle + np.pi / 4)
116 116
        radius = size
117 117
118 118
        polys.append(Circle(p1 + diff / 2, radius=radius, edgecolor=col, facecolor='w', lw=lw))
119 119
120 -
        lines.append([p1+diff/2+vec_size, p1+diff/2-vec_size+line1])
121 -
        lines.append([p1+diff/2+vec_size, p1+diff/2-vec_size+line2])
120 +
        lines.append([p1 + diff / 2 + vec_size, p1 + diff / 2 - vec_size + line1])
121 +
        lines.append([p1 + diff / 2 + vec_size, p1 + diff / 2 - vec_size + line2])
122 122
123 123
        lines.append([p1, p1 + diff / 2 - vec_size])
124 124
        lines.append([p2, p1 + diff / 2 + vec_size])
125 125
    return lines, polys, {}
126 +
127 +
128 +
def pressure_control_patches(coords, size, **kwargs):
129 +
    polys, lines = list(), list()
130 +
    edgecolor = kwargs.pop('patch_edgecolor')
131 +
    colors = get_color_list(edgecolor, len(coords))
132 +
    lw = kwargs.get("linewidths", 2.)
133 +
    for geodata, col in zip(coords, colors):
134 +
        p1, p2 = np.array(geodata[0]), np.array(geodata[-1])
135 +
        diff = p2 - p1
136 +
        angle = np.arctan2(*diff)
137 +
        vec_size = _rotate_dim2(np.array([0, size]), angle)
138 +
        vec_size_or = _rotate_dim2(np.array([0, size * 1.2 / 2]), angle + np.pi / 2)
139 +
        pll = p1 + diff / 2 - vec_size + vec_size_or
140 +
        plr = p1 + diff / 2 - vec_size - vec_size_or
141 +
        pul = p1 + diff / 2 + vec_size + vec_size_or/3
142 +
        pur = p1 + diff / 2 + vec_size - vec_size_or/3
143 +
144 +
        polys.append(Rectangle(pll, 2 * size, size * 1.2, angle=np.rad2deg(-angle + np.pi/2),
145 +
                               edgecolor=col, facecolor='w', lw=lw))
146 +
147 +
        lines.append([p1, p1 + diff / 2 - vec_size])
148 +
        lines.append([p2, p1 + diff / 2 + vec_size])
149 +
150 +
        lines.append([pll, pul])
151 +
        lines.append([plr, pur])
152 +
153 +
    return lines, polys, {}

@@ -198,15 +198,15 @@
Loading
198 198
    :return:
199 199
    :rtype:
200 200
    """
201 -
    if not 'std_type' in net:
201 +
    if 'std_type' not in net:
202 202
        net.update({'std_type': {std_type_category: {component_name: component_object}}})
203 -
    elif not std_type_category in net.std_type:
203 +
    elif std_type_category not in net.std_type:
204 204
        std_types = net.std_type
205 205
        std_types.update({std_type_category: {component_name: component_object}})
206 206
        net.std_type = std_types
207 207
    elif not overwrite and component_name in net['std_type'][std_type_category]:
208 208
        raise (ValueError(
209 -
            '%s is already in net.std_type["%s"]. Set overwrite = True if you want to change values!'
209 +
            '%s is already in net.std_type["%s"]. Set overwrite=True if you want to change values!'
210 210
            % (component_name, std_type_category)))
211 211
    else:
212 212
        std_types = net.std_type[std_type_category]

@@ -8,8 +8,8 @@
Loading
8 8
    _create_node_element_collection, _create_line2d_collection, _create_complex_branch_collection, \
9 9
    add_cmap_to_collection, coords_from_node_geodata
10 10
from pandapower.plotting.patch_makers import load_patches, ext_grid_patches
11 -
from pandapipes.plotting.patch_makers import valve_patches, source_patches, heat_exchanger_patches,\
12 -
    pump_patches
11 +
from pandapipes.plotting.patch_makers import valve_patches, source_patches, heat_exchanger_patches, \
12 +
    pump_patches, pressure_control_patches
13 13
from pandapower.plotting.plotting_toolbox import get_index_array
14 14
15 15
try:
@@ -490,3 +490,59 @@
Loading
490 490
        patch_edgecolor=patch_edgecolor, line_color=line_color, **kwargs)
491 491
492 492
    return lc, pc
493 +
494 +
495 +
def create_pressure_control_collection(net, pcs=None, table_name='press_control',
496 +
                                       size=5., junction_geodata=None,
497 +
                                       color='k', infofunc=None, picker=False, **kwargs):
498 +
    """
499 +
    Creates a matplotlib patch collection of pandapipes junction-junction valves. Valves are
500 +
    plotted in the center between two junctions with a "helper" line (dashed and thin) being drawn
501 +
    between the junctions as well.
502 +
503 +
    :param net: The pandapipes network
504 +
    :type net: pandapipesNet
505 +
    :param valves: The valves for which the collections are created. If None, all valves which have\
506 +
        entries in the respective junction geodata will be plotted.
507 +
    :type valves: list, default None
508 +
    :param size: Patch size
509 +
    :type size: float, default 5.
510 +
    :param junction_geodata: Coordinates to use for plotting. If None, net["junction_geodata"] is used.
511 +
    :type junction_geodata: pandas.DataFrame, default None
512 +
    :param colors: Color or list of colors for every valve
513 +
    :type colors: iterable, float, default None
514 +
    :param infofunc: infofunction for the patch element
515 +
    :type infofunc: function, default None
516 +
    :param picker: Picker argument passed to the patch collection
517 +
    :type picker: bool, default False
518 +
    :param fill_closed: If True, valves with parameter opened == False will be filled and those\
519 +
        with opened == True will have a white facecolor. Vice versa if False.
520 +
    :type fill_closed: bool, default True
521 +
    :param kwargs: Keyword arguments are passed to the patch function
522 +
    :return: lc - line collection, pc - patch collection
523 +
524 +
    """
525 +
    pcs = get_index_array(pcs, net[table_name].index)
526 +
    pc_table = net[table_name].loc[pcs]
527 +
528 +
    coords, pcs_with_geo = coords_from_node_geodata(
529 +
        pcs, pc_table.from_junction.values, pc_table.to_junction.values,
530 +
        junction_geodata if junction_geodata is not None else net["junction_geodata"], table_name,
531 +
        "Junction")
532 +
533 +
    if len(pcs_with_geo) == 0:
534 +
        return None
535 +
536 +
    linewidths = kwargs.pop("linewidths", 2.)
537 +
    linewidths = kwargs.pop("linewidth", linewidths)
538 +
    linewidths = kwargs.pop("lw", linewidths)
539 +
540 +
    infos = list(np.repeat([infofunc(i) for i in range(len(pcs_with_geo))], 2)) \
541 +
        if infofunc is not None else []
542 +
    lc, pc = _create_complex_branch_collection(coords, pressure_control_patches, size, infos,
543 +
                                               picker=picker, linewidths=linewidths,
544 +
                                               patch_edgecolor=color, line_color=color,
545 +
                                               **kwargs)
546 +
547 +
    return lc, pc
548 +

@@ -6,6 +6,7 @@
Loading
6 6
P = 1  # Reference node, pressure is fixed
7 7
L = 2  # All other nodes
8 8
T = 10  # Reference node with fixed temperature, otherwise 0
9 +
PC = 20  # Controlled node with fixed pressure p
9 10
NONE = 3  # None
10 11
11 12
# define the indices

@@ -6,8 +6,8 @@
Loading
6 6
7 7
from pandapipes.plotting.plotting_toolbox import get_collection_sizes
8 8
from pandapipes.plotting.collections import create_junction_collection, create_pipe_collection, \
9 -
     create_valve_collection, create_source_collection, \
10 -
     create_heat_exchanger_collection, create_sink_collection, create_pump_collection
9 +
    create_valve_collection, create_source_collection, create_pressure_control_collection, \
10 +
    create_heat_exchanger_collection, create_sink_collection, create_pump_collection
11 11
from pandapipes.plotting.generic_geodata import create_generic_coordinates
12 12
from pandapower.plotting import draw_collections
13 13
from itertools import chain
@@ -23,9 +23,11 @@
Loading
23 23
def simple_plot(net, respect_valves=False, respect_in_service=True, pipe_width=2.0,
24 24
                junction_size=1.0, ext_grid_size=1.0, plot_sinks=False, plot_sources=False,
25 25
                sink_size=1.0, source_size=1.0, valve_size=1.0, pump_size=1.0,
26 -
                heat_exchanger_size=1.0, scale_size=True, junction_color="r", pipe_color='silver',
27 -
                ext_grid_color='orange', valve_color='silver', pump_color='silver',
28 -
                heat_exchanger_color='silver', library="igraph", show_plot=True, ax=None, **kwargs):
26 +
                heat_exchanger_size=1.0, pressure_control_size=1.0, scale_size=True,
27 +
                junction_color="r", pipe_color='silver', ext_grid_color='orange',
28 +
                valve_color='silver', pump_color='silver', heat_exchanger_color='silver',
29 +
                pressure_control_color='silver', library="igraph", show_plot=True, ax=None,
30 +
                **kwargs):
29 31
    """
30 32
    Plots a pandapipes network as simple as possible. If no geodata is available, artificial
31 33
    geodata is generated. For advanced plotting see
@@ -61,6 +63,8 @@
Loading
61 63
    :type pump_size: float, default 1.0
62 64
    :param heat_exchanger_size: Relative size of heat_exchanger to plot.
63 65
    :type heat_exchanger_size: float, default 1.0
66 +
    :param pressure_control_size: Relative size of pres_control to plot.
67 +
    :type pressure_control_size: float, default 1.0
64 68
    :param scale_size: Flag if junction_size, ext_grid_size, valve_size- and distance will be \
65 69
            scaled with respect to grid mean distances
66 70
    :type scale_size: bool, default True
@@ -77,6 +81,8 @@
Loading
77 81
    :type pump_color: str, tuple, default "silver"
78 82
    :param heat_exchanger_color: Heat Exchanger Color.
79 83
    :type heat_exchanger_color: str, tuple, default "silver"
84 +
    :param pressure_control_color: Pressure Control Color.
85 +
    :type pressure_control_color: str, tuple, default "silver"
80 86
    :param library: Library name to create generic coordinates (case of missing geodata). Choose\
81 87
            "igraph" to use igraph package or "networkx" to use networkx package.
82 88
    :type library: str, default "igraph"
@@ -90,8 +96,9 @@
Loading
90 96
    collections = create_simple_collections(
91 97
        net, respect_valves, respect_in_service, pipe_width, junction_size, ext_grid_size,
92 98
        plot_sinks, plot_sources, sink_size, source_size, valve_size, pump_size,
93 -
        heat_exchanger_size, scale_size, junction_color, pipe_color, ext_grid_color, valve_color,
94 -
        pump_color, heat_exchanger_color, library, as_dict=False, **kwargs)
99 +
        heat_exchanger_size, pressure_control_size, scale_size, junction_color, pipe_color,
100 +
        ext_grid_color, valve_color, pump_color, heat_exchanger_color, pressure_control_color,
101 +
        library, as_dict=False, **kwargs)
95 102
    ax = draw_collections(collections, ax=ax)
96 103
97 104
    if show_plot:
@@ -102,11 +109,11 @@
Loading
102 109
def create_simple_collections(net, respect_valves=False, respect_in_service=True, pipe_width=5.0,
103 110
                              junction_size=1.0, ext_grid_size=1.0, plot_sinks=False,
104 111
                              plot_sources=False, sink_size=1.0, source_size=1.0, valve_size=1.0,
105 -
                              pump_size=1.0, heat_exchanger_size=1.0, scale_size=True,
106 -
                              junction_color="r", pipe_color='silver', ext_grid_color='orange',
107 -
                              valve_color='silver', pump_color='silver',
108 -
                              heat_exchanger_color='silver', library="igraph", as_dict=True,
109 -
                              **kwargs):
112 +
                              pump_size=1.0, heat_exchanger_size=1.0, pressure_control_size=1.0,
113 +
                              scale_size=True, junction_color="r", pipe_color='silver',
114 +
                              ext_grid_color='orange', valve_color='silver', pump_color='silver',
115 +
                              heat_exchanger_color='silver', pressure_control_color='silver',
116 +
                              library="igraph", as_dict=True, **kwargs):
110 117
    """
111 118
    Plots a pandapipes network as simple as possible.
112 119
    If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial
@@ -141,8 +148,10 @@
Loading
141 148
    :type valve_size: float, default 1.0
142 149
    :param pump_size: Relative size of pumps to plot.
143 150
    :type pump_size: float, default 1.0
144 -
    :param heat_exchanger_size:
145 -
    :type heat_exchanger_size:
151 +
    :param heat_exchanger_size: Relative size of heat_exchanger to plot.
152 +
    :type heat_exchanger_size: float, default 1.0
153 +
    :param pressure_control_size: Relative size of pres_control to plot.
154 +
    :type pressure_control_size: float, default 1.0
146 155
    :param scale_size: Flag if junction_size, ext_grid_size, valve_size- and distance will be \
147 156
            scaled with respect to grid mean distances
148 157
    :type scale_size: bool, default True
@@ -159,6 +168,8 @@
Loading
159 168
    :type pump_color: str, tuple, default "silver"
160 169
    :param heat_exchanger_color: Heat Exchanger Color.
161 170
    :type heat_exchanger_color: str, tuple, default "silver"
171 +
    :param pressure_control_color: Pressure Control Color.
172 +
    :type pressure_control_color: str, tuple, default "silver"
162 173
    :param library: library name to create generic coordinates (case of missing geodata). Choose\
163 174
            "igraph" to use igraph package or "networkx" to use networkx package. **NOTE**: \
164 175
            Currently the networkx implementation is not working!
@@ -177,8 +188,9 @@
Loading
177 188
178 189
    if scale_size:
179 190
        # if scale_size -> calc size from distance between min and max geocoord
180 -
        sizes = get_collection_sizes(net, junction_size, ext_grid_size, sink_size, source_size,
181 -
                                     valve_size, pump_size, heat_exchanger_size)
191 +
        sizes = get_collection_sizes(
192 +
            net, junction_size, ext_grid_size, sink_size, source_size, valve_size, pump_size,
193 +
            heat_exchanger_size, pressure_control_size)
182 194
        junction_size = sizes["junction"]
183 195
        ext_grid_size = sizes["ext_grid"]
184 196
        source_size = sizes["source"]
@@ -186,6 +198,7 @@
Loading
186 198
        valve_size = sizes["valve"]
187 199
        pump_size = sizes["pump"]
188 200
        heat_exchanger_size = sizes["heat_exchanger"]
201 +
        pressure_control_size = sizes["pressure_control"]
189 202
190 203
    # create junction collections to plot
191 204
    if respect_in_service:
@@ -296,6 +309,17 @@
Loading
296 309
                net, size=heat_exchanger_size, linewidths=pipe_width, color=heat_exchanger_color)
297 310
        collections["heat_exchanger"] = hxc
298 311
312 +
    if 'press_control' in net:
313 +
        if respect_in_service:
314 +
            pc = create_pressure_control_collection(
315 +
                net, pcs=net.press_control[net.press_control.in_service].index,
316 +
                size=pressure_control_size, linewidths=pipe_width, color=pressure_control_color)
317 +
        else:
318 +
            pc = create_pressure_control_collection(
319 +
                net, size=pressure_control_size, linewidths=pipe_width,
320 +
                color=pressure_control_color)
321 +
        collections["press_control"] = pc
322 +
299 323
    if 'additional_collections' in kwargs:
300 324
        collections["additional"] = list()
301 325
        for collection in kwargs.pop('additional_collections'):

@@ -11,7 +11,7 @@
Loading
11 11
from pandapipes.idx_branch import FROM_NODE, TO_NODE, FROM_NODE_T, TO_NODE_T, VINIT, branch_cols, \
12 12
    ACTIVE as ACTIVE_BR
13 13
from pandapipes.idx_node import NODE_TYPE, P, PINIT, NODE_TYPE_T, T, node_cols, \
14 -
    ACTIVE as ACTIVE_ND, TABLE_IDX as TABLE_IDX_ND, ELEMENT_IDX as ELEMENT_IDX_ND
14 +
    ACTIVE as ACTIVE_ND, TABLE_IDX as TABLE_IDX_ND, ELEMENT_IDX as ELEMENT_IDX_ND, PC
15 15
from pandapipes.properties.fluids import get_fluid
16 16
17 17
try:
@@ -320,7 +320,7 @@
Loading
320 320
321 321
322 322
def initialize_pit(net, node_name, NodeComponent, NodeElementComponent, BranchComponent,
323 -
                   BranchWInternalsComponent):
323 +
                   BranchWInternalsComponent, PressureControlComponent):
324 324
    """
325 325
    Initializes and fills the internal structure which is called pit (pandapipes internal tables).
326 326
    The structure is a dictionary which should contain one array for all nodes and one array for all
@@ -337,7 +337,8 @@
Loading
337 337
    for comp in net['component_list']:
338 338
        if issubclass(comp, NodeComponent) | \
339 339
                issubclass(comp, BranchWInternalsComponent) | \
340 -
                issubclass(comp, NodeElementComponent):
340 +
                issubclass(comp, NodeElementComponent) | \
341 +
                (comp==PressureControlComponent):
341 342
            comp.create_pit_node_entries(net, pit["node"], node_name)
342 343
        if issubclass(comp, BranchComponent):
343 344
            comp.create_pit_branch_entries(net, pit["branch"], node_name)
@@ -465,7 +466,8 @@
Loading
465 466
    active_node_lookup = node_pit[:, ACTIVE_ND].astype(np.bool)
466 467
    from_nodes = branch_pit[:, FROM_NODE].astype(np.int32)
467 468
    to_nodes = branch_pit[:, TO_NODE].astype(np.int32)
468 -
    hyd_slacks = np.where(node_pit[:, NODE_TYPE] == P & active_node_lookup)[0]
469 +
    hyd_slacks = np.where(((node_pit[:, NODE_TYPE] == P) | (node_pit[:, NODE_TYPE] == PC))
470 +
                          & active_node_lookup)[0]
469 471
470 472
    nodes_connected, branches_connected = perform_connectivity_search(
471 473
        net, node_pit, hyd_slacks, from_nodes, to_nodes, active_node_lookup, active_branch_lookup,

@@ -441,39 +441,39 @@
Loading
441 441
    return Fluid(name=name, fluid_type=fluid_type, **properties)
442 442
443 443
444 -
def call_lib(fluid):
444 +
def call_lib(fluid_name):
445 445
    """
446 446
    Creates a fluid with default fluid properties.
447 447
448 -
    :param fluid: Fluid which should be used
449 -
    :type fluid: str
448 +
    :param fluid_name: Fluid which should be used
449 +
    :type fluid_name: str
450 450
    :return: Fluid - Chosen fluid with default fluid properties
451 451
    :rtype: Fluid
452 452
    """
453 453
454 454
    def interextra_property(prop):
455 455
        return FluidPropertyInterExtra.from_path(
456 -
            os.path.join(pp_dir, "properties", fluid, prop + ".txt"))
456 +
            os.path.join(pp_dir, "properties", fluid_name, prop + ".txt"))
457 457
458 458
    def constant_property(prop):
459 459
        return FluidPropertyConstant.from_path(
460 -
            os.path.join(pp_dir, "properties", fluid, prop + ".txt"))
460 +
            os.path.join(pp_dir, "properties", fluid_name, prop + ".txt"))
461 461
462 462
    def linear_property(prop):
463 463
        return FluidPropertyLinear.from_path(
464 -
            os.path.join(pp_dir, "properties", fluid, prop + ".txt"))
464 +
            os.path.join(pp_dir, "properties", fluid_name, prop + ".txt"))
465 465
466 466
    liquids = ["water"]
467 467
    gases = ["air", "lgas", "hgas", "hydrogen", "methane"]
468 468
469 -
    if fluid == "natural_gas":
469 +
    if fluid_name == "natural_gas":
470 470
        logger.error("'natural_gas' is ambigious. Please choose 'hgas' or 'lgas' "
471 471
                     "(high- or low calorific natural gas)")
472 -
    if fluid not in liquids and fluid not in gases:
472 +
    if fluid_name not in liquids and fluid_name not in gases:
473 473
        raise AttributeError("Fluid '%s' not found in the fluid library. It might not be "
474 -
                             "implemented yet." % fluid)
474 +
                             "implemented yet." % fluid_name)
475 475
476 -
    phase = "liquid" if fluid in liquids else "gas"
476 +
    phase = "liquid" if fluid_name in liquids else "gas"
477 477
478 478
    density = interextra_property("density")
479 479
    viscosity = interextra_property("viscosity")
@@ -482,15 +482,15 @@
Loading
482 482
    der_compr = constant_property("der_compressibility")
483 483
    compr = linear_property("compressibility")
484 484
485 -
    if (phase == 'gas') & (fluid != 'air'):
485 +
    if (phase == 'gas') & (fluid_name != 'air'):
486 486
        lhv = constant_property("lower_heating_value")
487 487
        hhv = constant_property("higher_heating_value")
488 488
489 -
        return Fluid(fluid, phase, density=density, viscosity=viscosity,
489 +
        return Fluid(fluid_name, phase, density=density, viscosity=viscosity,
490 490
                     heat_capacity=heat_capacity, molar_mass=molar_mass,
491 491
                     compressibility=compr, der_compressibility=der_compr, lhv=lhv, hhv=hhv)
492 492
    else:
493 -
        return Fluid(fluid, phase, density=density, viscosity=viscosity,
493 +
        return Fluid(fluid_name, phase, density=density, viscosity=viscosity,
494 494
                     heat_capacity=heat_capacity, molar_mass=molar_mass, compressibility=compr,
495 495
                     der_compressibility=der_compr)
496 496

@@ -5,12 +5,12 @@
Loading
5 5
import numpy as np
6 6
from pandapipes.idx_branch import FROM_NODE, TO_NODE, JAC_DERIV_DV, JAC_DERIV_DP, JAC_DERIV_DP1, \
7 7
    JAC_DERIV_DV_NODE, LOAD_VEC_NODES, LOAD_VEC_BRANCHES, JAC_DERIV_DT, JAC_DERIV_DT1, \
8 -
    JAC_DERIV_DT_NODE, LOAD_VEC_NODES_T, LOAD_VEC_BRANCHES_T, FROM_NODE_T, TO_NODE_T
8 +
    JAC_DERIV_DT_NODE, LOAD_VEC_NODES_T, LOAD_VEC_BRANCHES_T, FROM_NODE_T, TO_NODE_T, BRANCH_TYPE
9 9
from pandapipes.idx_node import LOAD, TINIT
10 -
from pandapipes.idx_node import P, NODE_TYPE, T, NODE_TYPE_T
10 +
from pandapipes.idx_node import P, PC, NODE_TYPE, T, NODE_TYPE_T
11 11
from pandapipes.internals_toolbox import _sum_by_group_sorted, _sum_by_group
12 -
from scipy.sparse import csr_matrix
13 12
from pandapipes.pipeflow_setup import get_net_option
13 +
from scipy.sparse import csr_matrix
14 14
15 15
16 16
def build_system_matrix(net, branch_pit, node_pit, heat_mode):
@@ -35,21 +35,25 @@
Loading
35 35
    len_b = len(branch_pit)
36 36
    len_n = len(node_pit)
37 37
    branch_matrix_indices = np.arange(len_b) + len_n
38 -
    fn_col, tn_col, ntyp_col, slack_type, num_der = (FROM_NODE, TO_NODE, NODE_TYPE, P, 3) \
39 -
        if not heat_mode else (FROM_NODE_T, TO_NODE_T, NODE_TYPE_T, T, 2)
40 -
38 +
    fn_col, tn_col, ntyp_col, slack_type, pc_type, num_der = \
39 +
        (FROM_NODE, TO_NODE, NODE_TYPE, P, PC, 3) \
40 +
        if not heat_mode else (FROM_NODE_T, TO_NODE_T, NODE_TYPE_T, T, PC, 2)
41 +
    pc_nodes = np.where(node_pit[:, ntyp_col] == pc_type)[0]
41 42
    fn = branch_pit[:, fn_col].astype(np.int32)
42 43
    tn = branch_pit[:, tn_col].astype(np.int32)
43 44
    not_slack_fn_branch_mask = node_pit[fn, ntyp_col] != slack_type
44 45
    not_slack_tn_branch_mask = node_pit[tn, ntyp_col] != slack_type
46 +
    pc_branch_mask = branch_pit[:, BRANCH_TYPE] == pc_type
45 47
    slack_nodes = np.where(node_pit[:, ntyp_col] == slack_type)[0]
48 +
    pc_matrix_indices = branch_matrix_indices[pc_branch_mask]
46 49
47 50
    if not heat_mode:
48 51
        len_fn_not_slack = np.sum(not_slack_fn_branch_mask)
49 52
        len_tn_not_slack = np.sum(not_slack_tn_branch_mask)
50 53
        len_fn1 = num_der * len_b + len_fn_not_slack
51 54
        len_tn1 = len_fn1 + len_tn_not_slack
52 -
        full_len = len_tn1 + slack_nodes.shape[0]
55 +
        len_pc = len_tn1 + pc_nodes.shape[0]
56 +
        full_len = len_pc + slack_nodes.shape[0]
53 57
    else:
54 58
        inc_flow_sum = np.zeros(len(node_pit[:, LOAD]))
55 59
        tn_unique_der, tn_sums_der = _sum_by_group(tn, branch_pit[:, JAC_DERIV_DT_NODE])
@@ -72,7 +76,7 @@
Loading
72 76
        # jdF_dv_to_nodes
73 77
        system_data[len_fn1:len_tn1] = branch_pit[not_slack_tn_branch_mask,
74 78
                                                  JAC_DERIV_DV_NODE] * (-1)
75 -
        # p_nodes
79 +
        # pc_nodes and p_nodes
76 80
        system_data[len_tn1:] = 1
77 81
    else:
78 82
        system_data[:len_b] = branch_pit[:, JAC_DERIV_DT]
@@ -113,9 +117,13 @@
Loading
113 117
            system_cols[len_fn1:len_tn1] = branch_matrix_indices[not_slack_tn_branch_mask]
114 118
            system_rows[len_fn1:len_tn1] = tn[not_slack_tn_branch_mask]
115 119
120 +
            # pc_nodes
121 +
            system_cols[len_tn1:len_pc] = pc_nodes
122 +
            system_rows[len_tn1:len_pc] = pc_matrix_indices
123 +
116 124
            # p_nodes
117 -
            system_cols[len_tn1:] = slack_nodes
118 -
            system_rows[len_tn1:] = slack_nodes
125 +
            system_cols[len_pc:] = slack_nodes
126 +
            system_rows[len_pc:] = slack_nodes
119 127
        else:
120 128
            # pdF_dTfromnode
121 129
            system_cols[:len_b] = fn
@@ -145,8 +153,6 @@
Loading
145 153
            system_matrix = csr_matrix((system_data, (system_rows, system_cols)),
146 154
                                       shape=(len_n + len_b, len_n + len_b))
147 155
148 -
149 -
150 156
        else:
151 157
            data_order = np.lexsort([system_cols, system_rows])
152 158
            system_data = system_data[data_order]
@@ -176,6 +182,7 @@
Loading
176 182
        load_vector[fn_unique] -= fn_sums
177 183
        load_vector[tn_unique] += tn_sums
178 184
        load_vector[slack_nodes] = 0
185 +
        load_vector[pc_matrix_indices] = 0
179 186
    else:
180 187
        tn_unique, tn_sums = _sum_by_group(tn, branch_pit[:, LOAD_VEC_NODES_T])
181 188
        load_vector = np.zeros(len_n + len_b)

@@ -96,6 +96,7 @@
Loading
96 96
    :return: set of tuples with element names and column names
97 97
    :rtype: set
98 98
    """
99 +
    special_elements_junctions = [("press_control", "controlled_junction")]
99 100
    node_elements = []
100 101
    if net is not None and include_node_elements:
101 102
        node_elements = [comp.table_name() for comp in net.component_list
@@ -108,7 +109,7 @@
Loading
108 109
                           if issubclass(comp, BranchComponent)]
109 110
    elif include_branch_elements:
110 111
        branch_elements = ["pipe", "valve", "pump", "circ_pump_mass", "circ_pump_pressure",
111 -
                           "heat_exchanger"]
112 +
                           "heat_exchanger", "press_control"]
112 113
    ejts = set()
113 114
    if include_node_elements:
114 115
        for elm in node_elements:
@@ -124,6 +125,8 @@
Loading
124 125
            elements_without_res = ["valve"]
125 126
        ejts.update(
126 127
            [("res_" + ejt[0], ejt[1]) for ejt in ejts if ejt[0] not in elements_without_res])
128 +
    ejts.update((el, jn) for el, jn in special_elements_junctions if el in node_elements
129 +
                or el in branch_elements)
127 130
    return ejts
128 131
129 132

@@ -3,7 +3,7 @@
Loading
3 3
# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4 4
5 5
def get_collection_sizes(net, junction_size=1.0, ext_grid_size=1.0, sink_size=1.0, source_size=1.0,
6 -
                         valve_size=2.0, pump_size=1.0, heat_exchanger_size=1.0):
6 +
                         valve_size=2.0, pump_size=1.0, heat_exchanger_size=1.0, pressure_control_size=1.0):
7 7
    """
8 8
    Calculates the size for most collection types according to the distance between min and max
9 9
    geocoord so that the collections fit the plot nicely
@@ -37,7 +37,9 @@
Loading
37 37
        "sink": sink_size * mean_distance_between_junctions * 2,
38 38
        "source": source_size * mean_distance_between_junctions * 2,
39 39
        "heat_exchanger": heat_exchanger_size * mean_distance_between_junctions * 8,
40 -
        "pump": pump_size * mean_distance_between_junctions * 8
40 +
        "pump": pump_size * mean_distance_between_junctions * 8,
41 +
        "pressure_control": pressure_control_size * mean_distance_between_junctions * 8,
42 +
41 43
    }
42 44
    return sizes
43 45

@@ -101,8 +101,8 @@
Loading
101 101
102 102
        :param net: The pandapipes network
103 103
        :type net: pandapipesNet
104 -
        :param branch_component_pit:
105 -
        :type branch_component_pit:
104 +
        :param branch_pit:
105 +
        :type branch_pit:
106 106
        :param node_pit:
107 107
        :type node_pit:
108 108
        :param idx_lookups:
@@ -204,6 +204,7 @@
Loading
204 204
        mass_flow_dv = rho * branch_component_pit[:, AREA]
205 205
        branch_component_pit[:, JAC_DERIV_DV_NODE] = mass_flow_dv
206 206
        branch_component_pit[:, LOAD_VEC_NODES] = mass_flow_dv * v_init
207 +
        return branch_component_pit
207 208
208 209
    @classmethod
209 210
    def calculate_derivatives_thermal(cls, net, branch_pit, node_pit, idx_lookups, options):

@@ -0,0 +1,193 @@
Loading
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

@@ -15,6 +15,10 @@
Loading
15 15
    init_options, create_internal_results, write_internal_results, extract_all_results, \
16 16
    get_lookup, create_lookups, initialize_pit, check_connectivity, reduce_pit, \
17 17
    extract_results_active_pit, set_user_pf_options
18 +
from scipy.sparse.linalg import spsolve
19 +
from pandapipes.component_models import Junction, PressureControlComponent
20 +
from pandapipes.component_models.abstract_models import NodeComponent, NodeElementComponent, \
21 +
    BranchComponent, BranchWInternalsComponent
18 22
from pandapower.auxiliary import ppException
19 23
from scipy.sparse.linalg import spsolve
20 24
@@ -68,7 +72,8 @@
Loading
68 72
    create_lookups(net, NodeComponent, BranchComponent, BranchWInternalsComponent)
69 73
    node_pit, branch_pit = initialize_pit(net, Junction.table_name(),
70 74
                                          NodeComponent, NodeElementComponent,
71 -
                                          BranchComponent, BranchWInternalsComponent)
75 +
                                          BranchComponent, BranchWInternalsComponent,
76 +
                                          PressureControlComponent)
72 77
    if (len(node_pit) == 0) & (len(branch_pit) == 0):
73 78
        logger.warning("There are no node and branch entries defined. This might mean that your net"
74 79
                       " is empty")

@@ -5,12 +5,14 @@
Loading
5 5
import numpy as np
6 6
import pandas as pd
7 7
from pandapipes.component_models import Junction, Sink, Source, Pump, Pipe, ExtGrid, \
8 -
    HeatExchanger, Valve, CirculationPumpPressure, CirculationPumpMass
8 +
    HeatExchanger, Valve, CirculationPumpPressure, CirculationPumpMass, PressureControlComponent
9 +
from packaging import version
10 +
from pandapipes.component_models import Junction, Sink, Source, Pump, Pipe, ExtGrid, \
11 +
    HeatExchanger, Valve, CirculationPumpPressure, CirculationPumpMass, PressureControlComponent
9 12
from pandapipes.component_models.auxiliaries.component_toolbox import add_new_component
10 13
from pandapipes.pandapipes_net import pandapipesNet, get_basic_net_entries, add_default_components
11 14
from pandapipes.properties import call_lib
12 -
from pandapipes.properties.fluids import Fluid
13 -
from pandapipes.properties.fluids import _add_fluid_to_net
15 +
from pandapipes.properties.fluids import Fluid, _add_fluid_to_net
14 16
from pandapipes.std_types.std_type import PumpStdType, add_basic_std_types, add_pump_std_type, \
15 17
    load_std_type
16 18
from pandapipes.std_types.std_type_toolbox import regression_function
@@ -203,7 +205,8 @@
Loading
203 205
    return index
204 206
205 207
206 -
def create_ext_grid(net, junction, p_bar, t_k, name=None, in_service=True, index=None, type="pt"):
208 +
def create_ext_grid(net, junction, p_bar, t_k, name=None, in_service=True, index=None, type="pt",
209 +
                    **kwargs):
207 210
    """
208 211
    Creates an external grid and adds it to the table net["ext_grid"]. It transfers the junction
209 212
    that it is connected to into a node with fixed value for either pressure, temperature or both
@@ -224,6 +227,7 @@
Loading
224 227
    :type in_service: bool, default True
225 228
    :param index: Force a specified ID if it is available. If None, the index one higher than the\
226 229
            highest already existing index is selected.
230 +
    :type index: int, default None
227 231
    :param type: The external grid type denotes the values that are fixed at the respective node:\n
228 232
            - "p": The pressure is fixed, the node acts as a slack node for the mass flow.
229 233
            - "t": The temperature is fixed and will not be solved for, but is assumed as the \
@@ -231,7 +235,8 @@
Loading
231 235
                   inconsistencies in the formulation of heat transfer equations yet. \n
232 236
            - "pt": The external grid shows both "p" and "t" behavior.
233 237
    :type type: str, default "pt"
234 -
    :type index: int, default None
238 +
    :param kwargs: Additional keyword arguments will be added as further columns to the\
239 +
                    net["ext_grid"] table
235 240
    :return: index - The unique ID of the created element
236 241
    :rtype: int
237 242
@@ -737,6 +742,65 @@
Loading
737 742
    return index
738 743
739 744
745 +
def create_pressure_control(net, from_junction, to_junction, controlled_junction, controlled_p_bar,
746 +
                            control_active=True, loss_coefficient=0., name=None, index=None,
747 +
                            in_service=True, type="pressure_control", **kwargs):
748 +
    """
749 +
    Adds one pressure control with a constant mass flow in table net["press_control"].
750 +
751 +
    :param net: The net within this pump should be created
752 +
    :type net: pandapipesNet
753 +
    :param from_junction: ID of the junction on one side which the pressure control will be \
754 +
            connected with
755 +
    :type from_junction: int
756 +
    :param controlled_junction: ID of the junction at which the pressure is controlled
757 +
    :type controlled_junction: int
758 +
    :param to_junction: ID of the junction on the other side which the pressure control will be \
759 +
            connected with
760 +
    :type to_junction: int
761 +
    :param controlled_p_bar: Pressure set point
762 +
    :type controlled_p_bar: float
763 +
    :param control_active: Variable to state whether the pressure control is active (otherwise \
764 +
        behaviour similar to open valve)
765 +
    :type control_active: bool, default True
766 +
    :param loss_coefficient: The pressure loss coefficient introduced by the component's shape \
767 +
        (used only if control is not active).
768 +
    :type loss_coefficient: float, default 0
769 +
    :param name: Name of the pressure control element
770 +
    :type name: str
771 +
    :param index: Force a specified ID if it is available. If None, the index one higher than the\
772 +
            highest already existing index is selected.
773 +
    :type index: int, default None
774 +
    :param in_service: True for in_service or False for out of service
775 +
    :type in_service: bool, default True
776 +
    :param type: Currently not used - possibility to specify a certain type of pressure control
777 +
    :type type: str, default "pressure_control"
778 +
    :param kwargs: Additional keyword arguments will be added as further columns to the \
779 +
            net["press_control"] table
780 +
    :type kwargs: dict
781 +
    :return: index - The unique ID of the created element
782 +
    :rtype: int
783 +
784 +
    :Example:
785 +
        >>> create_pressure_control(net, 0, 1, 1, controlled_p_bar=5)
786 +
787 +
    """
788 +
    add_new_component(net, PressureControlComponent)
789 +
790 +
    index = _get_index_with_check(net, "press_control", index)
791 +
792 +
    # check if junctions exist to attach the pump to
793 +
    check_branch(net, "PressureControl", index, from_junction, to_junction)
794 +
795 +
    _set_entries(net, "press_control", index, name=name, from_junction=from_junction,
796 +
                 to_junction=to_junction, controlled_junction=controlled_junction,
797 +
                 control_active=bool(control_active), loss_coefficient=loss_coefficient,
798 +
                 controlled_p_bar=controlled_p_bar, in_service=bool(in_service), type=type,
799 +
                 **kwargs)
800 +
801 +
    return index
802 +
803 +
740 804
def create_junctions(net, nr_junctions, pn_bar, tfluid_k, height_m=0, name=None, index=None,
741 805
                     in_service=True, type="junction", geodata=None, **kwargs):
742 806
    """
@@ -1036,7 +1100,7 @@
Loading
1036 1100
def create_valves(net, from_junctions, to_junctions, diameter_m, opened=True, loss_coefficient=0,
1037 1101
                  name=None, index=None, type='valve', **kwargs):
1038 1102
    """
1039 -
     Convenience function for creating many pipes at once. Parameters 'from_junctions' and \
1103 +
     Convenience function for creating many valves at once. Parameters 'from_junctions' and \
1040 1104
    'to_junctions' must be arrays of equal length. Other parameters may be either arrays of the \
1041 1105
    same length or single values.
1042 1106
@@ -1084,6 +1148,65 @@
Loading
1084 1148
    return index
1085 1149
1086 1150
1151 +
def create_pressure_controls(net, from_junctions, to_junctions, controlled_junctions,
1152 +
                             controlled_p_bar, control_active=True, loss_coefficient=0., name=None,
1153 +
                             index=None, in_service=True, type="pressure_control", **kwargs):
1154 +
    """
1155 +
    Convenience function for creating many pressure controls at once. Parameters 'from_junctions'\
1156 +
    and 'to_junctions' must be arrays of equal length. Other parameters may be either arrays of the\
1157 +
    same length or single values.
1158 +
1159 +
    :param net: The net within this pump should be created
1160 +
    :type net: pandapipesNet
1161 +
    :param from_junctions: IDs of the junctions on one side which the pressure controls will be\
1162 +
            connected to
1163 +
    :type from_junctions: Iterable(int)
1164 +
    :param to_junctions: IDs of the junctions on the other side to which the pressure controls will\
1165 +
            be connected to
1166 +
    :type to_junctions: Iterable(int)
1167 +
    :param controlled_junctions: IDs of the junctions at which the pressure is controlled
1168 +
    :type controlled_junctions: Iterable or int
1169 +
    :param controlled_p_bar: Pressure set points
1170 +
    :type controlled_p_bar: Iterable or float
1171 +
    :param control_active: Variable to state whether the pressure control is active (otherwise \
1172 +
        behaviour similar to open valve)
1173 +
    :type control_active: bool, default True
1174 +
    :param loss_coefficient: The pressure loss coefficient introduced by the component's shape \
1175 +
        (used only if control is not active).
1176 +
    :type loss_coefficient: float, default 0
1177 +
    :param name: Name of the pressure control elements
1178 +
    :type name: Iterable or str
1179 +
    :param index: Force specified IDs if they are available. If None, the index one higher than the\
1180 +
            highest already existing index is selected and counted onwards.
1181 +
    :type index: Iterable(int), default None
1182 +
    :param in_service: True for in_service or False for out of service
1183 +
    :type in_service: Iterable or bool, default True
1184 +
    :param type: Currently not used - possibility to specify a certain type of pressure control
1185 +
    :type type: Iterable or str, default "pressure_control"
1186 +
    :param kwargs: Additional keyword arguments will be added as further columns to the \
1187 +
            net["press_control"] table
1188 +
    :return: index - The unique IDs of the created elements
1189 +
    :rtype: array(int)
1190 +
1191 +
    :Example:
1192 +
        >>> create_pressure_controls(net, [0, 2], [1, 4], [1, 3], controlled_p_bar=[5, 4.9])
1193 +
1194 +
    """
1195 +
    add_new_component(net, PressureControlComponent)
1196 +
1197 +
    index = _get_multiple_index_with_check(net, "press_control", index, len(from_junctions))
1198 +
    _check_branches(net, from_junctions, to_junctions, "press_control")
1199 +
1200 +
1201 +
    entries = {"name": name, "from_junction": from_junctions, "to_junction": to_junctions,
1202 +
               "controlled_junction": controlled_junctions, "controlled_p_bar": controlled_p_bar,
1203 +
               "control_active": control_active, "loss_coefficient": loss_coefficient,
1204 +
               "in_service": in_service, "type": type}
1205 +
    _set_multiple_entries(net, "press_control", index, **entries, **kwargs)
1206 +
1207 +
    return index
1208 +
1209 +
1087 1210
def create_fluid_from_lib(net, name, overwrite=True):
1088 1211
    """
1089 1212
    Creates a fluid from library (if there is an entry) and sets net["fluid"] to this value.

@@ -12,3 +12,4 @@
Loading
12 12
from pandapipes.component_models.pump_component import *
13 13
from pandapipes.component_models.circulation_pump_mass_component import *
14 14
from pandapipes.component_models.circulation_pump_pressure_component import *
15 +
from pandapipes.component_models.pressure_control_component import *

@@ -40,5 +40,6 @@
Loading
40 40
STD_TYPE = 35
41 41
PL = 36
42 42
TL = 37  # Temperature lift [K]
43 +
BRANCH_TYPE = 38 # branch type relevant for the pressure controller
43 44
44 -
branch_cols = 38
45 +
branch_cols = 39
Files Coverage
pandapipes 91.34%
setup.py 0.00%
Project Totals (75 files) 91.01%

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading