Пример #1
0
def create_nxgraph(net,
                   respect_switches=True,
                   include_lines=True,
                   include_trafos=True,
                   include_impedances=True,
                   nogobuses=None,
                   notravbuses=None,
                   multi=True,
                   calc_branch_impedances=False,
                   branch_impedance_unit="ohm",
                   library="networkx"):
    """
     Converts a pandapower network into a NetworkX graph, which is a is a simplified representation
     of a network's topology, reduced to nodes and edges. Busses are being represented by nodes
     (Note: only buses with in_service = 1 appear in the graph), edges represent physical
     connections between buses (typically lines or trafos).

     INPUT:
        **net** (pandapowerNet) - variable that contains a pandapower network


     OPTIONAL:
        **respect_switches** (boolean, True) - True: open switches (line, trafo, bus) are being \
            considered (no edge between nodes)
            False: open switches are being ignored

        **include_lines** (boolean, True) - determines, whether lines get converted to edges

        **include_impedances** (boolean, True) - determines, whether per unit impedances
            (net.impedance) are converted to edges

        **include_trafos** (boolean, True) - determines, whether trafos get converted to edges

        **nogobuses** (integer/list, None) - nogobuses are not being considered in the graph

        **notravbuses** (integer/list, None) - lines connected to these buses are not being
            considered in the graph

        **multi** (boolean, True) - True: The function generates a NetworkX MultiGraph, which allows
            multiple parallel edges between nodes
            False: NetworkX Graph (no multiple parallel edges)


        **calc_branch_impedances** (boolean, False) - detrmines wether impedances are calculated
        and added as a weight to all branches or not. Impedances can be added in ohm or per unit 
        (see branch_impedance unit parameter)
            
        **branch_impedance_unit** (str, "ohm") - defines the unit of the branch impedance for
                    calc_branch_impedances=True. If it is set to "ohm", the parameters 'r_ohm',
                    'x_ohm' and 'z_ohm' are added to each branch. If it is set to "pu", the
                    parameters are 'r_pu', 'x_pu' and 'z_pu'.

     OUTPUT:
        **mg** - Returns the required NetworkX graph

     EXAMPLE:
         import pandapower.topology as top

         mg = top.create_nx_graph(net, respect_switches = False)
         # converts the pandapower network "net" to a MultiGraph. Open switches will be ignored.

    """

    if multi:
        if graph_tool_available and library == "graph_tool":
            mg = GraphToolInterface(net.bus.index)
        else:
            mg = nx.MultiGraph()
    else:
        mg = nx.Graph()
    if branch_impedance_unit not in ["ohm", "pu"]:
        raise ValueError("branch impedance unit can be either 'ohm' or 'pu'")
    if respect_switches:
        open_sw = net.switch.closed.values == False
    if calc_branch_impedances:
        ppc = get_nx_ppc(net)

    if include_lines:
        line = net.line
        indices, parameter, in_service = init_par(line, calc_branch_impedances)
        indices[:, F_BUS] = line.from_bus.values
        indices[:, T_BUS] = line.to_bus.values

        if respect_switches:
            mask = (net.switch.et.values == "l") & open_sw
            if mask.any():
                open_lines = net.switch.element.values[mask]
                open_lines_mask = np.in1d(indices[:, INDEX], open_lines)
                in_service &= ~open_lines_mask

        parameter[:, WEIGHT] = line.length_km.values
        if calc_branch_impedances:
            baseR = get_baseR(net, ppc, line.from_bus.values) \
                if branch_impedance_unit == "pu" else 1
            line_length = line.length_km.values / line.parallel.values
            r = line.r_ohm_per_km.values * line_length
            x = line.x_ohm_per_km.values * line_length
            parameter[:, BR_R] = r / baseR
            parameter[:, BR_X] = x / baseR

        add_edges(mg, indices, parameter, in_service, net, "line",
                  calc_branch_impedances, branch_impedance_unit)

    if include_impedances and len(net.impedance):
        impedance = net.impedance
        indices, parameter, in_service = init_par(impedance,
                                                  calc_branch_impedances)
        indices[:, F_BUS] = impedance.from_bus.values
        indices[:, T_BUS] = impedance.to_bus.values

        if calc_branch_impedances:
            baseR = get_baseR(net, ppc, impedance.from_bus.values) \
                if branch_impedance_unit == "ohm" else 1
            r, x, _, _ = _calc_impedance_parameters_from_dataframe(net)
            parameter[:, BR_R] = r * baseR
            parameter[:, BR_X] = x * baseR

        add_edges(mg, indices, parameter, in_service, net, "impedance",
                  calc_branch_impedances, branch_impedance_unit)

    if include_trafos:
        trafo = net.trafo
        if len(trafo.index):
            indices, parameter, in_service = init_par(trafo,
                                                      calc_branch_impedances)
            indices[:, F_BUS] = trafo.hv_bus.values
            indices[:, T_BUS] = trafo.lv_bus.values

            if respect_switches:
                mask = (net.switch.et.values == "t") & open_sw
                if mask.any():
                    open_trafos = net.switch.element.values[mask]
                    open_trafos_mask = np.in1d(indices[:, INDEX], open_trafos)
                    in_service &= ~open_trafos_mask

            if calc_branch_impedances:
                baseR = get_baseR(net, ppc, trafo.hv_bus.values) \
                    if branch_impedance_unit == "ohm" else 1
                r, x, _, _, _ = _calc_branch_values_from_trafo_df(
                    net, ppc, trafo)
                parameter[:, BR_R] = r * baseR
                parameter[:, BR_X] = x * baseR

            add_edges(mg, indices, parameter, in_service, net, "trafo",
                      calc_branch_impedances, branch_impedance_unit)

        trafo3w = net.trafo3w
        if len(trafo3w):
            sides = ["hv", "mv", "lv"]
            if calc_branch_impedances:
                trafo_df = _trafo_df_from_trafo3w(net)
                r_all, x_all, _, _, _ = _calc_branch_values_from_trafo_df(
                    net, ppc, trafo_df)
                baseR = get_baseR(net, ppc, trafo3w.hv_bus.values) \
                    if branch_impedance_unit == "ohm" else 1
                r = {side: r for side, r in zip(sides, np.split(r_all, 3))}
                x = {side: x for side, x in zip(sides, np.split(x_all, 3))}

            if respect_switches:
                # for trafo3ws the bus where the open switch is located also matters. Open switches
                # are therefore defined by the tuple (idx, b) where idx is the trafo3w index and b
                # is the bus. To make searching for the open 3w trafos a 1d problem, open 3w switches
                # are represented with imaginary numbers as idx + b*1j
                mask = (net.switch.et.values == "t3") & open_sw
                open_trafo3w_index = net.switch.element.values[mask]
                open_trafo3w_buses = net.switch.bus.values[mask]
                open_trafo3w = (open_trafo3w_index +
                                open_trafo3w_buses * 1j).flatten()
            for f, t in combinations(sides, 2):
                indices, parameter, in_service = init_par(
                    trafo3w, calc_branch_impedances)
                indices[:, F_BUS] = trafo3w["%s_bus" % f].values
                indices[:, T_BUS] = trafo3w["%s_bus" % t].values
                if respect_switches and len(open_trafo3w):
                    for BUS in [F_BUS, T_BUS]:
                        open_switch = np.in1d(
                            indices[:, INDEX] + indices[:, BUS] * 1j,
                            open_trafo3w)
                        in_service &= ~open_switch
                if calc_branch_impedances:
                    parameter[:, BR_R] = (r[f] + r[t]) * baseR
                    parameter[:, BR_X] = (x[f] + x[t]) * baseR
                add_edges(mg, indices, parameter, in_service, net, "trafo3w",
                          calc_branch_impedances, branch_impedance_unit)

    switch = net.switch
    if len(switch):
        if respect_switches:
            # add edges for closed bus-bus switches
            in_service = (switch.et.values == "b") & ~open_sw
        else:
            # add edges for any bus-bus switches
            in_service = (switch.et.values == "b")
        indices, parameter = init_par(switch, calc_branch_impedances)
        indices[:, F_BUS] = switch.bus.values
        indices[:, T_BUS] = switch.element.values
        add_edges(mg, indices, parameter, in_service, net, "switch",
                  calc_branch_impedances, branch_impedance_unit)

    # add all buses that were not added when creating branches
    if len(mg.nodes()) < len(net.bus.index):
        if graph_tool_available and isinstance(mg, GraphToolInterface):
            mg.add_vertex(max(net.bus.index) + 1)
        else:
            for b in set(net.bus.index) - set(mg.nodes()):
                mg.add_node(b)

    # remove nogobuses
    if nogobuses is not None:
        for b in nogobuses:
            mg.remove_node(b)

    # remove the edges pointing away of notravbuses
    if notravbuses is not None:
        for b in notravbuses:
            for i in list(mg[b].keys()):
                try:
                    del mg[b][i]  # networkx versions < 2.0
                except:
                    del mg._adj[b][i]  # networkx versions 2.0

    # remove out of service buses
    for b in net.bus.index[~net.bus.in_service.values]:
        mg.remove_node(b)

    return mg
