e2nIEE / pandapipes
Showing 71 of 294 files from the diff.
Other files ignored by Codecov
LICENSE has changed.
setup.py has changed.
AUTHORS has changed.
.travis.yml has changed.
MANIFEST.in has changed.
.codacy.yml has changed.
.readthedocs.yml has changed.
README.rst has changed.
CHANGELOG.rst has changed.
CONTRIBUTING.rst has changed.

@@ -1,13 +1,8 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
try:
6 -
    from numba import jit
7 -
except ImportError:
8 -
    from pandapower.pf.no_numba import jit
9 -
10 -
from pandapipes.component_models.abstract_models.component_models import Component
5 +
from pandapipes.component_models.abstract_models.base_component import Component
11 6
12 7
try:
13 8
    import pplog as logging
@@ -54,6 +49,8 @@
Loading
54 49
        :type net: pandapipesNet
55 50
        :param node_pit:
56 51
        :type node_pit:
52 +
        :param node_name:
53 +
        :type node_name:
57 54
        :return: No Output.
58 55
        """
59 56
        raise NotImplementedError

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from pandapipes.component_models.abstract_models import ConstFlow

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import os
@@ -48,6 +48,17 @@
Loading
48 48
        """
49 49
        super(PumpStdType, self).__init__(name, 'pump')
50 50
        self.reg_par = reg_par
51 +
        self._pressure_list = None
52 +
        self._flowrate_list = None
53 +
        self._reg_polynomial_degree = 2
54 +
55 +
    def update_pump(self, pressure_list, flowrate_list, reg_polynomial_degree):
56 +
        reg_par = regression_function(pressure_list, flowrate_list, reg_polynomial_degree)
57 +
        self.reg_par = reg_par
58 +
        self._pressure_list = pressure_list
59 +
        self._flowrate_list = flowrate_list
60 +
        self._reg_polynomial_degree = reg_polynomial_degree
61 +
51 62
52 63
    def get_pressure(self, vdot_m3_per_s):
53 64
        """
@@ -86,12 +97,20 @@
Loading
86 97
        """
87 98
        p_values, v_values, degree = get_p_v_values(path)
88 99
        reg_par = regression_function(p_values, v_values, degree)
89 -
        return cls(name, reg_par)
100 +
        Pump = cls(name, reg_par)
101 +
        Pump._pressure_list = p_values
102 +
        Pump._flowrate_list = v_values
103 +
        Pump._reg_polynomial_degree = degree
104 +
        return Pump
90 105
91 106
    @classmethod
92 107
    def from_list(cls, name, p_values, v_values, degree):
93 108
        reg_par = regression_function(p_values, v_values, degree)
94 -
        return cls(name, reg_par)
109 +
        Pump = cls(name, reg_par)
110 +
        Pump._pressure_list = p_values
111 +
        Pump._flowrate_list = v_values
112 +
        Pump._reg_polynomial_degree = degree
113 +
        return Pump
95 114
96 115
97 116
def add_basic_std_types(net):

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from pandapipes.component_models.abstract_models import ConstFlow

@@ -0,0 +1,5 @@
Loading
1 +
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of 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 +
from .multinet_control import *

@@ -1,10 +1,12 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
6 5
import numpy as np
7 6
from numpy import linalg
7 +
from pandapipes.component_models import Junction
8 +
from pandapipes.component_models.abstract_models import NodeComponent, NodeElementComponent, \
9 +
    BranchComponent, BranchWInternalsComponent
8 10
from pandapipes.component_models.auxiliaries import build_system_matrix
9 11
from pandapipes.idx_branch import ACTIVE as ACTIVE_BR, FROM_NODE, TO_NODE, FROM_NODE_T, \
10 12
    TO_NODE_T, VINIT, T_OUT, VINIT_T
@@ -13,11 +15,8 @@
Loading
13 15
    init_options, create_internal_results, write_internal_results, extract_all_results, \
14 16
    get_lookup, create_lookups, initialize_pit, check_connectivity, reduce_pit, \
15 17
    extract_results_active_pit, set_user_pf_options
16 -
from scipy.sparse.linalg import spsolve
17 -
from pandapipes.component_models import Junction
18 -
from pandapipes.component_models.abstract_models import NodeComponent, NodeElementComponent, \
19 -
    BranchComponent, BranchWInternalsComponent
20 18
from pandapower.auxiliary import ppException
19 +
from scipy.sparse.linalg import spsolve
21 20
22 21
try:
23 22
    import pplog as logging
@@ -70,8 +69,9 @@
Loading
70 69
    node_pit, branch_pit = initialize_pit(net, Junction.table_name(),
71 70
                                          NodeComponent, NodeElementComponent,
72 71
                                          BranchComponent, BranchWInternalsComponent)
73 -
    if ((len(node_pit) == 0) & (len(branch_pit) == 0)):
74 -
        logger.warning("There are no node and branch entries defined. It might be that your net is empty")
72 +
    if (len(node_pit) == 0) & (len(branch_pit) == 0):
73 +
        logger.warning("There are no node and branch entries defined. This might mean that your net"
74 +
                       " is empty")
75 75
        return
76 76
    calculation_mode = get_net_option(net, "mode")
77 77
@@ -85,20 +85,20 @@
Loading
85 85
    reduce_pit(net, node_pit, branch_pit, nodes_connected, branches_connected)
86 86
87 87
    if calculation_mode == "hydraulics":
88 -
        niter = hydraulics(net)
88 +
        hydraulics(net)
89 89
    elif calculation_mode == "heat":
90 90
        if net.user_pf_options["hyd_flag"]:
91 91
            node_pit = net["_active_pit"]["node"]
92 92
            node_pit[:, PINIT] = sol_vec[:len(node_pit)]
93 93
            branch_pit = net["_active_pit"]["branch"]
94 94
            branch_pit[:, VINIT] = sol_vec[len(node_pit):]
95 -
            niter = heat_transfer(net)
95 +
            heat_transfer(net)
96 96
        else:
97 97
            logger.warning("Converged flag not set. Make sure that hydraulic calculation results "
98 98
                           "are available.")
99 99
    elif calculation_mode == "all":
100 -
        niter = hydraulics(net)
101 -
        niter = heat_transfer(net)
100 +
        hydraulics(net)
101 +
        heat_transfer(net)
102 102
    else:
103 103
        logger.warning("No proper calculation mode chosen.")
104 104
@@ -107,8 +107,8 @@
Loading
107 107
108 108
109 109
def hydraulics(net):
110 -
    max_iter, nonlinear_method, tol_p, tol_v, tol_t, tol_res = get_net_options(
111 -
        net, "iter", "nonlinear_method", "tol_p", "tol_v", "tol_T", "tol_res")
110 +
    max_iter, nonlinear_method, tol_p, tol_v, tol_res = get_net_options(
111 +
        net, "iter", "nonlinear_method", "tol_p", "tol_v", "tol_res")
112 112
113 113
    # Start of nonlinear loop
114 114
    # ---------------------------------------------------------------------------------------------
@@ -122,7 +122,7 @@
Loading
122 122
123 123
    # This loop is left as soon as the solver converged
124 124
    while not get_net_option(net, "converged") and niter <= max_iter:
125 -
        logger.info("niter %d" % niter)
125 +
        logger.debug("niter %d" % niter)
126 126
127 127
        # solve_hydraulics is where the calculation takes place
128 128
        v_init, p_init, v_init_old, p_init_old, epsilon = solve_hydraulics(net)
@@ -132,7 +132,7 @@
Loading
132 132
        dp_init = np.abs(p_init - p_init_old)
133 133
134 134
        residual_norm = (linalg.norm(epsilon) / (len(epsilon)))
135 -
        error_v.append(linalg.norm(dv_init) / (len(dv_init)))
135 +
        error_v.append(linalg.norm(dv_init) / (len(dv_init)) if len(dv_init) else 0)
136 136
        error_p.append(linalg.norm(dp_init / (len(dp_init))))
137 137
138 138
        # Control of damping factor
@@ -160,17 +160,18 @@
Loading
160 160
    write_internal_results(net, iterations=niter, error_p=error_p[niter - 1],
161 161
                           error_v=error_v[niter - 1], residual_norm=residual_norm)
162 162
163 -
    logger.info("---------------------------------------------------------------------------------")
163 +
    logger.debug(
164 +
        "---------------------------------------------------------------------------------")
164 165
    if get_net_option(net, "converged") is False:
165 166
        logger.warning("Maximum number of iterations reached but hydraulics solver did not "
166 167
                       "converge.")
167 -
        logger.info("Norm of residual: %s" % residual_norm)
168 +
        logger.debug("Norm of residual: %s" % residual_norm)
168 169
    else:
169 -
        logger.info("Calculation completed. Preparing results...")
170 -
        logger.info("Converged after %d iterations." % niter)
171 -
        logger.info("Norm of residual: %s" % residual_norm)
172 -
        logger.info("tol_p: %s" % get_net_option(net, "tol_p"))
173 -
        logger.info("tol_v: %s" % get_net_option(net, "tol_v"))
170 +
        logger.debug("Calculation completed. Preparing results...")
171 +
        logger.debug("Converged after %d iterations." % niter)
172 +
        logger.debug("Norm of residual: %s" % residual_norm)
173 +
        logger.debug("tol_p: %s" % get_net_option(net, "tol_p"))
174 +
        logger.debug("tol_v: %s" % get_net_option(net, "tol_v"))
174 175
        net['converged'] = True
175 176
176 177
    if not get_net_option(net, "reuse_internal_data"):
@@ -181,8 +182,8 @@
Loading
181 182
182 183
183 184
def heat_transfer(net):
184 -
    max_iter, nonlinear_method, tol_p, tol_v, tol_t, tol_res = get_net_options(
185 -
        net, "iter", "nonlinear_method", "tol_p", "tol_v", "tol_T", "tol_res")
185 +
    max_iter, nonlinear_method, tol_t, tol_res = get_net_options(
186 +
        net, "iter", "nonlinear_method", "tol_T", "tol_res")
186 187
187 188
    # Start of nonlinear loop
188 189
    # ---------------------------------------------------------------------------------------------
@@ -198,7 +199,7 @@
Loading
198 199
199 200
    # This loop is left as soon as the solver converged
200 201
    while not get_net_option(net, "converged") and niter <= max_iter:
201 -
        logger.info("niter %d" % niter)
202 +
        logger.debug("niter %d" % niter)
202 203
203 204
        # solve_hydraulics is where the calculation takes place
204 205
        t_out, t_out_old, t_init, t_init_old, epsilon = solve_temperature(net)
@@ -239,16 +240,17 @@
Loading
239 240
240 241
    write_internal_results(net, iterations_T=niter, error_T=error_t[niter - 1],
241 242
                           residual_norm_T=residual_norm)
242 -
    logger.info("---------------------------------------------------------------------------------")
243 +
    logger.debug(
244 +
        "---------------------------------------------------------------------------------")
243 245
    if get_net_option(net, "converged") is False:
244 246
        logger.warning("Maximum number of iterations reached but heat transfer solver did not "
245 247
                       "converge.")
246 -
        logger.info("Norm of residual: %s" % residual_norm)
248 +
        logger.debug("Norm of residual: %s" % residual_norm)
247 249
    else:
248 -
        logger.info("Calculation completed. Preparing results...")
249 -
        logger.info("Converged after %d iterations." % niter)
250 -
        logger.info("Norm of residual: %s" % residual_norm)
251 -
        logger.info("tol_T: %s" % get_net_option(net, "tol_T"))
250 +
        logger.debug("Calculation completed. Preparing results...")
251 +
        logger.debug("Converged after %d iterations." % niter)
252 +
        logger.debug("Norm of residual: %s" % residual_norm)
253 +
        logger.debug("tol_T: %s" % get_net_option(net, "tol_T"))
252 254
253 255
        net['converged'] = True
254 256

@@ -0,0 +1,267 @@
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 +
import pandapipes as ppipes
7 +
import pandapower as pp
8 +
import pandas as pd
9 +
from pandapipes.control.run_control import prepare_run_ctrl as prepare_run_ctrl_ppipes
10 +
from pandapower.control.run_control import prepare_run_ctrl as prepare_run_ctrl_pp, \
11 +
    net_initialization, get_recycle, control_initialization, control_finalization, \
12 +
    _evaluate_net as _evaluate_net, control_implementation, get_controller_order, NetCalculationNotConverged
13 +
14 +
try:
15 +
    import pplog as logging
16 +
except ImportError:
17 +
    import logging
18 +
19 +
logger = logging.getLogger(__name__)
20 +
21 +
22 +
def _evaluate_multinet(multinet, levelorder, ctrl_variables, **kwargs):
23 +
    """
24 +
    Within a control loop after all controllers applied their their action "_evaluate_multinet" checks if all
25 +
    nets affectd in one level did converge or not
26 +
27 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
28 +
    :type multinet: pandapipes.Multinet
29 +
    :param levelorder: list of tuples given the correct order of the different controllers within one level
30 +
    :type levelorder: list
31 +
    :param ctrl_variables: contains all relevant information and boundaries required for a successful control run
32 +
    :type ctrl_variables: dict
33 +
    :param kwargs: additional keyword arguments handed to each run function
34 +
    :type kwargs: dict
35 +
    :return: as the ctrl_variables are adapted they are returned
36 +
    :rtype: dict
37 +
    """
38 +
    levelorder = np.array(levelorder)
39 +
    multinet_converged = []
40 +
    rel_nets = _relevant_nets(multinet, levelorder)
41 +
    for net_name in multinet['nets'].keys():
42 +
        net = multinet['nets'][net_name]
43 +
        rel_levelorder = levelorder[rel_nets[net_name]]
44 +
        ctrl_variables[net_name] = _evaluate_net(net, rel_levelorder, ctrl_variables[net_name], **kwargs) if np.any(
45 +
            rel_nets[net_name]) else ctrl_variables[net_name]
46 +
        multinet_converged += [ctrl_variables[net_name]['converged']]
47 +
    ctrl_variables['converged'] = np.all(multinet_converged)
48 +
    return ctrl_variables
49 +
50 +
51 +
def _relevant_nets(multinet, levelorder):
52 +
    """
53 +
    This function determines the relevant nets in each level, i.e. only the nets affected in each level are investigated
54 +
    and checked.
55 +
56 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
57 +
    :type multinet: pandapipes.Multinet
58 +
    :param levelorder: list of tuples given the correct order of the different controllers within one level
59 +
    :type levelorder: list
60 +
    :return: dictionary of all nets in multinet.nets. Entries are booleans. True means net is in the
61 +
    corresponding level, False means it is not.
62 +
    :rtype: dict
63 +
    """
64 +
    net_names = dict()
65 +
66 +
    nns = []
67 +
    levelorder = np.array(levelorder)
68 +
    rel_levelorder_multi = levelorder[:, 1].__eq__(multinet)
69 +
    controller = levelorder[rel_levelorder_multi, 0]
70 +
    nns += [ctrl.get_all_net_names() for ctrl in controller]
71 +
72 +
    for net_name in multinet['nets'].keys():
73 +
        net = multinet['nets'][net_name]
74 +
        rel_levelorder = levelorder[:, 1].__eq__(net)
75 +
        level_excl = [False if net_name not in nn else True for nn in nns]
76 +
        rel_levelorder_multi[rel_levelorder_multi] = level_excl
77 +
        net_names[net_name] = np.maximum(rel_levelorder_multi, rel_levelorder)
78 +
79 +
    return net_names