Пример #2
0
def _add_trafo3w_sc_impedance_zero(net, ppc):
    branch_lookup = net["_pd2ppc_lookups"]["branch"]
    if not "trafo3w" in branch_lookup:
        return
    bus_lookup = net["_pd2ppc_lookups"]["bus"]
    branch = ppc["branch"]
    f, t = net["_pd2ppc_lookups"]["branch"]["trafo3w"]
    trafo_df = _trafo_df_from_trafo3w(net, sequence=0)
    hv_bus = get_trafo_values(trafo_df, "hv_bus").astype(int)
    lv_bus = get_trafo_values(trafo_df, "lv_bus").astype(int)
    in_service = get_trafo_values(trafo_df, "in_service").astype(int)
    branch[f:t, F_BUS] = bus_lookup[hv_bus]
    branch[f:t, T_BUS] = bus_lookup[lv_bus]

    r, x, _, ratio, shift = _calc_branch_values_from_trafo_df(net,
                                                              ppc,
                                                              trafo_df,
                                                              sequence=0)

    n_t3 = net.trafo3w.shape[0]
    for t3_ix in np.arange(n_t3):
        t3 = net.trafo3w.iloc[t3_ix, :]

        if t3.vector_group.lower() in set(
                map(lambda vg: "".join(vg), product("dy", repeat=3))):
            x[[t3_ix, t3_ix + n_t3, t3_ix + n_t3 * 2]] = 1e10
            r[[t3_ix, t3_ix + n_t3, t3_ix + n_t3 * 2]] = 1e10
        elif t3.vector_group.lower() == "ynyd":
            # Correction for YnYD
            # z3->y3
            ys = 1 / ((x[t3_ix + n_t3 * 2] * 1j + r[t3_ix + n_t3 * 2]) *
                      ratio[t3_ix + n_t3 * 2]**2)
            aux_bus = bus_lookup[lv_bus[t3_ix]]
            ppc["bus"][aux_bus, BS] += ys.imag
            ppc["bus"][aux_bus, GS] += ys.real

            # Set y2/y3 to almost 0 to avoid isolated bus
            x[[t3_ix + n_t3, t3_ix + n_t3 * 2]] = 1e10
            r[[t3_ix + n_t3, t3_ix + n_t3 * 2]] = 1e10
        elif t3.vector_group.lower() == "yynd":
            # z3->y3
            ys = 1 / ((x[t3_ix + n_t3 * 2] * 1j + r[t3_ix + n_t3 * 2]) *
                      ratio[t3_ix + n_t3 * 2]**2)
            aux_bus = bus_lookup[lv_bus[t3_ix]]
            ppc["bus"][aux_bus, BS] += ys.imag
            ppc["bus"][aux_bus, GS] += ys.real

            # Set y1/y3 to almost 0 to avoid isolated bus
            x[[t3_ix, t3_ix + n_t3 * 2]] = 1e10
            r[[t3_ix, t3_ix + n_t3 * 2]] = 1e10
        elif t3.vector_group.lower() == "ynynd":
            # z3->y3
            ys = 1 / ((x[t3_ix + n_t3 * 2] * 1j + r[t3_ix + n_t3 * 2]) *
                      ratio[t3_ix + n_t3 * 2]**2)
            aux_bus = bus_lookup[lv_bus[t3_ix]]
            ppc["bus"][aux_bus, BS] += ys.imag
            ppc["bus"][aux_bus, GS] += ys.real

            # Set y3 to almost 0 to avoid isolated bus
            x[t3_ix + n_t3 * 2] = 1e10
            r[t3_ix + n_t3 * 2] = 1e10
        else:
            raise UserWarning(
                f"{t3.vector_group} not supported yet for trafo3w!")

    branch[f:t, BR_R] = r
    branch[f:t, BR_X] = x
    branch[f:t, BR_B] = 0
    branch[f:t, TAP] = ratio
    branch[f:t, SHIFT] = shift
    branch[f:t, BR_STATUS] = in_service