80 +
81 +
82 +
def net_initialization_multinet(multinet, ctrl_variables, **kwargs):
83 +
    """
84 +
    This function initilizes each net, i.e. if one controller affecting a net requires an initial_run a loadflow/
85 +
    pipeflow is conducted, otherwise not.
86 +
87 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
88 +
    :type multinet: pandapipes.Multinet
89 +
    :param ctrl_variables: contains all relevant information and boundaries required for a successful control run
90 +
    :type ctrl_variables: dict
91 +
    :param kwargs: additional keyword arguments handed to each run function
92 +
    :type kwargs: dict
93 +
    :return: as the ctrl_variables are adapted they are returned
94 +
    :rtype: dict
95 +
    """
96 +
    ctrl_variables['converged'] = False
97 +
98 +
    for net_name in multinet['nets'].keys():
99 +
        net = multinet['nets'][net_name]
100 +
        kwargs['recycle'], kwargs['only_v_results'] = \
101 +
            ctrl_variables[net_name]['recycle'], ctrl_variables[net_name]['only_v_results']
102 +
        ctrl_variables[net_name] = net_initialization(net, ctrl_variables[net_name], **kwargs)
103 +
        ctrl_variables['converged'] = max(ctrl_variables['converged'], ctrl_variables[net_name]['converged'])
104 +
    return ctrl_variables
105 +
106 +
107 +
def run_control(multinet, ctrl_variables=None, max_iter=30, **kwargs):
108 +
    """
109 +
    Main function to call a multnet with controllers
110 +
    Function is running control loops for the controllers specified in net.controller
111 +
    Runs controller until each one converged or max_iter is hit.
112 +
113 +
    1. Call initialize_control() on each controller
114 +
    2. Calculate an inital run (if it is enabled, i.e. setting the initial_run veriable to True)
115 +
    3. Repeats the following steps in ascending order of controller_order until total convergence of all
116 +
       controllers for each level:
117 +
        a) Evaluate individual convergence for all controllers in the level
118 +
        b) Call control_step() for all controllers in the level on diverged controllers
119 +
        c) Fire run function (or optionally another function like runopf or whatever you defined)
120 +
    4. Call finalize_control() on each controller
121 +
122 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
123 +
    :type multinet: pandapipes.Multinet
124 +
    :param ctrl_variables: contains all relevant information and boundaries required for a successful control run. To \
125 +
        define ctrl_variables yourself, following entries for each net are required:\n
126 +
        - level (list): gives a list of levels to be investigated \n
127 +
        - controller_order (list): nested list of tuples given the correct order of the different controllers \
128 +
        within one level\
129 +
        - run (funct, e.g. pandapower.runpp, pandapipes.pipeflow): function to be used to conduct a loadflow/pipeflow \n
130 +
        - initial_run (boolean): Is a initial_run for a net required or not\n
131 +
        - continue_on_divergence (boolean): What to do if loadflow/pipeflow is not converging, fires control_repair
132 +
    :type ctrl_variables: dict, default: None
133 +
    :param max_iter: number of iterations for each controller to converge
134 +
    :type max_iter: int, default: 30
135 +
    :param kwargs: additional keyword arguments handed to each run function
136 +
    :type kwargs: dict
137 +
    :return: runs an entire control loop
138 +
    :rtype: None
139 +
    """
140 +
    ctrl_variables = prepare_run_ctrl(multinet, ctrl_variables)
141 +
    controller_order = ctrl_variables['controller_order']
142 +
143 +
    # initialize each controller prior to the first power flow
144 +
    control_initialization(controller_order)
145 +
146 +
    # initial run (takes time, but is not needed for every kind of controller)
147 +
    ctrl_variables = net_initialization_multinet(multinet, ctrl_variables, **kwargs)
148 +
149 +
    # run each controller step in given controller order
150 +
    control_implementation(multinet, controller_order, ctrl_variables, max_iter,
151 +
                           evaluate_net_fct=_evaluate_multinet, **kwargs)
152 +
153 +
    # call finalize function of each controller
154 +
    control_finalization(controller_order)
155 +
156 +
157 +
def get_controller_order_multinet(multinet):
158 +
    """
159 +
    Defining the controller order per level
160 +
    Takes the order and level columns from net.controller
161 +
    If levels are specified, the levels and orders are executed in ascending order.
162 +
163 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
164 +
    :type multinet: pandapipes.Multinet
165 +
    :return: nested list of tuples given the correct order of the controllers, respectively for each level
166 +
    :rtype: list
167 +
    """
168 +
169 +
    net_list = []
170 +
    controller_list = []
171 +
172 +
    if hasattr(multinet, "controller") and len(multinet.controller[multinet.controller.in_service]) != 0:
173 +
        # if no controllers are in the net, we have no levels and no order lists
174 +
        multinets = [multinet] * len(multinet.controller)
175 +
        net_list += multinets
176 +
        controller_list += [multinet.controller]
177 +
178 +
    for net_name in multinet['nets'].keys():
179 +
        net = multinet['nets'][net_name]
180 +
        if not (hasattr(net, 'controller') and len(net.controller[net.controller.in_service]) != 0):
181 +
            # if no controllers are in the net, we have no levels and no order lists
182 +
            continue
183 +
        nets = [net] * len(net.controller)
184 +
        net_list += nets
185 +
        controller_list += [net.controller]
186 +
187 +
    controller_list = pd.concat(controller_list).reset_index(drop=True)
188 +
189 +
    if not controller_list.size:
190 +
        # if no controllers are in the net, we have no levels and no order lists
191 +
        return [0], [[]]
192 +
    else:
193 +
        return get_controller_order(net_list, controller_list)
194 +
195 +
196 +
def prepare_run_ctrl(multinet, ctrl_variables):
197 +
    """
198 +
    Prepares run control functions. Internal variables needed:
199 +
        - level (list): gives a list of levels to be investigated
200 +
        - controller_order (list): nested list of tuples given the correct order of the different controllers
201 +
        within one level
202 +
        - run (funct, e.g. pandapower.runpp, pandapipes.pipeflow): function to be used to conduct a loadflow/pipeflow
203 +
        - initial_run (boolean): Is a initial_run for a net required or not
204 +
        - continue_on_divergence (boolean): What to do if loadflow/pipeflow is not converging, fires control_repair
205 +
206 +
    You don't need to define it for each net. If one net is not defined, the default settings are used.
207 +
208 +
    :param multinet: multinet with multinet controllers, net distinct controllers and several pandapipes/pandapower nets
209 +
    :type multinet: pandapipes.Multinet
210 +
    :param ctrl_variables: contains all relevant information and boundaries required for a successful control run.
211 +
    :type ctrl_variables: dict
212 +
    :return: adapted ctrl_variables for all nets with all required boundary informaiton
213 +
    :rtype: dict
214 +
    """
215 +
216 +
    # sort controller_order by order if not already done
217 +
    if ctrl_variables is None:
218 +
        ctrl_variables = dict()
219 +
220 +
    excl_net = []
221 +
222 +
    if hasattr(multinet, "controller") and len(multinet.controller[multinet.controller.in_service]) != 0:
223 +
        for _, c in multinet['controller'].iterrows():
224 +
            net_names = c.object.get_all_net_names()
225 +
            for net_name in net_names:
226 +
                if net_name not in ctrl_variables.keys():
227 +
                    ctrl_variables[net_name] = {'run': None, 'initial_run': None, 'errors': ()}
228 +
                net = multinet['nets'][net_name]
229 +
                if isinstance(net, ppipes.pandapipesNet):
230 +
                    ctrl_variables_net = prepare_run_ctrl_ppipes(net, None)
231 +
                elif isinstance(net, pp.pandapowerNet):
232 +
                    ctrl_variables_net = prepare_run_ctrl_pp(net, None)
233 +
                else:
234 +
                    raise ValueError('the given nets are neither pandapipes nor pandapower nets')
235 +
236 +
                ctrl_variables[net_name]['run'] = ctrl_variables_net['run']
237 +
                ctrl_variables[net_name]['errors'] = ctrl_variables_net['errors']
238 +
                ctrl_variables[net_name]['initial_run'] = ctrl_variables[net_name]['initial_run'] if \
239 +
                    ctrl_variables[net_name]['initial_run'] is not None else ctrl_variables_net['initial_run']
240 +
                ctrl_variables[net_name]['only_v_results'], ctrl_variables[net_name]['recycle'] = \
241 +
                    get_recycle(ctrl_variables_net)
242 +
                excl_net += [net_name]
243 +
244 +
    for net_name in multinet['nets'].keys():
245 +
        if net_name in excl_net:
246 +
            continue
247 +
        if net_name not in ctrl_variables.keys():
248 +
            ctrl_variables[net_name] = {'run': None, 'initial_run': False, 'errors': ()}
249 +
        net = multinet['nets'][net_name]
250 +
        if isinstance(net, ppipes.pandapipesNet):
251 +
            ctrl_variables_net = prepare_run_ctrl_ppipes(net, None)
252 +
        elif isinstance(net, pp.pandapowerNet):
253 +
            ctrl_variables_net = prepare_run_ctrl_pp(net, None)
254 +
        else:
255 +
            raise ValueError('the given nets are neither pandapipes nor pandapower nets')
256 +
        ctrl_variables[net_name]['run'] = ctrl_variables_net['run']
257 +
        ctrl_variables[net_name]['errors'] = ctrl_variables_net['errors']
258 +
        ctrl_variables[net_name]['initial_run'] = ctrl_variables[net_name]['initial_run'] if \
259 +
            ctrl_variables[net_name]['initial_run'] is not None else ctrl_variables_net['initial_run']
260 +
        ctrl_variables[net_name]['only_v_results'], ctrl_variables[net_name]['recycle'] = \
261 +
            get_recycle(ctrl_variables_net)
262 +
263 +
    ctrl_variables['errors'] = (NetCalculationNotConverged,)
264 +
265 +
    ctrl_variables['level'], ctrl_variables['controller_order'] = get_controller_order_multinet(multinet)
266 +
267 +
    return ctrl_variables

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
@@ -14,7 +14,8 @@
Loading
14 14
15 15
16 16
def build_system_matrix(net, branch_pit, node_pit, heat_mode):
17 -
    """Builds the system matrix.
17 +
    """
18 +
    Builds the system matrix.
18 19
19 20
    :param net: The pandapipes network
20 21
    :type net: pandapipesNet

@@ -1,25 +1,20 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import matplotlib.pyplot as plt
6 6
import numpy as np
7 -
8 -
7 +
from numpy import dtype
9 8
from pandapipes.component_models.abstract_models import BranchWInternalsComponent
10 9
from pandapipes.component_models.auxiliaries.component_toolbox import p_correction_height_air, \
11 10
    vinterp
12 11
from pandapipes.component_models.junction_component import Junction
13 -
14 -
from pandapipes.idx_node import ELEMENT_IDX, PINIT, HEIGHT, TINIT as TINIT_NODE, \
15 -
    RHO as RHO_NODES, PAMB, ACTIVE as ACTIVE_ND
16 -
from pandapipes.idx_branch import FROM_NODE, TO_NODE, LENGTH, D, TINIT, AREA, K, \
17 -
    VINIT, RE, LAMBDA, LOAD_VEC_NODES, ALPHA, QEXT, TEXT, LOSS_COEFFICIENT as LC, T_OUT, PL, TL
18 12
from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE
19 -
13 +
from pandapipes.idx_branch import FROM_NODE, TO_NODE, LENGTH, D, AREA, K, \
14 +
    VINIT, ALPHA, QEXT, TEXT, LOSS_COEFFICIENT as LC, T_OUT, PL, TL
15 +
from pandapipes.idx_node import PINIT, HEIGHT, TINIT as TINIT_NODE, \
16 +
    RHO as RHO_NODES, PAMB, ACTIVE as ACTIVE_ND
20 17
from pandapipes.pipeflow_setup import get_net_option, get_fluid, get_lookup
21 -
from pandapipes.internals_toolbox import _sum_by_group, select_from_pit
22 -
from numpy import dtype
23 18
24 19
try:
25 20
    import pplog as logging
@@ -35,6 +30,10 @@
Loading
35 30
36 31
    """
37 32
33 +
    @classmethod
34 +
    def from_to_node_cols(cls):
35 +
        return "from_junction", "to_junction"
36 +
38 37
    @classmethod
39 38
    def table_name(cls):
40 39
        return "pipe"
@@ -95,6 +94,8 @@
Loading
95 94
        :type net: pandapipesNet
96 95
        :param node_pit:
97 96
        :type node_pit:
97 +
        :param node_name:
98 +
        :type node_name:
98 99
        :return: No Output.
99 100
        """
100 101
        table_nr, int_node_number, int_node_pit, junction_pit, from_junctions, to_junctions = \
@@ -120,8 +121,10 @@
Loading
120 121
121 122
        :param net: The pandapipes network
122 123
        :type net: pandapipesNet
123 -
        :param branch_pit:
124 -
        :type branch_pit:
124 +
        :param pipe_pit:
125 +
        :type pipe_pit:
126 +
        :param node_name:
127 +
        :type node_name:
125 128
        :return: No Output.
126 129
        """
127 130
        pipe_pit, internal_pipe_number = \
@@ -173,97 +176,11 @@
Loading
173 176
        """
174 177
        pipe_pit[:, TL] = 0
175 178
176 -
    @classmethod
177 -
    def extract_results(cls, net, options, node_name):
178 -
        """
179 -
        Function that extracts certain results.
180 -
181 -
        :param net: The pandapipes network
182 -
        :type net: pandapipesNet
183 -
        :param options:
184 -
        :type options:
185 -
        :return: No Output.
186 -
        """
187 -
188 -
        placement_table, pipe_pit, res_table = super().extract_results(net, options, node_name)
189 -
190 -
        node_pit = net["_active_pit"]["node"]
191 -
        node_active_idx_lookup = get_lookup(net, "node", "index_active")[node_name]
192 -
        junction_idx_lookup = get_lookup(net, "node", "index")[node_name]
193 -
        from_junction_nodes = node_active_idx_lookup[junction_idx_lookup[
194 -
            net[cls.table_name()]["from_junction"].values[placement_table]]]
195 -
        to_junction_nodes = node_active_idx_lookup[junction_idx_lookup[
196 -
            net[cls.table_name()]["to_junction"].values[placement_table]]]
197 -
198 -
        from_nodes = pipe_pit[:, FROM_NODE].astype(np.int32)
199 -
        to_nodes = pipe_pit[:, TO_NODE].astype(np.int32)
200 -
        p_scale = get_net_option(net, "p_scale")
201 -
        fluid = get_fluid(net)
202 -
203 -
        v_mps = pipe_pit[:, VINIT]
204 -
205 -
        t0 = node_pit[from_nodes, TINIT_NODE]
206 -
        t1 = node_pit[to_nodes, TINIT_NODE]
207 -
        mf = pipe_pit[:, LOAD_VEC_NODES]
208 -
        vf = pipe_pit[:, LOAD_VEC_NODES] / get_fluid(net).get_density((t0 + t1) / 2)
209 -
210 -
        idx_active = pipe_pit[:, ELEMENT_IDX]
211 -
        idx_sort, v_sum, mf_sum, vf_sum, internal_pipes = \
212 -
            _sum_by_group(idx_active, v_mps, mf, vf, np.ones_like(idx_active))
213 -
214 -
        if fluid.is_gas:
215 -
            # derived from the ideal gas law
216 -
            p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] * p_scale
217 -
            p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] * p_scale
218 -
            numerator = NORMAL_PRESSURE * pipe_pit[:, TINIT]
219 -
            normfactor_from = numerator * fluid.get_property("compressibility", p_from) \
220 -
                              / (p_from * NORMAL_TEMPERATURE)
221 -
            normfactor_to = numerator * fluid.get_property("compressibility", p_to) \
222 -
                            / (p_to * NORMAL_TEMPERATURE)
223 -
            v_gas_from = v_mps * normfactor_from
224 -
            v_gas_to = v_mps * normfactor_to
225 -
            mask = ~np.isclose(p_from, p_to)
226 -
            p_mean = np.empty_like(p_to)
227 -
            p_mean[~mask] = p_from[~mask]
228 -
            p_mean[mask] = 2 / 3 * (p_from[mask] ** 3 - p_to[mask] ** 3) \
229 -
                           / (p_from[mask] ** 2 - p_to[mask] ** 2)
230 -
            normfactor_mean = numerator * fluid.get_property("compressibility", p_mean) \
231 -
                              / (p_mean * NORMAL_TEMPERATURE)
232 -
            v_gas_mean = v_mps * normfactor_mean
233 -
234 -
            idx_sort, v_gas_from_sum, v_gas_to_sum, v_gas_mean_sum, nf_from_sum, nf_to_sum, \
235 -
            internal_pipes = _sum_by_group(
236 -
                idx_active, v_gas_from, v_gas_to, v_gas_mean, normfactor_from, normfactor_to,
237 -
                np.ones_like(idx_active))
238 -
239 -
            v_gas_from_ordered = select_from_pit(from_nodes,from_junction_nodes, v_gas_from)
240 -
            v_gas_to_ordered = select_from_pit(to_nodes,to_junction_nodes, v_gas_to)
241 -
242 -
            res_table["v_from_m_per_s"].values[placement_table] = v_gas_from_ordered
243 -
            res_table["v_to_m_per_s"].values[placement_table] = v_gas_to_ordered
244 -
            res_table["v_mean_m_per_s"].values[placement_table] = v_gas_mean_sum / internal_pipes
245 -
            res_table["normfactor_from"].values[placement_table] = nf_from_sum / internal_pipes
246 -
            res_table["normfactor_to"].values[placement_table] = nf_to_sum / internal_pipes
247 -
        else:
248 -
            res_table["v_mean_m_per_s"].values[placement_table] = v_sum / internal_pipes
249 -
250 -
        res_table["p_from_bar"].values[placement_table] = node_pit[from_junction_nodes, PINIT]
251 -
        res_table["p_to_bar"].values[placement_table] = node_pit[to_junction_nodes, PINIT]
252 -
        res_table["t_from_k"].values[placement_table] = node_pit[from_junction_nodes, TINIT_NODE]
253 -
        res_table["t_to_k"].values[placement_table] = node_pit[to_junction_nodes, TINIT_NODE]
254 -
        res_table["mdot_to_kg_per_s"].values[placement_table] = -mf_sum / internal_pipes
255 -
        res_table["mdot_from_kg_per_s"].values[placement_table] = mf_sum / internal_pipes
256 -
        res_table["vdot_norm_m3_per_s"].values[placement_table] = vf_sum / internal_pipes
257 -
        idx_pit = pipe_pit[:, ELEMENT_IDX]
258 -
        idx_sort, lambda_sum, reynolds_sum, = \
259 -
            _sum_by_group(idx_pit, pipe_pit[:, LAMBDA], pipe_pit[:, RE])
260 -
        res_table["lambda"].values[placement_table] = lambda_sum / internal_pipes
261 -
        res_table["reynolds"].values[placement_table] = reynolds_sum / internal_pipes
262 -
263 179
    @classmethod
264 180
    def get_internal_results(cls, net, pipe):
265 181
        """
266 -
        Retrieve velocity (at to/from node; mean), pressure and temperature of the internal sections of pipes. The pipes have to have at least 2 internal sections.
182 +
        Retrieve velocity (at to/from node; mean), pressure and temperature of the internal sections
183 +
        of pipes. The pipes have to have at least 2 internal sections.
267 184
268 185
        :param net: The pandapipes network
269 186
        :type net: pandapipesNet
@@ -283,7 +200,6 @@
Loading
283 200
        pipe_results["VINIT_TO"] = np.zeros((len(v_pipe_idx), 2), dtype=np.float64)
284 201
        pipe_results["VINIT_MEAN"] = np.zeros((len(v_pipe_idx), 2), dtype=np.float64)
285 202
286 -
287 203
        if np.all(internal_sections[pipe] >= 2):
288 204
            fluid = get_fluid(net)
289 205
            f, t = get_lookup(net, "branch", "from_to")[cls.table_name()]
@@ -321,11 +237,11 @@
Loading
321 237
                                  2 / 3 * (p_from ** 3 - p_to ** 3) / (p_from ** 2 - p_to ** 2))
322 238
                numerator = NORMAL_PRESSURE * node_pit[v_nodes, TINIT_NODE]
323 239
                normfactor_mean = numerator * fluid.get_property("compressibility", p_mean) \
324 -
                             / (p_mean * NORMAL_TEMPERATURE)
240 +
                                  / (p_mean * NORMAL_TEMPERATURE)
325 241
                normfactor_from = numerator * fluid.get_property("compressibility", p_from) \
326 242
                                  / (p_from * NORMAL_TEMPERATURE)
327 243
                normfactor_to = numerator * fluid.get_property("compressibility", p_to) \
328 -
                                / (p_to * NORMAL_TEMPERATURE)
244 +
                                  / (p_to * NORMAL_TEMPERATURE)
329 245
330 246
                v_pipe_data_mean = v_pipe_data * normfactor_mean
331 247
                v_pipe_data_from = v_pipe_data * normfactor_from
@@ -345,8 +261,6 @@
Loading
345 261
                pipe_results["VINIT_MEAN"][:, 0] = v_pipe_idx
346 262
                pipe_results["VINIT_MEAN"][:, 1] = v_pipe_data
347 263
348 -
349 -
350 264
            pipe_results["PINIT"][:, 0] = p_node_idx
351 265
            pipe_results["PINIT"][:, 1] = p_node_data
352 266
            pipe_results["TINIT"][:, 0] = p_node_idx
@@ -446,7 +360,7 @@
Loading
446 360
447 361
        x_pt = np.linspace(0, net.pipe["length_km"], len(p_values))
448 362
        x_v = np.linspace(0, net.pipe["length_km"], len(v_values))
449 -
        f, axes = plt.subplots(3, 1, sharex="all")
363 +
        _, axes = plt.subplots(3, 1, sharex="all")
450 364
        axes[0].plot(x_pt, p_values)
451 365
        axes[0].set_title("Pressure [bar]")
452 366
        axes[1].plot(x_v, v_values)

@@ -1,8 +1,7 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
6 5
import matplotlib.pyplot as plt
7 6
8 7
from pandapipes.plotting.plotting_toolbox import get_collection_sizes
@@ -13,7 +12,6 @@
Loading
13 12
from pandapower.plotting import draw_collections
14 13
from itertools import chain
15 14
16 -
17 15
try:
18 16
    import pplog as logging
19 17
except ImportError:
@@ -22,13 +20,12 @@
Loading
22 20
logger = logging.getLogger(__name__)
23 21
24 22
25 -
def simple_plot(net, respect_valves=False, respect_in_service=True,
26 -
                pipe_width=2.0, junction_size=1.0, ext_grid_size=1.0,
27 -
                plot_sinks=False, plot_sources=False, sink_size=1.0, source_size=1.0,
28 -
                valve_size=1.0, pump_size=1.0, heat_exchanger_size=1.0, scale_size=True,
29 -
                junction_color="r", pipe_color='silver', ext_grid_color='orange',
30 -
                valve_color='silver', pump_color='silver', heat_exchanger_color='silver',
31 -
                library="igraph", show_plot=True, ax=None, **kwargs):  # pragma: no cover
23 +
def simple_plot(net, respect_valves=False, respect_in_service=True, pipe_width=2.0,
24 +
                junction_size=1.0, ext_grid_size=1.0, plot_sinks=False, plot_sources=False,
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):
32 29
    """
33 30
    Plots a pandapipes network as simple as possible. If no geodata is available, artificial
34 31
    geodata is generated. For advanced plotting see
@@ -60,6 +57,8 @@
Loading
60 57
    :type source_size: float, default 1.0
61 58
    :param valve_size: Relative size of valves to plot.
62 59
    :type valve_size: float, default 1.0
60 +
    :param pump_size: Relative size of pumps to plot.
61 +
    :type pump_size: float, default 1.0
63 62
    :param heat_exchanger_size: Relative size of heat_exchanger to plot.
64 63
    :type heat_exchanger_size: float, default 1.0
65 64
    :param scale_size: Flag if junction_size, ext_grid_size, valve_size- and distance will be \
@@ -72,6 +71,12 @@
Loading
72 71
    :type pipe_color: str, tuple, default "silver"
73 72
    :param ext_grid_color: External grid color
74 73
    :type ext_grid_color: str, tuple, default "orange"
74 +
    :param valve_color: Valve Color.
75 +
    :type valve_color: str, tuple, default "silver"
76 +
    :param pump_color: Pump Color.
77 +
    :type pump_color: str, tuple, default "silver"
78 +
    :param heat_exchanger_color: Heat Exchanger Color.
79 +
    :type heat_exchanger_color: str, tuple, default "silver"
75 80
    :param library: Library name to create generic coordinates (case of missing geodata). Choose\
76 81
            "igraph" to use igraph package or "networkx" to use networkx package.
77 82
    :type library: str, default "igraph"
@@ -82,12 +87,11 @@
Loading
82 87
    :return: ax - Axes of figure
83 88
84 89
    """
85 -
    collections = create_simple_collections(net, respect_valves, respect_in_service, pipe_width, junction_size,
86 -
                                            ext_grid_size, plot_sinks, plot_sources, sink_size,
87 -
                                            source_size, valve_size, pump_size, heat_exchanger_size,
88 -
                                            scale_size, junction_color, pipe_color, ext_grid_color,
89 -
                                            valve_color, pump_color, heat_exchanger_color,
90 -
                                            library, as_dict=False, **kwargs)
90 +
    collections = create_simple_collections(
91 +
        net, respect_valves, respect_in_service, pipe_width, junction_size, ext_grid_size,
92 +
        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)
91 95
    ax = draw_collections(collections, ax=ax)
92 96
93 97
    if show_plot:
@@ -95,17 +99,17 @@
Loading
95 99
    return ax
96 100
97 101
98 -
def create_simple_collections(net, respect_valves=False, respect_in_service=True,
99 -
                              pipe_width=5.0, junction_size=1.0,
100 -
                              ext_grid_size=1.0, plot_sinks=False, plot_sources=False,
101 -
                              sink_size=1.0, source_size=1.0, valve_size=1.0, pump_size=1.0,
102 -
                              heat_exchanger_size=1.0, scale_size=True, junction_color="r",
103 -
                              pipe_color='silver', ext_grid_color='orange', valve_color='silver',
104 -
                              pump_color='silver', heat_exchanger_color='silver',
105 -
                              library="igraph", as_dict=True, **kwargs):
102 +
def create_simple_collections(net, respect_valves=False, respect_in_service=True, pipe_width=5.0,
103 +
                              junction_size=1.0, ext_grid_size=1.0, plot_sinks=False,
104 +
                              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):
106 110
    """
107 -
    Plots a pandapipes network as simple as possible. If no geodata is available, artificial
108 -
    geodata is generated. For advanced plotting see the tutorial
111 +
    Plots a pandapipes network as simple as possible.
112 +
    If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial
109 113
110 114
    :param net: The pandapipes format network.
111 115
    :type net: pandapipesNet
@@ -135,6 +139,8 @@
Loading
135 139
    :type source_size: float, default 1.0
136 140
    :param valve_size: Relative size of valves to plot.
137 141
    :type valve_size: float, default 1.0
142 +
    :param pump_size: Relative size of pumps to plot.
143 +
    :type pump_size: float, default 1.0
138 144
    :param heat_exchanger_size:
139 145
    :type heat_exchanger_size:
140 146
    :param scale_size: Flag if junction_size, ext_grid_size, valve_size- and distance will be \
@@ -147,6 +153,12 @@
Loading
147 153
    :type pipe_color: str, tuple, default "silver"
148 154
    :param ext_grid_color: External Grid Color.
149 155
    :type ext_grid_color: str, tuple, default "orange"
156 +
    :param valve_color: Valve Color.
157 +
    :type valve_color: str, tuple, default "silver"
158 +
    :param pump_color: Pump Color.
159 +
    :type pump_color: str, tuple, default "silver"
160 +
    :param heat_exchanger_color: Heat Exchanger Color.
161 +
    :type heat_exchanger_color: str, tuple, default "silver"
150 162
    :param library: library name to create generic coordinates (case of missing geodata). Choose\
151 163
            "igraph" to use igraph package or "networkx" to use networkx package. **NOTE**: \
152 164
            Currently the networkx implementation is not working!
@@ -200,8 +212,9 @@
Loading
200 212
201 213
    # create ext_grid collections
202 214
    if respect_in_service:
203 -
        eg_junctions_with_geo_coordinates = set(net.ext_grid[net.ext_grid.in_service].junction.values) \
204 -
                                            & set(net.junction_geodata.index)
215 +
        eg_junctions_with_geo_coordinates = \
216 +
            set(net.ext_grid[net.ext_grid.in_service].junction.values) \
217 +
            & set(net.junction_geodata.index)
205 218
    else:
206 219
        eg_junctions_with_geo_coordinates = set(net.ext_grid.junction.values) \
207 220
                                            & set(net.junction_geodata.index)
@@ -213,22 +226,24 @@
Loading
213 226
214 227
    if 'source' in net and plot_sources and len(net.source) > 0:
215 228
        if respect_in_service:
216 -
            source_colls = create_source_collection(net, sources=net.source[net.source.in_service].index,
217 -
                                                    size=source_size, patch_edgecolor='silver', line_color='silver',
218 -
                                                    linewidths=pipe_width)
229 +
            source_colls = create_source_collection(
230 +
                net, sources=net.source[net.source.in_service].index, size=source_size,
231 +
                patch_edgecolor='silver', line_color='silver', linewidths=pipe_width)
219 232
        else:
220 -
            source_colls = create_source_collection(net, size=source_size, patch_edgecolor='silver', line_color='silver',
221 -
                                                    linewidths=pipe_width)
233 +
            source_colls = create_source_collection(
234 +
                net, size=source_size, patch_edgecolor='silver', line_color='silver',
235 +
                linewidths=pipe_width)
222 236
        collections["source"] = source_colls
223 237
224 238
    if 'sink' in net and plot_sinks and len(net.sink) > 0:
225 239
        if respect_in_service:
226 -
            sink_colls = create_sink_collection(net, sinks=net.sink[net.sink.in_service].index,
227 -
                                                size=sink_size, patch_edgecolor='silver', line_color='silver',
228 -
                                                linewidths=pipe_width)
240 +
            sink_colls = create_sink_collection(
241 +
                net, sinks=net.sink[net.sink.in_service].index, size=sink_size,
242 +
                patch_edgecolor='silver', line_color='silver', linewidths=pipe_width)
229 243
        else:
230 -
            sink_colls = create_sink_collection(net, size=sink_size, patch_edgecolor='silver', line_color='silver',
231 -
                                                linewidths=pipe_width)
244 +
            sink_colls = create_sink_collection(
245 +
                net, size=sink_size, patch_edgecolor='silver', line_color='silver',
246 +
                linewidths=pipe_width)
232 247
        collections["sink"] = sink_colls
233 248
234 249
    if 'valve' in net:
@@ -248,34 +263,37 @@
Loading
248 263
249 264
    if 'circ_pump_mass' in net:
250 265
        if respect_in_service:
251 -
            circ_pump_colls = create_pump_collection(net, pumps=net.circ_pump_mass[net.circ_pump_mass.in_service].index,
252 -
                                                table_name='circ_pump_mass',
253 -
                                                size=pump_size, linewidths=pipe_width, color=pump_color)
266 +
            circ_pump_colls = create_pump_collection(
267 +
                net, pumps=net.circ_pump_mass[net.circ_pump_mass.in_service].index,
268 +
                table_name='circ_pump_mass', size=pump_size, linewidths=pipe_width,
269 +
                color=pump_color)
254 270
        else:
255 -
            circ_pump_colls = create_pump_collection(net, table_name='circ_pump_mass',
256 -
                                                     size=pump_size, linewidths=pipe_width, color=pump_color)
271 +
            circ_pump_colls = create_pump_collection(
272 +
                net, table_name='circ_pump_mass', size=pump_size, linewidths=pipe_width,
273 +
                color=pump_color)
257 274
        collections["circ_pump_mass"] = circ_pump_colls
258 275
259 276
    if 'circ_pump_pressure' in net:
260 277
        if respect_in_service:
261 -
            circ_pump_colls = create_pump_collection(net, pumps=net.circ_pump_pressure[
262 -
                                                     net.circ_pump_pressure.in_service].index,
263 -
                                                     table_name='circ_pump_pressure',
264 -
                                                     size=pump_size, linewidths=pipe_width, color=pump_color)
278 +
            circ_pump_colls = create_pump_collection(
279 +
                net, pumps=net.circ_pump_pressure[net.circ_pump_pressure.in_service].index,
280 +
                table_name='circ_pump_pressure', size=pump_size, linewidths=pipe_width,
281 +
                color=pump_color)
265 282
            collections["circ_pump_pressure"] = circ_pump_colls
266 283
        else:
267 -
            circ_pump_colls = create_pump_collection(net, table_name='circ_pump_pressure',
268 -
                                                     size=pump_size, linewidths=pipe_width, color=pump_color)
284 +
            circ_pump_colls = create_pump_collection(
285 +
                net, table_name='circ_pump_pressure', size=pump_size, linewidths=pipe_width,
286 +
                color=pump_color)
269 287
            collections["circ_pump_pressure"] = circ_pump_colls
270 288
271 289
    if 'heat_exchanger' in net:
272 290
        if respect_in_service:
273 -
            hxc = create_heat_exchanger_collection(net, hex=net.heat_exchanger[net.heat_exchanger.in_service].index,
274 -
                                                   size=heat_exchanger_size, linewidths=pipe_width,
275 -
                                                   color=heat_exchanger_color)
291 +
            hxc = create_heat_exchanger_collection(
292 +
                net, heat_ex=net.heat_exchanger[net.heat_exchanger.in_service].index,
293 +
                size=heat_exchanger_size, linewidths=pipe_width, color=heat_exchanger_color)
276 294
        else:
277 -
            hxc = create_heat_exchanger_collection(net, size=heat_exchanger_size, linewidths=pipe_width,
278 -
                                                   color=heat_exchanger_color)
295 +
            hxc = create_heat_exchanger_collection(
296 +
                net, size=heat_exchanger_size, linewidths=pipe_width, color=heat_exchanger_color)
279 297
        collections["heat_exchanger"] = hxc
280 298
281 299
    if 'additional_collections' in kwargs:

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import os
@@ -12,7 +12,7 @@
Loading
12 12
13 13
logger = logging.getLogger(__name__)
14 14
15 -
heat_tranfer_modelica_path = os.path.join(pp_dir, "networks", "simple_test_networks",
15 +
heat_tranfer_modelica_path = os.path.join(pp_dir, "networks", "network_files",
16 16
                                   "openmodelica_test_networks", "heat_transfer_cases")
17 17
18 18
def heat_transfer_delta():

@@ -0,0 +1,74 @@
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 +
import pandas as pd
7 +
from pandapipes.multinet.multinet import MultiNet, get_default_multinet_structure
8 +
9 +
try:
10 +
    import pplog as logging
11 +
except ImportError:
12 +
    import logging
13 +
14 +
logger = logging.getLogger(__name__)
15 +
logger.setLevel(level=logging.WARNING)
16 +
17 +
18 +
def create_empty_multinet(name=""):
19 +
    """
20 +
    This function initializes the multinet datastructure.
21 +
22 +
    :param name: Name for the multi net
23 +
    :type name: string, default None
24 +
    :return: MultiNet with empty tables
25 +
    :rtype: MultiNet
26 +
27 +
    :Example:
28 +
        >>> mn = create_empty_multinet("my_first_multinet")
29 +
30 +
    """
31 +
    multinet = MultiNet(get_default_multinet_structure())
32 +
    multinet['controller'] = pd.DataFrame(np.zeros(0, dtype=multinet['controller']), index=[])
33 +
    multinet['name'] = name
34 +
    return multinet
35 +
36 +
37 +
def add_net_to_multinet(multinet, net, net_name='power', overwrite=False):
38 +
    """
39 +
    Add a pandapipes or pandapower net to the multinet structure.
40 +
41 +
    :param multinet: multinet to which a pandapipes/pandapower net will be added
42 +
    :type multinet: pandapipes.MultiNet
43 +
    :param net: pandapipes or pandapower net that will be added to the multinet
44 +
    :type net: pandapowerNet or pandapipesNet
45 +
    :param net_name: unique name for the added net, e.g. 'power', 'gas', or 'power_net1'
46 +
    :type net_name: str
47 +
    :param overwrite: whether a net should be overwritten if it has the same net_name
48 +
    :type overwrite: bool
49 +
    :return: net reference is added inplace to the multinet (in multinet['nets'])
50 +
    :rtype: None
51 +
    """
52 +
    if net_name in multinet['nets'] and not overwrite:
53 +
        logger.warning("A net with the name %s exists already in the multinet. If you want to "
54 +
                       "overwrite it, set 'overwrite' to True." % net_name)
55 +
    else:
56 +
        multinet['nets'][net_name] = net
57 +
58 +
59 +
def add_nets_to_multinet(multinet, overwrite=False, **networks):
60 +
    """
61 +
    Add multiple nets to a multinet. 'networks' has to be a dictionary.
62 +
63 +
    :param multinet: multinet to which several pandapipes/pandapower nets are added
64 +
    :type multinet: pandapipes.MultiNet
65 +
    :param overwrite: whether a net should be overwritten if it has the same net_name
66 +
    :type overwrite: bool
67 +
    :param networks: a dictionary with different pandapipes/pandapower nets as values. The keys
68 +
                     will be set in multinet.nets as net names for the different networks.
69 +
    :type networks: dict
70 +
    :return: net is added to multinet
71 +
    :rtype: None
72 +
    """
73 +
    for name, net in networks.items():
74 +
        add_net_to_multinet(multinet, net, name, overwrite)

@@ -0,0 +1,5 @@
Loading
1 +
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of 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 +
from .run_control_multinet import run_control

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
# physical constants

@@ -0,0 +1,100 @@
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 copy
6 +
7 +
import pandas as pd
8 +
from numpy import dtype
9 +
from pandapower import pandapowerNet
10 +
from pandapower.auxiliary import ADict
11 +
12 +
from pandapipes import __version__
13 +
from pandapipes import pandapipesNet
14 +
15 +
try:
16 +
    import pplog as logging
17 +
except ImportError:
18 +
    import logging
19 +
20 +
logger = logging.getLogger(__name__)
21 +
22 +
23 +
class MultiNet(ADict):
24 +
    """
25 +
    A 'MultiNet' is a frame for different pandapipes & pandapower nets and coupling controllers.
26 +
27 +
    Usually, a multinet is a multi energy net which one net per energy carrier. 
28 +
    The coupled simulation can be run with
29 +
    pandapipes.multinet.control.run_control_multinet.run_control()
30 +
    The nets are stored with a unique key in a dictionary in multinet['nets'].
31 +
    Controllers that connect to nets are stored in multinet['controller'].
32 +
    """
33 +
34 +
    def __init__(self, *args, **kwargs):
35 +
        """
36 +
37 +
        :param args: item of the ADict
38 +
        :type args: variable
39 +
        :param kwargs: item of the ADict with corresponding name
40 +
        :type kwargs: dict
41 +
        """
42 +
        super().__init__(*args, **kwargs)
43 +
        if isinstance(args[0], self.__class__):
44 +
            net = args[0]
45 +
            self.clear()
46 +
            self.update(**net.deepcopy())
47 +
48 +
    def deepcopy(self):
49 +
        return copy.deepcopy(self)
50 +
51 +
    def __repr__(self):  # pragma: no cover
52 +
        """
53 +
        defines the representation of the multinet in the console
54 +
55 +
        :return: representation
56 +
        :rtype: str
57 +
        """
58 +
59 +
        r = "This multi net includes following nets:"
60 +
        for cat in self.nets:
61 +
            if isinstance(self['nets'][cat], pandapowerNet):
62 +
                r += "\n   - %s (%s pandapowerNet)" % (cat, 1)
63 +
            elif isinstance(self['nets'][cat], pandapipesNet):
64 +
                r += "\n   - %s (%s pandapipesNet)" % (cat, 1)
65 +
            else:
66 +
                r += "\n   - %s (%s nets)" % (cat, len(self['nets'][cat]))
67 +
68 +
        par = []
69 +
        for tb in list(self.keys()):
70 +
            if isinstance(self[tb], pd.DataFrame) and len(self[tb]) > 0:
71 +
                par.append(tb)
72 +
            elif tb == 'std_type':
73 +
                par.append(tb)
74 +
        if par:
75 +
            r += "\nand the following parameter tables:"
76 +
            for tb in par:
77 +
                r += "\n   - %s (%s elements)" % (tb, len(self[tb]))
78 +
        return r
79 +
80 +
81 +
def get_default_multinet_structure():
82 +
    """
83 +
    Return the default structure of an empty multinet with categories and data types.
84 +
85 +
    :return: default structure of an empty multinet
86 +
    :rtype: dict
87 +
    """
88 +
    default_multinet_structure = {
89 +
        # structure data
90 +
        # f8, u4 etc. are probably referencing numba or numpy data types
91 +
        "name": "",
92 +
        "nets": dict(),
93 +
        "version": __version__,
94 +
        "controller": [('object', dtype(object)),
95 +
                       ('in_service', "bool"),
96 +
                       ('order', "float64"),
97 +
                       ('level', dtype(object)),
98 +
                       ('initial_run', "bool"),
99 +
                       ("recycle", "bool")]}
100 +
    return default_multinet_structure

@@ -1,4 +1,8 @@
Loading
1 -
from .component_models import *
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of 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 +
from .base_component import *
2 6
from .branch_models import *
3 7
from .branch_w_internals_models import *
4 8
from .branch_wo_internals_models import *
5 9
imilarity index 76%
6 10
ename from pandapipes/component_models/abstract_models/component_models.py
7 11
ename to pandapipes/component_models/abstract_models/base_component.py

@@ -1,24 +1,11 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
6 -
import copy
7 -
8 -
import pandas as pd
5 +
import numpy as np
9 6
from pandapipes.component_models import ExtGrid, Pipe, Sink, Source, Junction
10 7
from pandapower.plotting.generic_geodata import coords_from_igraph, \
11 -
                                                _prepare_geodata_table, \
12 -
                                                _get_element_mask_from_nodes,\
13 -
                                                _igraph_meshed
14 -
15 -
import numpy as np
16 -
try:
17 -
    import igraph
18 -
19 -
    IGRAPH_INSTALLED = True
20 -
except ImportError:
21 -
    IGRAPH_INSTALLED = False
8 +
    _prepare_geodata_table, _get_element_mask_from_nodes, _igraph_meshed
22 9
23 10
try:
24 11
    import pplog as logging
@@ -70,25 +57,20 @@
Loading
70 57
    for comp in net['component_list']:
71 58
        if comp in [Source, Sink, ExtGrid, Pipe, Junction]:
72 59
            continue
73 -
        mask = _get_element_mask_from_nodes(net, comp.table_name(),
74 -
                                            ["from_junction", "to_junction"], 
75 -
                                            junctions)
60 +
        mask = _get_element_mask_from_nodes(
61 +
            net, comp.table_name(), ["from_junction", "to_junction"], junctions)
76 62
        for comp_data in net[comp.table_name()][mask].itertuples():
77 63
            g.add_edge(pp_junction_mapping[comp_data.from_junction],
78 64
                       pp_junction_mapping[comp_data.to_junction],
79 65
                       weight=0.001)
80 66
81 -
82 67
    meshed = _igraph_meshed(g)
83 -
        
84 -
    roots = [pp_junction_mapping[s] for s in net.ext_grid.junction.values]
68 +
    roots = [pp_junction_mapping[s] for s in net.ext_grid.junction.values if s in junction_index]
85 69
    return g, meshed, roots  # g, (not g.is_dag())
86 70
87 71
88 -
def create_generic_coordinates(net, mg=None, library="igraph",
89 -
                               geodata_table="junction_geodata",
90 -
                               junctions=None,
91 -
                               overwrite=False):
72 +
def create_generic_coordinates(net, mg=None, library="igraph", geodata_table="junction_geodata",
73 +
                               junctions=None, overwrite=False):
92 74
    """
93 75
    This function will add arbitrary geo-coordinates for all junctions based on an analysis of
94 76
    branches and rings. It will remove out of service junctions/pipes from the net. The coordinates
@@ -112,10 +94,7 @@
Loading
112 94
    _prepare_geodata_table(net, geodata_table, overwrite)
113 95
114 96
    if library == "igraph":
115 -
        if not IGRAPH_INSTALLED:
116 -
            raise UserWarning("The library igraph is selected for plotting, but not installed "
117 -
                              "correctly.")
118 -
        graph, meshed, roots = build_igraph_from_ppipes(net)
97 +
        graph, meshed, roots = build_igraph_from_ppipes(net, junctions=junctions)
119 98
        coords = coords_from_igraph(graph, roots, meshed)
120 99
    elif library == "networkx":
121 100
        logger.warning("The networkx implementation is not working currently!")

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
# define bus types

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from .derivative_toolbox import *

@@ -1,9 +1,11 @@
Loading
1 -
import numpy as np
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of 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.
2 4
5 +
import numpy as np
3 6
4 7
def _sum_by_group_sorted(indices, *values):
5 -
    """
6 -
    Auxiliary function to sum up values by some given indices (both as numpy arrays). Expects the
8 +
    """Auxiliary function to sum up values by some given indices (both as numpy arrays). Expects the
7 9
    indices and values to already be sorted.
8 10
9 11
    :param indices:
@@ -13,7 +15,6 @@
Loading
13 15
    :return:
14 16
    :rtype:
15 17
    """
16 -
17 18
    # Index defines whether a specific index has already appeared in the index array before.
18 19
    index = np.ones(len(indices), 'bool')
19 20
    index[:-1] = indices[1:] != indices[:-1]
@@ -22,7 +23,7 @@
Loading
22 23
    indices = indices[index]
23 24
24 25
    val = list(values)
25 -
    for i in range(len(val)):
26 +
    for i, _ in enumerate(val):
26 27
        # sum up values, chose only those with unique indices and then subtract the previous sums
27 28
        # --> this way for each index the sum of all values belonging to this index is returned
28 29
        np.cumsum(val[i], out=val[i])
@@ -47,7 +48,7 @@
Loading
47 48
    order = np.argsort(indices)
48 49
    indices = indices[order]
49 50
    val = list(values)
50 -
    for i in range(len(val)):
51 +
    for i, _ in enumerate(val):
51 52
        val[i] = val[i][order]
52 53
53 54
    return _sum_by_group_sorted(indices, *val)

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import importlib
@@ -7,13 +7,14 @@
Loading
7 7
from functools import partial
8 8
from inspect import isclass
9 9
10 -
import pandapower as pp
10 +
from pandapipes.multinet.create_multinet import MultiNet, create_empty_multinet
11 11
from pandapipes.component_models.abstract_models import Component
12 -
from pandapipes.create import create_empty_network as create_fluid_network
12 +
from pandapipes.create import create_empty_network
13 13
from pandapipes.pandapipes_net import pandapipesNet
14 14
from pandapower.io_utils import pp_hook
15 15
from pandapower.io_utils import with_signature, to_serializable, JSONSerializableClass, \
16 16
    isinstance_partial as ppow_isinstance, FromSerializableRegistry, PPJSONDecoder
17 +
from copy import deepcopy
17 18
18 19
try:
19 20
    import pplog as logging
@@ -22,21 +23,6 @@
Loading
22 23
23 24
logger = logging.getLogger(__name__)
24 25
25 -
try:
26 -
    import fiona
27 -
    import geopandas
28 -
29 -
    GEOPANDAS_INSTALLED = True
30 -
except ImportError:
31 -
    GEOPANDAS_INSTALLED = False
32 -
33 -
try:
34 -
    import shapely.geometry
35 -
36 -
    SHAPELY_INSTALLED = True
37 -
except (ImportError, OSError):
38 -
    SHAPELY_INSTALLED = False
39 -
40 26
41 27
def isinstance_partial(obj, cls):
42 28
    if isinstance(obj, pandapipesNet):
@@ -45,22 +31,21 @@
Loading
45 31
46 32
47 33
class FromSerializableRegistryPpipe(FromSerializableRegistry):
48 -
    from_serializable = FromSerializableRegistry.from_serializable
34 +
    from_serializable = deepcopy(FromSerializableRegistry.from_serializable)
49 35
    class_name = ''
50 36
    module_name = ''
51 37
52 -
    def __init__(self, obj, d, net, ppipes_hook):
53 -
        super().__init__(obj, d, net, ppipes_hook)
38 +
    def __init__(self, obj, d, ppipes_hook):
39 +
        """
54 40
55 -
    @from_serializable.register(class_name='pandapowerNet', module_name='pandapower.auxiliary')
56 -
    def pandapowerNet(self):
57 -
        if isinstance(self.obj, str):  # backwards compatibility
58 -
            from pandapower import from_json_string
59 -
            return from_json_string(self.obj)
60 -
        else:
61 -
            net = pp.create_empty_network()
62 -
            net.update(self.obj)
63 -
            return net
41 +
        :param obj: object the data is written to
42 +
        :type obj: object
43 +
        :param d: data to be re-serialized
44 +
        :type d: any kind
45 +
        :param ppipes_hook: a way how to handle non-default data
46 +
        :type ppipes_hook: funct
47 +
        """
48 +
        super().__init__(obj, d, ppipes_hook)
64 49
65 50
    @from_serializable.register(class_name="method")
66 51
    def method(self):
@@ -76,8 +61,9 @@
Loading
76 61
            from pandapipes import from_json_string
77 62
            return from_json_string(self.obj)
78 63
        else:
79 -
            self.net.update(self.obj)
80 -
            return self.net
64 +
            net = create_empty_network()
65 +
            net.update(self.obj)
66 +
            return net
81 67
82 68
    @from_serializable.register()
83 69
    def rest(self):
@@ -86,16 +72,28 @@
Loading
86 72
        if isclass(class_) and issubclass(class_, JSONSerializableClass):
87 73
            if isinstance(self.obj, str):
88 74
                self.obj = json.loads(self.obj, cls=PPJSONDecoder,
89 -
                                      object_hook=partial(pp_hook, net=self.net,
75 +
                                      object_hook=partial(pp_hook,
90 76
                                                          registry_class=FromSerializableRegistryPpipe))
91 77
                                                          # backwards compatibility
92 -
            return class_.from_dict(self.obj, self.net)
78 +
            if "net" in self.obj:
79 +
                del self.obj["net"]
80 +
            return class_.from_dict(self.obj)
93 81
        if isclass(class_) and issubclass(class_, Component):
94 82
            return class_
95 83
        else:
96 84
            # for non-pp objects, e.g. tuple
97 85
            return class_(self.obj, **self.d)
98 86
87 +
    @from_serializable.register(class_name='MultiNet')
88 +
    def MultiNet(self):
89 +
        if isinstance(self.obj, str):  # backwards compatibility
90 +
            from pandapipes import from_json_string
91 +
            return from_json_string(self.obj)
92 +
        else:
93 +
            net = create_empty_multinet()
94 +
            net.update(self.obj)
95 +
            return net
96 +
99 97
100 98
@to_serializable.register(pandapipesNet)
101 99
def json_net(obj):
@@ -114,9 +112,8 @@
Loading
114 112
                           'class %s in @to_serializable.register(type)!' % class_))
115 113
116 114
117 -
if __name__ == '__main__':
118 -
    ntw = create_fluid_network()
119 -
    import pandapipes as pp
120 -
121 -
    pp.to_json(ntw, 'test.json')
122 -
    ntw = pp.from_json('test.json')
115 +
@to_serializable.register(MultiNet)
116 +
def json_net(obj):
117 +
    net_dict = {k: item for k, item in obj.items() if not k.startswith("_")}
118 +
    d = with_signature(obj, net_dict)
119 +
    return d

@@ -1,19 +1,20 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 +
from numpy import dtype
6 7
from pandapipes.component_models.abstract_models.node_element_models import NodeElementComponent
7 8
from pandapipes.idx_node import LOAD, ELEMENT_IDX
8 -
from pandapipes.pipeflow_setup import get_lookup
9 9
from pandapipes.internals_toolbox import _sum_by_group
10 -
from numpy import dtype
10 +
from pandapipes.pipeflow_setup import get_lookup
11 11
12 12
13 13
class ConstFlow(NodeElementComponent):
14 -
    """
15 14
16 -
    """
15 +
    @classmethod
16 +
    def table_name(cls):
17 +
        raise NotImplementedError
17 18
18 19
    @classmethod
19 20
    def sign(cls):
@@ -28,6 +29,8 @@
Loading
28 29
        :type net: pandapipesNet
29 30
        :param node_pit:
30 31
        :type node_pit:
32 +
        :param node_name:
33 +
        :type node_name:
31 34
        :return: No Output.
32 35
        """
33 36
        loads = net[cls.table_name()]
@@ -48,6 +51,8 @@
Loading
48 51
        :type net: pandapipesNet
49 52
        :param options:
50 53
        :type options:
54 +
        :param node_name:
55 +
        :type node_name:
51 56
        :return: No Output.
52 57
        """
53 58
        res_table = super().extract_results(net, options, node_name)
@@ -71,13 +76,12 @@
Loading
71 76
        :return:
72 77
        :rtype:
73 78
        """
74 -
        input = [("name", dtype(object)),
75 -
                 ("junction", "u4"),
76 -
                 ("mdot_kg_per_s", "f8"),
77 -
                 ("scaling", "f8"),
78 -
                 ("in_service", "bool"),
79 -
                 ("type", dtype(object))]
80 -
        return input
79 +
        return [("name", dtype(object)),
80 +
                ("junction", "u4"),
81 +
                ("mdot_kg_per_s", "f8"),
82 +
                ("scaling", "f8"),
83 +
                ("in_service", "bool"),
84 +
                ("type", dtype(object))]
81 85
82 86
    @classmethod
83 87
    def get_result_table(cls, net):

@@ -1,8 +1,7 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
6 5
def get_collection_sizes(net, junction_size=1.0, ext_grid_size=1.0, sink_size=1.0, source_size=1.0,
7 6
                         valve_size=2.0, pump_size=1.0, heat_exchanger_size=1.0):
8 7
    """

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from pandapipes.component_models.abstract_models.branch_wo_internals_models import \
@@ -19,6 +19,34 @@
Loading
19 19
20 20
    """
21 21
22 +
    @classmethod
23 +
    def table_name(cls):
24 +
        raise NotImplementedError
25 +
26 +
    @classmethod
27 +
    def get_component_input(cls):
28 +
        raise NotImplementedError
29 +
30 +
    @classmethod
31 +
    def get_result_table(cls, net):
32 +
        raise NotImplementedError
33 +
34 +
    @classmethod
35 +
    def active_identifier(cls):
36 +
        raise NotImplementedError
37 +
38 +
    @classmethod
39 +
    def from_to_node_cols(cls):
40 +
        raise NotImplementedError
41 +
42 +
    @classmethod
43 +
    def calculate_pressure_lift(cls, net, pipe_pit, node_pit):
44 +
        raise NotImplementedError
45 +
46 +
    @classmethod
47 +
    def calculate_temperature_lift(cls, net, pipe_pit, node_pit):
48 +
        raise NotImplementedError
49 +
22 50
    @classmethod
23 51
    def create_pit_branch_entries(cls, net, branch_wzerolength_pit, node_name):
24 52
        """
@@ -26,10 +54,10 @@
Loading
26 54
27 55
        :param net: The pandapipes network
28 56
        :type net: pandapipesNet
29 -
        :param valve_pit:
30 -
        :type valve_pit:
31 -
        :param internal_pipe_number:
32 -
        :type internal_pipe_number:
57 +
        :param branch_wzerolength_pit:
58 +
        :type branch_wzerolength_pit:
59 +
        :param node_name:
60 +
        :type node_name:
33 61
        :return: No Output.
34 62
        """
35 63
        branch_wizerolength_pit = \

@@ -1,14 +1,13 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 +
from numpy import dtype
6 7
from pandapipes.component_models.abstract_models import CirculationPump
7 8
from pandapipes.idx_node import PINIT, NODE_TYPE, P, EXT_GRID_OCCURENCE
8 -
from pandapipes.pipeflow_setup import get_lookup
9 -
from numpy import dtype
10 -
11 9
from pandapipes.internals_toolbox import _sum_by_group
10 +
from pandapipes.pipeflow_setup import get_lookup
12 11
13 12
try:
14 13
    import pplog as logging
@@ -33,6 +32,8 @@
Loading
33 32
        :type net: pandapipesNet
34 33
        :param node_pit:
35 34
        :type node_pit:
35 +
        :param node_name:
36 +
        :type node_name:
36 37
        :return: No Output.
37 38
        """
38 39
        circ_pump, press = super().create_pit_node_entries(net, node_pit, node_name)

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import os

@@ -0,0 +1,5 @@
Loading
1 +
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of 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 +
from .run_time_series_multinet import run_timeseries

@@ -1,11 +1,11 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 6
import pandas as pd
7 -
from pandapipes.constants import NORMAL_PRESSURE, R_UNIVERSAL, \
8 -
    MOLAR_MASS_AIR, GRAVITATION_CONSTANT, TEMP_GRADIENT_KPM, AVG_TEMPERATURE_K, HEIGHT_EXPONENT
7 +
from pandapipes.constants import NORMAL_PRESSURE, TEMP_GRADIENT_KPM, AVG_TEMPERATURE_K, \
8 +
    HEIGHT_EXPONENT
9 9
10 10
11 11
def p_correction_height_air(height):

@@ -0,0 +1,523 @@
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 +
from pandapower.control import ConstControl
6 +
from pandapipes import get_fluid
7 +
from pandapower.control.basic_controller import Controller
8 +
9 +
10 +
class P2GControlMultiEnergy(Controller):
11 +
12 +
    """
13 +
    A controller to be used in a multinet. Converts power consumption to gas production.
14 +
15 +
    This controller couples a power network (from pandapower) and a gas network (from
16 +
    pandapipes) that are stored in a multinet. Requires one or multiple 'load' elements in the
17 +
    power net and as many corresponding 'source' elements in the gas net. It reads the power load
18 +
    values for given 'load' elements, applies the efficiency factor and unit conversions and
19 +
    writes the resulting gas mass flow to 'source' elements in the gas net.
20 +
    It is stored in the controller-DataFrame of the multinet (multinet.controller).
21 +
    It is run by run_control_multinet.run_control() or within
22 +
    run_time_series_multinet.run_timeseries().
23 +
24 +
    :param multinet: pandapipes-Mulitnet that includes the power and gas network with load and
25 +
                     source elements
26 +
    :type multinet: attrdict (pandapipes.MultiNet)
27 +
    :param element_index_power: Index of one or more load elements in the power net from which
28 +
                                the power consumption will be read. For each load element,
29 +
                                a corresponding source element has to be provided in
30 +
                                element_index_gas.
31 +
    :type element_index_power: int or iterable of integers
32 +
    :param element_index_gas: Index of one or more source elements in the gas net to which the
33 +
                              calculated mass flow will be written. For each source element,
34 +
                              a corresponing el. load element has to be provided in
35 +
                              element_index_power.
36 +
    :type element_index_gas: int or iterable of integers
37 +
    :param efficiency: constant efficiency factor (default: based on HHV)
38 +
    :type efficiency: float
39 +
    :param name_power_net: Key name to find the power net in multinet['nets']
40 +
    :type name_power_net: str
41 +
    :param name_gas_net: Key name to find the gas net in multinet['nets']
42 +
    :type name_gas_net: str
43 +
    :param in_service: Indicates if the controllers are currently in_service
44 +
    :type in_service: bool
45 +
    :param order: within the same level, controllers with lower order are called before controllers
46 +
                  with numerical higher order
47 +
    :type order: real
48 +
    :param level: level to which the controller belongs. Low level is called before higher level.
49 +
                  Respective run function for the nets are called at least once per level.
50 +
    :type level: real
51 +
    :param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and
52 +
                                    with the same matching parameters (e.g. at same element) should
53 +
                                    be dropped
54 +
    :type drop_same_existing_ctrl: bool
55 +
    :param initial_run: Whether a power and pipe flow should be run before the control step is
56 +
                        applied or not
57 +
    :type initial_run: bool
58 +
    :param kwargs: optional additional controller arguments that were implemented by users
59 +
    :type kwargs: any
60 +
    """
61 +
    def __init__(self, multinet, element_index_power, element_index_gas, efficiency,
62 +
                 name_power_net='power', name_gas_net='gas',
63 +
                 in_service=True, order=0, level=0,
64 +
                 drop_same_existing_ctrl=False, initial_run=True, **kwargs):
65 +
        """
66 +
        see class docstring
67 +
        """
68 +
        super().__init__(multinet, in_service, order, level,
69 +
                         drop_same_existing_ctrl=drop_same_existing_ctrl, initial_run=initial_run,
70 +
                         **kwargs)
71 +
72 +
        self.elm_idx_power = element_index_power
73 +
        self.elm_idx_gas = element_index_gas
74 +
        self.name_net_power = name_power_net
75 +
        self.name_net_gas = name_gas_net
76 +
        self.efficiency = efficiency
77 +
        self.mdot_kg_per_s = None
78 +
        self.fluid = get_fluid(multinet['nets'][name_gas_net])
79 +
        self.fluid_calorific_value = self.fluid.get_property('hhv')
80 +
        self.applied = False
81 +
82 +
    def initialize_control(self, multinet):
83 +
        self.applied = False
84 +
85 +
    def get_all_net_names(self):
86 +
        return [self.name_net_power, self.name_net_gas]
87 +
88 +
    def control_step(self, multinet):
89 +
        try:
90 +
            power_load = multinet['nets'][self.name_net_power].load.at[self.elm_idx_power, 'p_mw']
91 +
        except (ValueError, TypeError):
92 +
            power_load = multinet['nets'][self.name_net_power].load.loc[self.elm_idx_power, 'p_mw'].values
93 +
        self.mdot_kg_per_s = power_load * self.conversion_factor_mw_to_kgps() * self.efficiency
94 +
        self.write_to_net(multinet)
95 +
        self.applied = True
96 +
97 +
    def write_to_net(self, multinet):
98 +
        try:
99 +
            multinet['nets'][self.name_net_gas].source.at[self.elm_idx_gas, 'mdot_kg_per_s'] \
100 +
                = self.mdot_kg_per_s
101 +
        except (ValueError, TypeError):
102 +
            multinet['nets'][self.name_net_gas].source.loc[self.elm_idx_gas,
103 +
                                                           'mdot_kg_per_s'].values[:] = self.mdot_kg_per_s
104 +
105 +
    def is_converged(self, multinet):
106 +
        return self.applied
107 +
108 +
    def conversion_factor_mw_to_kgps(self):
109 +
        return 1e3 / (self.fluid_calorific_value * 3600)
110 +
111 +
112 +
class G2PControlMultiEnergy(Controller):
113 +
114 +
    """
115 +
    A controller to be used in a multinet. Connects power generation and gas consumption.
116 +
117 +
    This controller couples a gas network (from pandapipes) and a power network (from
118 +
    pandapower) that are stored in a multinet. Requires one or multiple 'sink' elements in the gas
119 +
    net and as many corresponding 'sgen'/'gen' elements in the power net.
120 +
    If 'calc_gas_from_power' is False (default), it reads the gas mass consumption values
121 +
    of given 'sink' elements, applies the efficiency factor and unit conversions and writes the
122 +
    resulting power output to 'sgen' (default) or 'gen' elements in the power net.
123 +
    If 'calc_gas_from_power' is True, it reads the power output of
124 +
    given 'sgen' (default) or 'gen' elements, calculates the corresponding gas consumption by
125 +
    appling the efficiency factor and unit conversions, and writes the resulting gas consumption
126 +
    mass flow to the given 'sink' elements in the gas net.
127 +
    It is stored in the controller-DataFrame of the multinet (multinet.controller).
128 +
    It is run by run_control_multinet.run_control() or within
129 +
    run_time_series_multinet.run_timeseries().
130 +
131 +
    :param multinet: pandapipes-Mulitnet that includes the power and gas network with sgen/gen and
132 +
                     sink elements
133 +
    :type multinet: attrdict (pandapipes.MultiNet)
134 +
    :param element_index_power: Index of one or more elements in the power net from which
135 +
                                the power generation will be read from or written to (either
136 +
                                'sgen' or 'gen' elements, as defined by element_type_power).
137 +
                                For each entry, a corresponding gas sink element has to be
138 +
                                provided in element_index_gas.
139 +
    :type element_index_power: int or iterable of integers
140 +
    :param element_index_gas: Index of one or more sink elements in the gas net from which the
141 +
                              G2P units' gas consumption (mass flow) is read from or written to.
142 +
                              For each sink element, a corresponding sgen/gen element has to be
143 +
                              provided in element_index_power.
144 +
    :type element_index_gas: int or iterable of integers
145 +
    :param efficiency: constant efficiency factor (default: based on HHV)
146 +
    :type efficiency: float
147 +
    :param name_power_net: Key name to find the power net in multinet['nets']
148 +
    :type name_power_net: str
149 +
    :param name_gas_net: Key name to find the gas net in multinet['nets']
150 +
    :type name_gas_net: str
151 +
    :param element_type_power: type of the corresponding power generation units, either 'sgen' or 'gen'
152 +
    :type element_type_power: str
153 +
    :param in_service: Indicates if the controllers are currently in_service
154 +
    :type in_service: bool
155 +
    :param order: within the same level, controllers with lower order are called before controllers
156 +
                  with numerical higher order
157 +
    :type order: int or float
158 +
    :param level: level to which the controller belongs. Low level is called before higher level.
159 +
                  Respective run function for the nets are called at least once per level.
160 +
    :type level: int or float
161 +
    :param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and
162 +
                                    with the same matching parameters (e.g. at same element) should
163 +
                                    be dropped
164 +
    :type drop_same_existing_ctrl: bool
165 +
    :param initial_run: Whether a power and pipe flow should be run before the control step is
166 +
                        applied or not
167 +
    :type initial_run: bool
168 +
    :param calc_gas_from_power: (default: False) If False, the power output will be calculated on the
169 +
                                basis of the sink's gas consumption. If True, the gas consumption
170 +
                                will be calculated on the basis of the generator's power output.
171 +
    :type calc_gas_from_power: bool
172 +
    :param kwargs: optional additional controller arguments that were implemented by users
173 +
    :type kwargs: any
174 +
    """
175 +
176 +
    def __init__(self, multinet, element_index_power, element_index_gas, efficiency,
177 +
                 name_power_net='power', name_gas_net='gas', element_type_power="sgen",
178 +
                 in_service=True, order=0,
179 +
                 level=0, drop_same_existing_ctrl=False, initial_run=True,
180 +
                 calc_gas_from_power=False, **kwargs):
181 +
        """
182 +
        see class docstring
183 +
        """
184 +
        super().__init__(multinet, in_service, order, level,
185 +
                         drop_same_existing_ctrl=drop_same_existing_ctrl, initial_run=initial_run,
186 +
                         **kwargs)
187 +
188 +
        self.elm_idx_power = element_index_power
189 +
        self.elm_idx_gas = element_index_gas
190 +
        self.elm_type_power = element_type_power
191 +
        self.name_net_power = name_power_net
192 +
        self.name_net_gas = name_gas_net
193 +
        self.efficiency = efficiency
194 +
        self.mdot_kg_per_s = None
195 +
        self.fluid = get_fluid(multinet['nets'][name_gas_net])
196 +
        self.fluid_calorific_value = self.fluid.get_property('hhv')
197 +
        self.el_power_led = calc_gas_from_power
198 +
        self.applied = False
199 +
200 +
    def initialize_control(self, multinet):
201 +
        self.applied = False
202 +
203 +
    def get_all_net_names(self):
204 +
        return [self.name_net_gas, self.name_net_power]
205 +
206 +
    def control_step(self, multinet):
207 +
        if self.el_power_led:
208 +
            try:
209 +
                power_gen = multinet['nets'][self.name_net_power][self.elm_type_power].at[
210 +
                    self.elm_idx_power, 'p_mw']
211 +
            except (ValueError, TypeError):
212 +
                power_gen = multinet['nets'][self.name_net_power][self.elm_type_power].loc[
213 +
                                self.elm_idx_power, 'p_mw'].values[:]
214 +
215 +
            self.gas_cons = power_gen / (self.conversion_factor_kgps_to_mw() * self.efficiency)
216 +
217 +
        else:
218 +
            try:
219 +
                gas_sink = multinet['nets'][self.name_net_gas].sink.at[self.elm_idx_gas,
220 +
                                                                       'mdot_kg_per_s']
221 +
            except (ValueError, TypeError):
222 +
                gas_sink = multinet['nets'][self.name_net_gas].sink.loc[self.elm_idx_gas,
223 +
                                                                        'mdot_kg_per_s'].values[:]
224 +
225 +
            self.power_gen = gas_sink * self.conversion_factor_kgps_to_mw() * self.efficiency
226 +
227 +
        self.write_to_net(multinet)
228 +
        self.applied = True
229 +
230 +
    def write_to_net(self, multinet):
231 +
        if self.el_power_led:
232 +
            try:
233 +
                multinet['nets'][self.name_net_gas].sink.at[self.elm_idx_gas,
234 +
                                                            'mdot_kg_per_s'] = self.gas_cons
235 +
            except (ValueError, TypeError):
236 +
                multinet['nets'][self.name_net_gas].sink.loc[self.elm_idx_gas,
237 +
                                                             'mdot_kg_per_s'] = self.gas_cons
238 +
        else:
239 +
            try:
240 +
                multinet['nets'][self.name_net_power][self.elm_type_power].at[
241 +
                    self.elm_idx_power, 'p_mw'] = self.power_gen
242 +
            except (ValueError, TypeError):
243 +
                multinet['nets'][self.name_net_power][self.elm_type_power].loc[
244 +
                    self.elm_idx_power, 'p_mw'] = self.power_gen
245 +
246 +
    def is_converged(self, multinet):
247 +
        return self.applied
248 +
249 +
    def conversion_factor_kgps_to_mw(self):
250 +
        return self.fluid_calorific_value * 3600 / 1e3
251 +
252 +
253 +
class GasToGasConversion(Controller):
254 +
255 +
    """
256 +
    A controller to be used in a multinet with two gas nets that have different gases.
257 +
258 +
    This controller represents a gas conversion unit (e.g. methanization or steam methane reformer)
259 +
    and couples two pandapipes-gas networks that are stored together in a multinet.
260 +
    Requires one or multiple sinks in one net ('gas_net_from') and as many corresponding sources
261 +
    in the other net ('gas_net_to').
262 +
    It reads the gas consumption values for given 'sink' elements in one gas net, applies the
263 +
    efficiency factor and writes the resulting gas mass flow to 'source' elements in the other
264 +
    gas net.
265 +
    It is stored in the controller-DataFrame of the multinet (multinet.controller).
266 +
    It is run by run_control_multinet.run_control() or within
267 +
    run_time_series_multinet.run_timeseries().
268 +
269 +
    :param multinet: pandapipes-Mulitnet that includes the gas networks that will be coupled with \
270 +
                     sink and source elements
271 +
    :type multinet: attrdict (pandapipes.MultiNet)
272 +
    :param element_index_from: Index of one or more sink elements in the name_gas_net_from from \
273 +
                               which the gas consumption will be read
274 +
    :type element_index_from: int or iterable of integers
275 +
    :param element_index_to: Index of one or more source elements in the name_gas_net_to to which the \
276 +
                             calculated mass flow will be written
277 +
    :type element_index_to: int or iterable of integers
278 +
    :param efficiency: constant efficiency factor (default: based on HHV)
279 +
    :type efficiency: float
280 +
    :param name_gas_net_from: Key name to find the gas net from which gas is consumed in \
281 +
                              multinet['nets']
282 +
    :type name_gas_net_from: str
283 +
    :param name_gas_net_to: Key name to find the gas net in which gas is fed into in \
284 +
                            multinet['nets']
285 +
    :type name_gas_net_to: str
286 +
    :param in_service: Indicates if the controllers are currently in_service
287 +
    :type in_service: bool
288 +
    :param order: within the same level, controllers with lower order are called before controllers
289 +
                  with numerical higher order
290 +
    :type order: int or float
291 +
    :param level: level to which the controller belongs. Low level is called before higher level.
292 +
                  Respective run function for the nets are called at least once per level.
293 +
    :type level: int or float
294 +
    :param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and
295 +
                                    with the same matching parameters (e.g. at same element) should
296 +
                                    be dropped
297 +
    :type drop_same_existing_ctrl: bool
298 +
    :param initial_run: Whether a power and pipe flow should be run before the control step is
299 +
                        applied or not
300 +
    :type initial_run: bool
301 +
    :param kwargs: optional additional controller arguments that were implemented by users
302 +
    :type kwargs: any
303 +
    """
304 +
305 +
    def __init__(self, multinet, element_index_from, element_index_to, efficiency,
306 +
                 name_gas_net_from='gas1', name_gas_net_to='gas2', in_service=True, order=0,
307 +
                 level=0, drop_same_existing_ctrl=False, initial_run=True, **kwargs):
308 +
        """
309 +
        see class docstring
310 +
        """
311 +
        super().__init__(multinet, in_service, order, level,
312 +
                         drop_same_existing_ctrl=drop_same_existing_ctrl, initial_run=initial_run,
313 +
                         **kwargs)
314 +
315 +
        self.element_index_from = element_index_from
316 +
        self.element_index_to = element_index_to
317 +
        self.name_net_from = name_gas_net_from
318 +
        self.name_net_to = name_gas_net_to
319 +
        self.efficiency = efficiency
320 +
        self.gas1_calorific_value = get_fluid(multinet['nets'][name_gas_net_from]).get_property('hhv')
321 +
        self.gas2_calorific_value = get_fluid(multinet['nets'][name_gas_net_to]).get_property('hhv')
322 +
        self.applied = False
323 +
324 +
    def initialize_control(self, multinet):
325 +
        self.applied = False
326 +
327 +
    def get_all_net_names(self):
328 +
        return [self.name_net_from, self.name_net_to]
329 +
330 +
    def control_step(self, multinet):
331 +
        try:
332 +
            gas_in = multinet['nets'][self.name_net_from].sink.at[self.element_index_from, 'mdot_kg_per_s']
333 +
        except (ValueError, TypeError):
334 +
            gas_in = multinet['nets'][self.name_net_from].sink.loc[self.element_index_from, 'mdot_kg_per_s'].values
335 +
336 +
        self.mdot_kg_per_s_out = gas_in * self.conversion_factor_gas1_to_gas2() * self.efficiency
337 +
        self.write_to_net(multinet)
338 +
        self.applied = True
339 +
340 +
    def write_to_net(self, multinet):
341 +
        try:
342 +
            multinet['nets'][self.name_net_to].source.at[self.element_index_to, 'mdot_kg_per_s'] \
343 +
                = self.mdot_kg_per_s_out
344 +
        except (ValueError, TypeError):
345 +
            multinet['nets'][self.name_net_to].source.loc[self.element_index_to,
346 +
                                                          'mdot_kg_per_s'].values[:] = self.mdot_kg_per_s_out
347 +
348 +
    def is_converged(self, multinet):
349 +
        return self.applied
350 +
351 +
    def conversion_factor_gas1_to_gas2(self):
352 +
        """Ideal conversion with energy conservation."""
353 +
        return self.gas1_calorific_value / self.gas2_calorific_value
354 +
355 +
356 +
def coupled_p2g_const_control(multinet, element_index_power, element_index_gas, p2g_efficiency,
357 +
                              name_power_net='power', name_gas_net='gas', profile_name=None,
358 +
                              data_source=None, scale_factor=1.0, in_service=True,
359 +
                              order=(0, 1), level=0, drop_same_existing_ctrl=False,
360 +
                              matching_params=None, initial_run=False, **kwargs):
361 +
    """
362 +
    Creates a ConstController (load values) and a P2G Controller (corresponding gas mass flows).
363 +
364 +
    The ConstController updates load values of a given electric load in accordance to the profile
365 +
    given in the datasource.
366 +
    The P2GControlMultiEnergy-controller couples a power network (from pandapower) and a gas
367 +
    network (from pandapipes). It reads the power load values that were updated by the
368 +
    ConstController, applies the efficiency factor and unit conversions and writes the resulting
369 +
    gas mass flow to 'source' elements in the gas net.
370 +
    The ConstController is stored in the power net inside the multinet.
371 +
    The P2GControlMultiEnergy is stored in the controller-DataFrame of the multinet
372 +
    (multinet.controller).
373 +
    Both controllers are run by run_control_multinet.run_control() or within
374 +
    run_time_series_multinet.run_timeseries().
375 +
376 +
    :param multinet: pandapipes-Mulitnet that includes the power and gas network with load and
377 +
                     source elements
378 +
    :type multinet: attrdict (pandapipes.MultiNet)
379 +
    :param element_index_power: Index of one or more load elements in the power net to which
380 +
                                the load values from the data source will be written
381 +
    :type element_index_power: int or iterable of integers
382 +
    :param element_index_gas: Index of one or more source elements in the gas net to which the
383 +
                              corresponding calculated mass flow will be written
384 +
    :param p2g_efficiency: constant efficiency factor (default: based on HHV)
385 +
    :type p2g_efficiency: float
386 +
    :param name_power_net: Key name to find the power net in multinet['nets']
387 +
    :type name_power_net: str
388 +
    :param name_gas_net: Key name to find the gas net in multinet['nets']
389 +
    :type name_gas_net: str
390 +
    :param profile_name: The profile names of the elements in the data source
391 +
    :type profile_name: str
392 +
    :param data_source: The data source that provides profile data
393 +
    :type data_source: object
394 +
    :param scale_factor: Scaling factor for time series input values
395 +
    :type scale_factor: real
396 +
    :param in_service: Indicates if the controller is currently in_service
397 +
    :type in_service: bool
398 +
    :param order: within the same level, controllers with lower order are called before controllers
399 +
                  with numerical higher order. Default: (0, 1) -> ConstController updates values
400 +
                  before P2G controller calculates mass flow
401 +
    :type order: tuple of integers
402 +
    :param level: level to which the controllers belong. Low level is called before higher level.
403 +
                  Respective run function for the nets are called at least once per level.
404 +
    :type level: int or float
405 +
    :param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and
406 +
                                    with the same matching parameters (e.g. at same element) should
407 +
                                    be dropped
408 +
    :type drop_same_existing_ctrl: bool
409 +
    :param matching_params: is required to check if same controller already exists (dropping or logging)
410 +
    :type matching_params: dict
411 +
    :param initial_run: Whether a power and pipe flow should be run before the control step is
412 +
                        applied or not
413 +
    :type initial_run: bool
414 +
    :param kwargs: optional additional controller arguments that were implemented by users
415 +
    :type kwargs:
416 +
    :return: (ID of the ConstController, ID of P2G controller)
417 +
    :rtype:
418 +
    """
419 +
    net_power = multinet['nets'][name_power_net]
420 +
421 +
    const = ConstControl(
422 +
        net_power, element='load', variable='p_mw', element_index=element_index_power,
423 +
        profile_name=profile_name, data_source=data_source, scale_factor=scale_factor,
424 +
        in_service=in_service, order=order[0], level=level,
425 +
        drop_same_existing_ctrl=drop_same_existing_ctrl, matching_params=matching_params,
426 +
        initial_run=initial_run, **kwargs)
427 +
428 +
    p2g = P2GControlMultiEnergy(multinet, element_index_power, element_index_gas, p2g_efficiency,
429 +
                                name_power_net, name_gas_net,
430 +
                                in_service, order[1], level,
431 +
                                drop_same_existing_ctrl=drop_same_existing_ctrl,
432 +
                                initial_run=initial_run, **kwargs)
433 +
    return const, p2g
434 +
435 +
436 +
def coupled_g2p_const_control(multinet, element_index_power, element_index_gas, g2p_efficiency=0.6,
437 +
                              name_power_net='power', name_gas_net='gas', element_type_power="sgen",
438 +
                              profile_name=None, data_source=None, scale_factor=1.0, power_led=False,
439 +
                              in_service=True, order=(0, 1), level=0, drop_same_existing_ctrl=False,
440 +
                              matching_params=None, initial_run=False, **kwargs):
441 +
    """
442 +
    Creates a ConstController (gas consumption) and a G2P Controller (corresponding power output).
443 +
444 +
    The ConstController updates gas consumption values of a given sink element in accordance to
445 +
    the profile given in the datasource.
446 +
    The G2PControlMultiEnergy-controller couples a gas network (from pandapipes) and a power
447 +
    network (from pandapower). It reads the gas consumption values that were updated by the
448 +
    ConstController, applies the efficiency factor and unit conversions and writes the resulting
449 +
    power output to 'sgen' or 'gen' elements in the power net.
450 +
    The ConstController is stored in the gas net inside the multinet.
451 +
    The G2PControlMultiEnergy is stored in the controller-DataFrame of the multinet itself
452 +
    (multinet.controller).
453 +
    Both controllers are run by run_control_multinet.run_control() or within
454 +
    run_time_series_multinet.run_timeseries().
455 +
456 +
    :param multinet: pandapipes-Mulitnet that includes the power and gas network with load and
457 +
                     source elements
458 +
    :type multinet: attrdict (pandapipes.MultiNet)
459 +
    :param element_index_power: Index of one or more sgen/gen elements in the power net to which
460 +
                                the power generation values from the data source will be written
461 +
    :type element_index_power: int or iterable of integers
462 +
    :param element_index_gas: Index of one or more sink elements in the gas net to which the
463 +
                              corresponding calculated mass flow will be written
464 +
    :param g2p_efficiency: constant efficiency factor (default: based on HHV)
465 +
    :type g2p_efficiency: float
466 +
    :param name_power_net: Key name to find the power net in multinet['nets']
467 +
    :type name_power_net: str
468 +
    :param name_gas_net: Key name to find the gas net in multinet['nets']
469 +
    :type name_gas_net: str
470 +
    :param element_type_power: type of the corresponding power generation units, either 'sgen' or 'gen'
471 +
    :type element_type_power: str
472 +
    :param profile_name: The profile names of the elements in the data source
473 +
    :type profile_name: str
474 +
    :param data_source: The data source that provides profile data
475 +
    :type data_source: object
476 +
    :param scale_factor: Scaling factor for time series input values
477 +
    :type scale_factor: real
478 +
    :param in_service: Indicates if the controllers are currently in_service
479 +
    :type in_service: bool
480 +
    :param order: within the same level, controllers with lower order are called before controllers
481 +
                  with numerical higher order. Default: (0, 1) -> ConstController updates values
482 +
                  before G2P controller calculates power output
483 +
    :type order: tuple of integers
484 +
    :param level: level to which the controllers belong. Low level is called before higher level.
485 +
                  Respective run function for the nets are called at least once per level.
486 +
    :type level: real
487 +
    :param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and
488 +
                                    with the same matching parameters (e.g. at same element) should
489 +
                                    be dropped
490 +
    :type drop_same_existing_ctrl: bool
491 +
    :param matching_params: is required to check if same controller already exists (dropping or logging)
492 +
    :type matching_params: dict
493 +
    :param initial_run: Whether a power and pipe flow should be run before the control step is
494 +
                        applied or not
495 +
    :type initial_run: bool
496 +
    :param kwargs: optional additional controller arguments that were implemented by users
497 +
    :type kwargs:
498 +
    :return: (ID of the ConstController, ID of G2P controller)
499 +
    :rtype:
500 +
    """
501 +
    if power_led:
502 +
        net_power = multinet['nets'][name_power_net]
503 +
504 +
        const = ConstControl(
505 +
            net_power, element='sgen', variable='p_mw', element_index=element_index_power,
506 +
            profile_name=profile_name, data_source=data_source, scale_factor=scale_factor,
507 +
            in_service=in_service, order=order[0], level=level,
508 +
            drop_same_existing_ctrl=drop_same_existing_ctrl, matching_params=matching_params,
509 +
            initial_run=initial_run, **kwargs)
510 +
    else:
511 +
        net_gas = multinet['nets'][name_gas_net]
512 +
        const = ConstControl(
513 +
            net_gas, element='sink', variable='mdot_kg_per_s', element_index=element_index_gas,
514 +
            profile_name=profile_name, data_source=data_source,
515 +
            scale_factor=scale_factor, in_service=in_service, order=order[0], level=level,
516 +
            drop_same_existing_ctrl=drop_same_existing_ctrl, matching_params=matching_params,
517 +
            initial_run=initial_run, **kwargs)
518 +
    g2p = G2PControlMultiEnergy(multinet, element_index_power, element_index_gas, g2p_efficiency,
519 +
                                name_power_net, name_gas_net, element_type_power,
520 +
                                in_service, order[1], level,
521 +
                                drop_same_existing_ctrl=drop_same_existing_ctrl,
522 +
                                initial_run=initial_run, calc_gas_from_power=power_led, **kwargs)
523 +
    return const, g2p

@@ -1,16 +1,13 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 -
from pandapipes.component_models.abstract_models import CirculationPump
7 -
from pandapipes.idx_node import PINIT, NODE_TYPE, P, LOAD, EXT_GRID_OCCURENCE, TINIT, NODE_TYPE_T, \
8 -
    EXT_GRID_OCCURENCE_T, T
9 -
from pandapipes.idx_branch import FROM_NODE, TO_NODE, LOAD_VEC_NODES
10 -
from pandapipes.pipeflow_setup import get_lookup, get_fluid
11 6
from numpy import dtype
12 -
7 +
from pandapipes.component_models.abstract_models import CirculationPump
8 +
from pandapipes.idx_node import LOAD
13 9
from pandapipes.internals_toolbox import _sum_by_group
10 +
from pandapipes.pipeflow_setup import get_lookup
14 11
15 12
try:
16 13
    import pplog as logging
@@ -35,9 +32,11 @@
Loading
35 32
        :type net: pandapipesNet
36 33
        :param node_pit:
37 34
        :type node_pit:
35 +
        :param node_name:
36 +
        :type node_name:
38 37
        :return: No Output.
39 38
        """
40 -
        circ_pump, press = super().create_pit_node_entries(net, node_pit, node_name)
39 +
        circ_pump, _ = super().create_pit_node_entries(net, node_pit, node_name)
41 40
42 41
        mf = np.nan_to_num(circ_pump.mdot_kg_per_s.values)
43 42
        mass_flow_loads = mf * circ_pump.in_service.values

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
TABLE_IDX = 0  # number of the table that this branch belongs to

@@ -1,19 +1,16 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
import numpy as np
6 -
from numpy import dtype
7 5
from operator import itemgetter
8 6
7 +
import numpy as np
8 +
from numpy import dtype
9 9
from pandapipes.component_models.abstract_models import BranchWZeroLengthComponent
10 -
11 -
from pandapipes.idx_node import PINIT, PAMB
12 -
from pandapipes.idx_branch import STD_TYPE, VINIT, D, AREA, TL, \
13 -
    LOSS_COEFFICIENT as LC, FROM_NODE, TO_NODE, TINIT, PL
14 -
15 10
from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE
16 -
11 +
from pandapipes.idx_branch import STD_TYPE, VINIT, D, AREA, TL, \
12 +
    LOSS_COEFFICIENT as LC, FROM_NODE, TINIT, PL
13 +
from pandapipes.idx_node import PINIT, PAMB
17 14
from pandapipes.pipeflow_setup import get_net_option, get_fluid
18 15
19 16
@@ -22,6 +19,10 @@
Loading
22 19
23 20
    """
24 21
22 +
    @classmethod
23 +
    def from_to_node_cols(cls):
24 +
        return "from_junction", "to_junction"
25 +
25 26
    @classmethod
26 27
    def table_name(cls):
27 28
        return "pump"
@@ -34,6 +35,7 @@
Loading
34 35
    def create_pit_branch_entries(cls, net, pump_pit, node_name):
35 36
        """
36 37
        Function which creates pit branch entries with a specific table.
38 +
37 39
        :param net: The pandapipes network
38 40
        :type net: pandapipesNet
39 41
        :param pump_pit:
@@ -69,10 +71,10 @@
Loading
69 71
        std_types = np.array(list(net.std_type['pump'].keys()))[idx]
70 72
        p_scale = get_net_option(net, "p_scale")
71 73
        from_nodes = pump_pit[:, FROM_NODE].astype(np.int32)
72 -
        to_nodes = pump_pit[:, TO_NODE].astype(np.int32)
74 +
        # to_nodes = pump_pit[:, TO_NODE].astype(np.int32)
73 75
        fluid = get_fluid(net)
74 76
        p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] * p_scale
75 -
        p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] * p_scale
77 +
        # p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] * p_scale
76 78
        numerator = NORMAL_PRESSURE * pump_pit[:, TINIT]
77 79
        v_mps = pump_pit[:, VINIT]
78 80
        if fluid.is_gas:
@@ -114,7 +116,7 @@
Loading
114 116
        :type options:
115 117
        :return: No Output.
116 118
        """
117 -
        placement_table, pump_pit, res_table = super().extract_results(net, options, node_name)
119 +
        placement_table, pump_pit, res_table = super().prepare_result_tables(net, options, node_name)
118 120
        res_table['deltap_bar'].values[placement_table] = pump_pit[:, PL]
119 121
120 122
    @classmethod

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from pandapipes.control.run_control import run_control

@@ -1,22 +1,14 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 -
6 +
from pandapipes.component_models.abstract_models.branch_models import BranchComponent
7 7
from pandapipes.idx_branch import FROM_NODE, TO_NODE, TINIT, ELEMENT_IDX, RHO, ETA, CP, ACTIVE
8 8
from pandapipes.idx_node import TINIT as TINIT_NODE, L, node_cols
9 -
10 9
from pandapipes.pipeflow_setup import add_table_lookup, get_lookup, get_table_number
11 10
from pandapipes.properties.fluids import get_fluid
12 11
13 -
from pandapipes.component_models.abstract_models.branch_models import BranchComponent
14 -
15 -
try:
16 -
    from numba import jit
17 -
except ImportError:
18 -
    from pandapower.pf.no_numba import jit
19 -
20 12
try:
21 13
    import pplog as logging
22 14
except ImportError:
@@ -30,6 +22,22 @@
Loading
30 22
31 23
    """
32 24
25 +
    @classmethod
26 +
    def active_identifier(cls):
27 +
        raise NotImplementedError
28 +
29 +
    @classmethod
30 +
    def calculate_pressure_lift(cls, net, pipe_pit, node_pit):
31 +
        raise NotImplementedError
32 +
33 +
    @classmethod
34 +
    def calculate_temperature_lift(cls, net, pipe_pit, node_pit):
35 +
        raise NotImplementedError
36 +
37 +
    @classmethod
38 +
    def from_to_node_cols(cls):
39 +
        raise NotImplementedError
40 +
33 41
    @classmethod
34 42
    def internal_node_name(cls):
35 43
        return NotImplementedError

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from .io_utils import *

@@ -1,13 +1,13 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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 -
import json
6 5
import copy
6 +
7 7
import pandas as pd
8 8
from numpy import dtype
9 9
from pandapipes import __version__
10 -
from pandapower.auxiliary import ADict, _preserve_dtypes
10 +
from pandapower.auxiliary import ADict
11 11
12 12
try:
13 13
    import pplog as logging
@@ -75,6 +75,7 @@
Loading
75 75
                       ('in_service', "bool"),
76 76
                       ('order', "float64"),
77 77
                       ('level', dtype(object)),
78 +
                       ('initial_run', "bool"),
78 79
                       ("recycle", "bool")],
79 80
        "component_list": []}
80 81
    return default_pandapipes_structure

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
@@ -158,7 +158,7 @@
Loading
158 158
    if cmap is not None:
159 159
        if z is None:
160 160
            z = net.res_pipe.v_mean_m_per_s.loc[pipes_with_geo]
161 -
        add_cmap_to_collection(lc, cmap, norm, z, cbar_title, clim)
161 +
        add_cmap_to_collection(lc, cmap, norm, z, cbar_title, clim=clim)
162 162
163 163
    return lc
164 164
@@ -273,7 +273,7 @@
Loading
273 273
    return ext_grid_pc, ext_grid_lc
274 274
275 275
276 -
def create_heat_exchanger_collection(net, hex=None, size=5., junction_geodata=None, color='k',
276 +
def create_heat_exchanger_collection(net, heat_ex=None, size=5., junction_geodata=None, color='k',
277 277
                                     infofunc=None, picker=False, **kwargs):
278 278
    """
279 279
    Creates a matplotlib patch collection of pandapipes junction-junction heat_exchangers.
@@ -300,11 +300,11 @@
Loading
300 300
    :return: heat_exchanger, helper_lines
301 301
    :rtype: tuple of patch collections
302 302
    """
303 -
    hex = get_index_array(hex, net.heat_exchanger.index)
304 -
    hex_table = net.heat_exchanger.loc[hex]
303 +
    heat_ex = get_index_array(heat_ex, net.heat_exchanger.index)
304 +
    hex_table = net.heat_exchanger.loc[heat_ex]
305 305
306 306
    coords, hex_with_geo = coords_from_node_geodata(
307 -
        hex, hex_table.from_junction.values, hex_table.to_junction.values,
307 +
        heat_ex, hex_table.from_junction.values, hex_table.to_junction.values,
308 308
        junction_geodata if junction_geodata is not None else net["junction_geodata"],
309 309
        "heat_exchanger", "Junction")
310 310

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from numpy import linalg

@@ -1,23 +1,24 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import numpy as np
6 -
from pandapipes.pipeflow_setup import get_fluid, get_lookup, get_net_option
7 -
from pandapipes.component_models.abstract_models import BranchWZeroLengthComponent
8 -
from pandapipes.idx_node import ELEMENT_IDX, PINIT, TINIT as TINIT_NODE, PAMB
9 -
from pandapipes.idx_branch import FROM_NODE, TO_NODE, D, TINIT, AREA, VINIT, \
10 -
    LOAD_VEC_NODES, LOSS_COEFFICIENT as LC, PL, TL, RE, LAMBDA
11 -
from pandapipes.internals_toolbox import _sum_by_group
12 6
from numpy import dtype
13 -
from pandapipes.constants import NORMAL_TEMPERATURE, NORMAL_PRESSURE
7 +
from pandapipes.component_models.abstract_models import BranchWZeroLengthComponent
8 +
from pandapipes.idx_branch import D, AREA, LOSS_COEFFICIENT as LC, PL, TL
9 +
from pandapipes.pipeflow_setup import get_fluid
14 10
15 11
16 12
class Valve(BranchWZeroLengthComponent):
17 13
    """
18 -
14 +
    Valves are branch elements that can separate two junctions.
15 +
    They have a length of 0, but can introduce a lumped pressure loss.
19 16
    """
20 17
18 +
    @classmethod
19 +
    def from_to_node_cols(cls):
20 +
        return "from_junction", "to_junction"
21 +
21 22
    @classmethod
22 23
    def table_name(cls):
23 24
        return "valve"
@@ -35,8 +36,8 @@
Loading
35 36
        :type net: pandapipesNet
36 37
        :param valve_pit:
37 38
        :type valve_pit:
38 -
        :param internal_pipe_number:
39 -
        :type internal_pipe_number:
39 +
        :param node_name:
40 +
        :type node_name:
40 41
        :return: No Output.
41 42
        """
42 43
        valve_pit = super().create_pit_branch_entries(net, valve_pit, node_name)
@@ -74,88 +75,6 @@
Loading
74 75
        """
75 76
        valve_pit[:, TL] = 0
76 77
77 -
    @classmethod
78 -
    def extract_results(cls, net, options, node_name):
79 -
        """
80 -
        Function that extracts certain results.
81 -
82 -
        :param net: The pandapipes network
83 -
        :type net: pandapipesNet
84 -
        :param options:
85 -
        :type options:
86 -
        :return: No Output.
87 -
        """
88 -
        placement_table, valve_pit, res_table = super().extract_results(net, options, node_name)
89 -
90 -
        node_pit = net["_active_pit"]["node"]
91 -
        node_active_idx_lookup = get_lookup(net, "node", "index_active")[node_name]
92 -
        junction_idx_lookup = get_lookup(net, "node", "index")[node_name]
93 -
        from_junction_nodes = node_active_idx_lookup[junction_idx_lookup[
94 -
            net[cls.table_name()]["from_junction"].values[placement_table]]]
95 -
        to_junction_nodes = node_active_idx_lookup[junction_idx_lookup[
96 -
            net[cls.table_name()]["to_junction"].values[placement_table]]]
97 -
98 -
        from_nodes = valve_pit[:, FROM_NODE].astype(np.int32)
99 -
        to_nodes = valve_pit[:, TO_NODE].astype(np.int32)
100 -
        p_scale = get_net_option(net, "p_scale")
101 -
        fluid = get_fluid(net)
102 -
103 -
        v_mps = valve_pit[:, VINIT]
104 -
105 -
        t0 = node_pit[from_nodes, TINIT_NODE]
106 -
        t1 = node_pit[to_nodes, TINIT_NODE]
107 -
        mf = valve_pit[:, LOAD_VEC_NODES]
108 -
        vf = valve_pit[:, LOAD_VEC_NODES] / get_fluid(net).get_density((t0 + t1) / 2)
109 -
110 -
        idx_active = valve_pit[:, ELEMENT_IDX]
111 -
        idx_sort, v_sum, mf_sum, vf_sum = \
112 -
            _sum_by_group(idx_active, v_mps, mf, vf)
113 -
114 -
        if fluid.is_gas:
115 -
            # derived from the ideal gas law
116 -
            p_from = node_pit[from_nodes, PAMB] + node_pit[from_nodes, PINIT] * p_scale
117 -
            p_to = node_pit[to_nodes, PAMB] + node_pit[to_nodes, PINIT] * p_scale
118 -
            numerator = NORMAL_PRESSURE * valve_pit[:, TINIT]
119 -
            normfactor_from = numerator * fluid.get_property("compressibility", p_from) \
120 -
                              / (p_from * NORMAL_TEMPERATURE)
121 -
            normfactor_to = numerator * fluid.get_property("compressibility", p_to) \
122 -
                            / (p_to * NORMAL_TEMPERATURE)
123 -
            v_gas_from = v_mps * normfactor_from
124 -
            v_gas_to = v_mps * normfactor_to
125 -
            mask = p_from != p_to
126 -
            p_mean = np.empty_like(p_to)
127 -
            p_mean[~mask] = p_from[~mask]
128 -
            p_mean[mask] = 2 / 3 * (p_from[mask] ** 3 - p_to[mask] ** 3) \
129 -
                           / (p_from[mask] ** 2 - p_to[mask] ** 2)
130 -
            normfactor_mean = numerator * fluid.get_property("compressibility", p_mean) \
131 -
                              / (p_mean * NORMAL_TEMPERATURE)
132 -
            v_gas_mean = v_mps * normfactor_mean
133 -
134 -
            idx_sort, v_gas_from_sum, v_gas_to_sum, v_gas_mean_sum, nf_from_sum, nf_to_sum = \
135 -
                _sum_by_group(idx_active, v_gas_from, v_gas_to, v_gas_mean, normfactor_from,
136 -
                              normfactor_to)
137 -
138 -
            res_table["v_from_m_per_s"].values[placement_table] = v_gas_from_sum
139 -
            res_table["v_to_m_per_s"].values[placement_table] = v_gas_to_sum
140 -
            res_table["v_mean_m_per_s"].values[placement_table] = v_gas_mean_sum
141 -
            res_table["normfactor_from"].values[placement_table] = nf_from_sum
142 -
            res_table["normfactor_to"].values[placement_table] = nf_to_sum
143 -
        else:
144 -
            res_table["v_mean_m_per_s"].values[placement_table] = v_sum
145 -
146 -
        res_table["p_from_bar"].values[placement_table] = node_pit[from_junction_nodes, PINIT]
147 -
        res_table["p_to_bar"].values[placement_table] = node_pit[to_junction_nodes, PINIT]
148 -
        res_table["t_from_k"].values[placement_table] = node_pit[from_junction_nodes, TINIT_NODE]
149 -
        res_table["t_to_k"].values[placement_table] = node_pit[to_junction_nodes, TINIT_NODE]
150 -
        res_table["mdot_to_kg_per_s"].values[placement_table] = -mf_sum
151 -
        res_table["mdot_from_kg_per_s"].values[placement_table] = mf_sum
152 -
        res_table["vdot_norm_m3_per_s"].values[placement_table] = vf_sum
153 -
        idx_pit = valve_pit[:, ELEMENT_IDX]
154 -
        idx_sort, lambda_sum, reynolds_sum, = \
155 -
            _sum_by_group(idx_pit, valve_pit[:, LAMBDA], valve_pit[:, RE])
156 -
        res_table["lambda"].values[placement_table] = lambda_sum
157 -
        res_table["reynolds"].values[placement_table] = reynolds_sum
158 -
159 78
    @classmethod
160 79
    def get_component_input(cls):
161 80
        """

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from pandapipes.component_models.abstract_models.branch_models import BranchComponent
@@ -10,11 +10,6 @@
Loading
10 10
from pandapipes.pipeflow_setup import add_table_lookup
11 11
from pandapipes.properties.fluids import get_fluid
12 12
13 -
try:
14 -
    from numba import jit
15 -
except ImportError:
16 -
    from pandapower.pf.no_numba import jit
17 -
18 13
try:
19 14
    import pplog as logging
20 15
except ImportError:
@@ -24,13 +19,37 @@
Loading
24 19
25 20
26 21
class BranchWOInternalsComponent(BranchComponent):
27 -
    """
28 22
29 -
    """
23 +
    @classmethod
24 +
    def table_name(cls):
25 +
        raise NotImplementedError
26 +
27 +
    @classmethod
28 +
    def get_component_input(cls):
29 +
        raise NotImplementedError
30 +
31 +
    @classmethod
32 +
    def get_result_table(cls, net):
33 +
        raise NotImplementedError
34 +
35 +
    @classmethod
36 +
    def active_identifier(cls):
37 +
        raise NotImplementedError
38 +
39 +
    @classmethod
40 +
    def from_to_node_cols(cls):
41 +
        raise NotImplementedError
42 +
43 +
    @classmethod
44 +
    def calculate_pressure_lift(cls, net, pipe_pit, node_pit):
45 +
        raise NotImplementedError
46 +
47 +
    @classmethod
48 +
    def calculate_temperature_lift(cls, net, pipe_pit, node_pit):
49 +
        raise NotImplementedError
30 50
31 51
    @classmethod
32 -
    def create_branch_lookups(cls, net, ft_lookups, table_lookup, idx_lookups, current_table,
33 -
                              current_start):
52 +
    def create_branch_lookups(cls, net, ft_lookups, table_lookup, idx_lookups, current_table, current_start):
34 53
        """
35 54
        Function which creates branch lookups.
36 55
@@ -61,10 +80,10 @@
Loading
61 80
62 81
        :param net: The pandapipes network
63 82
        :type net: pandapipesNet
64 -
        :param valve_pit:
65 -
        :type valve_pit:
66 -
        :param internal_pipe_number:
67 -
        :type internal_pipe_number:
83 +
        :param branch_wo_internals_pit:
84 +
        :type branch_wo_internals_pit:
85 +
        :param node_name:
86 +
        :type node_name:
68 87
        :return: No Output.
69 88
        """
70 89
        branch_wo_internals_pit, node_pit, from_nodes, to_nodes \

@@ -1,28 +1,19 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
import json
6 6
import os
7 7
import pickle
8 +
from functools import partial
8 9
9 -
try:
10 -
    from fiona.crs import from_epsg
11 -
    from geopandas import GeoDataFrame, GeoSeries
12 -
    from shapely.geometry import Point, LineString
13 -
14 -
    GEOPANDAS_INSTALLED = True
15 -
except ImportError:
16 -
    GEOPANDAS_INSTALLED = False
17 -
18 -
from pandapipes.pandapipes_net import pandapipesNet
19 10
from pandapower.io_utils import PPJSONEncoder, to_dict_with_coord_transform, \
20 11
    get_raw_data_from_pickle, transform_net_with_df_and_geo, PPJSONDecoder
21 -
from pandapipes.io.io_utils import isinstance_partial, FromSerializableRegistryPpipe
22 12
from pandapower.io_utils import pp_hook
23 -
from pandapipes.create import create_empty_network
24 -
from functools import partial
13 +
25 14
from pandapipes.io.convert_format import convert_format
15 +
from pandapipes.io.io_utils import isinstance_partial, FromSerializableRegistryPpipe
16 +
from pandapipes.pandapipes_net import pandapipesNet
26 17
27 18
28 19
def to_pickle(net, filename):
@@ -106,6 +97,8 @@
Loading
106 97
107 98
    :param filename: The absolute or relative path to the input file or file-like object
108 99
    :type filename: str, file-object
100 +
    :param convert: whether or not to convert the format from earlier versions
101 +
    :type convert: bool
109 102
    :return: net - The pandapipes network that was saved as JSON
110 103
    :rtype: pandapipesNet
111 104
@@ -132,6 +125,8 @@
Loading
132 125
133 126
    :param json_string: The JSON string representation of the network
134 127
    :type json_string: str
128 +
    :param convert: whether or not to convert the format from earlier versions
129 +
    :type convert: bool
135 130
    :return: net - The pandapipes network that was contained in the JSON string
136 131
    :rtype: pandapipesNet
137 132
@@ -140,8 +135,7 @@
Loading
140 135
        >>> net = pandapipes.from_json_string(json_str)
141 136
142 137
    """
143 -
    net = create_empty_network()
144 -
    net = json.loads(json_string, cls=PPJSONDecoder, object_hook=partial(pp_hook, net=net,
138 +
    net = json.loads(json_string, cls=PPJSONDecoder, object_hook=partial(pp_hook,
145 139
                                                                         registry_class=FromSerializableRegistryPpipe))
146 140
147 141
    if convert:

@@ -1,5 +1,5 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
method_transfer_dict = {"n": "Nikuradse", "nik": "Nikuradse", "nikuradse": "Nikuradse",

@@ -1,13 +1,14 @@
Loading
1 -
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics
2 -
# and Energy System Technology (IEE), Kassel. All rights reserved.
1 +
# Copyright (c) 2020-2021 by Fraunhofer Institute for Energy Economics
2 +
# and Energy System Technology (IEE), Kassel, and University of Kassel. All rights reserved.
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
from collections.abc import Iterable
5 6
6 7
import numpy as np
7 8
import pandas as pd
8 9
from pandapipes.component_models.abstract_models.branch_models import BranchComponent
9 10
from pandapipes.component_models.abstract_models.node_element_models import NodeElementComponent
10 -
from pandapipes.pandapipes_net import pandapipesNet, logger
11 +
from pandapipes.pandapipes_net import pandapipesNet
11 12
from pandapower.auxiliary import get_indices
12 13
from pandapower.toolbox import dataframes_equal
13 14
@@ -210,7 +211,10 @@
Loading
210 211
    old_indices = old_indices if old_indices is not None else net[element].index
211 212
    if not len(new_indices) or not net[element].shape[0]:
212 213
        return
213 -
    assert len(new_indices) == len(old_indices)
214 +
    if len(new_indices) != len(old_indices):
215 +
        raise UserWarning("The length of new indices to replace existing ones for %s does not "
216 +
                          "match: %d (new) vs. %d (old)."
217 +
                          % (element, len(new_indices), len(old_indices)))
214 218
    lookup = dict(zip(old_indices, new_indices))
215 219
216 220
    if element == "junction":