コード例 #1
0
ファイル: test_network.py プロジェクト: mhdella/ding0
 def test_graph_add_node_branch(self, empty_grid):
     branch1 = BranchDing0()
     # make sure that call of add_nodes
     # does nothing
     len_nodes_before = len(list(empty_grid._graph.nodes()))
     empty_grid.graph_add_node(branch1)
     len_nodes_after = len(list(empty_grid._graph.nodes()))
     assert len_nodes_before == len_nodes_after
コード例 #2
0
ファイル: test_network.py プロジェクト: mhdella/ding0
 def simple_graph_grid(self):
     grid = GridDing0(id_db=0)
     station = StationDing0(id_db=0, geo_data=Point(0, 0))
     generator = GeneratorDing0(id_db=0, geo_data=Point(0, 1), mv_grid=grid)
     grid.graph_add_node(station)
     grid.add_generator(generator)
     branch = BranchDing0(id_db=0, length=2.0, kind='cable')
     grid._graph.add_edge(generator, station, branch=branch)
     return (grid, station, generator, branch)
コード例 #3
0
def disconnect_node(node, target_obj_result, graph, debug):
    """ Disconnects `node` from `target_obj`

    Parameters
    ----------
    node: LVLoadAreaCentreDing0, i.e.
        Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0)
    target_obj_result: LVLoadAreaCentreDing0, i.e.
        Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0)
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes and newly created branches
    debug: bool
        If True, information is printed during process

    """

    # backup kind and type of branch
    branch_kind = graph.adj[node][target_obj_result]['branch'].kind
    branch_type = graph.adj[node][target_obj_result]['branch'].type
    branch_ring = graph.adj[node][target_obj_result]['branch'].ring

    graph.remove_edge(node, target_obj_result)

    if isinstance(target_obj_result, MVCableDistributorDing0):

        neighbor_nodes = list(graph.neighbors(target_obj_result))

        if len(neighbor_nodes) == 2:
            node.grid.remove_cable_distributor(target_obj_result)

            branch_length = calc_geo_dist_vincenty(neighbor_nodes[0],
                                                   neighbor_nodes[1])
            graph.add_edge(neighbor_nodes[0],
                           neighbor_nodes[1],
                           branch=BranchDing0(length=branch_length,
                                              kind=branch_kind,
                                              type=branch_type,
                                              ring=branch_ring))

    if debug:
        logger.debug('disconnect edge {0}-{1}'.format(node, target_obj_result))
コード例 #4
0
def build_lv_graph_residential(lvgd, selected_string_df):
    """Builds nxGraph based on the LV grid model

    Parameters
    ----------
    lvgd : LVGridDistrictDing0
        Low-voltage grid district object
    selected_string_df: :pandas:`pandas.DataFrame<dataframe>`
        Table of strings of the selected grid model

    Note
    -----
    To understand what is happening in this method a few data table columns
    are explained here

    * `count house branch`: number of houses connected to a string
    * `distance house branch`: distance on a string between two house branches
    * `string length`: total length of a string
    * `length house branch A|B`: cable from string to connection point of a house

    A|B in general brings some variation in to the typified model grid and
    refer to different length of house branches and different cable types
    respectively different cable widths.
    """

    houses_connected = (selected_string_df['occurence'] *
                        selected_string_df['count house branch']).sum()

    average_load = lvgd.peak_load_residential / \
                   houses_connected

    average_consumption = lvgd.sector_consumption_residential / \
                   houses_connected

    hh_branch = 0

    # iterate over each type of branch
    for i, row in selected_string_df.iterrows():

        # get overall count of branches to set unique branch_no
        branch_count_sum = len(
            list(lvgd.lv_grid._graph.neighbors(lvgd.lv_grid.station())))

        # iterate over it's occurences
        for branch_no in range(1, int(row['occurence']) + 1):

            hh_branch += 1
            # iterate over house branches
            for house_branch in range(1, row['count house branch'] + 1):
                if house_branch % 2 == 0:
                    variant = 'B'
                else:
                    variant = 'A'

                # cable distributor to divert from main branch
                lv_cable_dist = LVCableDistributorDing0(grid=lvgd.lv_grid,
                                                        string_id=i,
                                                        branch_no=branch_no +
                                                        branch_count_sum,
                                                        load_no=house_branch)
                # add lv_cable_dist to graph
                lvgd.lv_grid.add_cable_dist(lv_cable_dist)

                # cable distributor within building (to connect load+geno)
                lv_cable_dist_building = LVCableDistributorDing0(
                    grid=lvgd.lv_grid,
                    string_id=i,
                    branch_no=branch_no + branch_count_sum,
                    load_no=house_branch,
                    in_building=True)
                # add lv_cable_dist_building to graph
                lvgd.lv_grid.add_cable_dist(lv_cable_dist_building)

                lv_load = LVLoadDing0(
                    grid=lvgd.lv_grid,
                    string_id=i,
                    branch_no=branch_no + branch_count_sum,
                    load_no=house_branch,
                    peak_load=average_load,
                    consumption={'residential': average_consumption})

                # add lv_load to graph
                lvgd.lv_grid.add_load(lv_load)

                cable_name = row['cable type'] + \
                             ' 4x1x{}'.format(row['cable width'])
                cable_type = lvgd.lv_grid.network.static_data['LV_cables'].loc[
                    cable_name]

                # connect current lv_cable_dist to station
                if house_branch == 1:
                    # edge connect first house branch in branch with the station
                    lvgd.lv_grid._graph.add_edge(
                        lvgd.lv_grid.station(),
                        lv_cable_dist,
                        branch=BranchDing0(
                            length=row['distance house branch'],
                            kind='cable',
                            type=cable_type,
                            id_db='branch_{sector}{branch}_{load}'.format(
                                branch=hh_branch,
                                load=house_branch,
                                sector='HH')))
                # connect current lv_cable_dist to last one
                else:
                    lvgd.lv_grid._graph.add_edge(
                        lvgd.lv_grid._cable_distributors[-4],
                        lv_cable_dist,
                        branch=BranchDing0(
                            length=row['distance house branch'],
                            kind='cable',
                            type=lvgd.lv_grid.network.static_data['LV_cables'].
                            loc[cable_name],
                            id_db='branch_{sector}{branch}_{load}'.format(
                                branch=hh_branch,
                                load=house_branch,
                                sector='HH')))

                # connect house to cable distributor
                house_cable_name = row['cable type {}'.format(variant)] + \
                                   ' 4x1x{}'.format(
                                       row['cable width {}'.format(variant)])
                lvgd.lv_grid._graph.add_edge(
                    lv_cable_dist,
                    lv_cable_dist_building,
                    branch=BranchDing0(
                        length=row['length house branch {}'.format(
                            variant)],
                        kind='cable',
                        type=lvgd.lv_grid.network.static_data['LV_cables']. \
                            loc[house_cable_name],
                        id_db='branch_{sector}{branch}_{load}'.format(
                            branch=hh_branch,
                            load=house_branch,
                            sector='HH'))
                )

                lvgd.lv_grid._graph.add_edge(
                    lv_cable_dist_building,
                    lv_load,
                    branch=BranchDing0(
                        length=1,
                        kind='cable',
                        type=lvgd.lv_grid.network.static_data['LV_cables']. \
                            loc[house_cable_name],
                        id_db='branch_{sector}{branch}_{load}'.format(
                            branch=hh_branch,
                            load=house_branch,
                            sector='HH'))
                )
コード例 #5
0
    def lv_graph_attach_branch():
        """Attach a single branch including its equipment (cable dist, loads
        and line segments) to graph of `lv_grid`
        """

        # determine maximum current occuring due to peak load
        # of this load load_no
        I_max_load = val['single_peak_load'] / (3**0.5 * v_nom) / cos_phi_load

        # determine suitable cable for this current
        suitable_cables_stub = lvgd.lv_grid.network.static_data['LV_cables'][(
            lvgd.lv_grid.network.static_data['LV_cables']['I_max_th'] *
            cable_lf) > I_max_load]
        cable_type_stub = suitable_cables_stub.loc[
            suitable_cables_stub['I_max_th'].idxmin(), :]

        # cable distributor to divert from main branch
        lv_cable_dist = LVCableDistributorDing0(grid=lvgd.lv_grid,
                                                branch_no=branch_no,
                                                load_no=load_no)
        # add lv_cable_dist to graph
        lvgd.lv_grid.add_cable_dist(lv_cable_dist)

        # cable distributor within building (to connect load+geno)
        lv_cable_dist_building = LVCableDistributorDing0(grid=lvgd.lv_grid,
                                                         branch_no=branch_no,
                                                         load_no=load_no,
                                                         in_building=True)
        # add lv_cable_dist_building to graph
        lvgd.lv_grid.add_cable_dist(lv_cable_dist_building)

        # create an instance of Ding0 LV load
        lv_load = LVLoadDing0(grid=lvgd.lv_grid,
                              branch_no=branch_no,
                              load_no=load_no,
                              peak_load=val['single_peak_load'],
                              consumption=val['consumption'])

        # add lv_load to graph
        lvgd.lv_grid.add_load(lv_load)

        # create branch line segment between either (a) station
        # and cable distributor or (b) between neighboring cable
        # distributors
        if load_no == 1:
            # case a: cable dist <-> station
            lvgd.lv_grid._graph.add_edge(
                lvgd.lv_grid.station(),
                lv_cable_dist,
                branch=BranchDing0(
                    length=val['load_distance'],
                    kind='cable',
                    type=cable_type,
                    id_db='branch_{sector}{branch}_{load}'.format(
                        branch=branch_no, load=load_no, sector=sector_short)))
        else:
            # case b: cable dist <-> cable dist
            lvgd.lv_grid._graph.add_edge(
                lvgd.lv_grid._cable_distributors[-4],
                lv_cable_dist,
                branch=BranchDing0(
                    length=val['load_distance'],
                    kind='cable',
                    type=cable_type,
                    id_db='branch_{sector}{branch}_{load}'.format(
                        branch=branch_no, load=load_no, sector=sector_short)))

        # create branch stub that connects the load to the
        # lv_cable_dist located in the branch line
        lvgd.lv_grid._graph.add_edge(
            lv_cable_dist,
            lv_cable_dist_building,
            branch=BranchDing0(length=cfg_ding0.get(
                'assumptions', 'lv_ria_branch_connection_distance'),
                               kind='cable',
                               type=cable_type_stub,
                               id_db='stub_{sector}{branch}_{load}'.format(
                                   branch=branch_no,
                                   load=load_no,
                                   sector=sector_short)))

        lvgd.lv_grid._graph.add_edge(
            lv_cable_dist_building,
            lv_load,
            branch=BranchDing0(length=1,
                               kind='cable',
                               type=cable_type_stub,
                               id_db='stub_{sector}{branch}_{load}'.format(
                                   branch=branch_no,
                                   load=load_no,
                                   sector=sector_short)))
コード例 #6
0
def routing_solution_to_ding0_graph(graph, solution):
    """ Insert `solution` from routing into `graph`

    Args
    ----
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes
    solution: BaseSolution
        Instance of `BaseSolution` or child class (e.g. `LocalSearchSolution`) (=solution from routing)

    Returns
    -------
    :networkx:`NetworkX Graph Obj< >` 
        NetworkX graph object with nodes and edges
    """
    # TODO: Bisherige Herangehensweise (diese Funktion): Branches werden nach Routing erstellt um die Funktionsfähigkeit
    # TODO: des Routing-Tools auch für die TestCases zu erhalten. Es wird ggf. notwendig, diese direkt im Routing vorzunehmen.

    # build node dict (name: obj) from graph nodes to map node names on node objects
    node_list = {str(n): n for n in graph.nodes()}

    # add edges from solution to graph
    try:
        depot = solution._nodes[solution._problem._depot.name()]
        depot_node = node_list[depot.name()]
        for r in solution.routes():
            circ_breaker_pos = None

            # if route has only one node and is not aggregated, it wouldn't be possible to add two lines from and to
            # this node (undirected graph of NetworkX). So, as workaround, an additional MV cable distributor is added
            # at nodes' position (resulting route: HV/MV_subst --- node --- cable_dist --- HV/MV_subst.
            if len(r._nodes) == 1:
                if not solution._problem._is_aggregated[r._nodes[0]._name]:
                    # create new cable dist
                    cable_dist = MVCableDistributorDing0(
                        geo_data=node_list[r._nodes[0]._name].geo_data,
                        grid=depot_node.grid)
                    depot_node.grid.add_cable_distributor(cable_dist)

                    # create new node (as dummy) an allocate to route r
                    r.allocate([Node(name=repr(cable_dist), demand=0)])

                    # add it to node list and allocated-list manually
                    node_list[str(cable_dist)] = cable_dist
                    solution._problem._is_aggregated[str(cable_dist)] = False

                    # set circ breaker pos manually
                    circ_breaker_pos = 1

            # build edge list
            n1 = r._nodes[0:len(r._nodes) - 1]
            n2 = r._nodes[1:len(r._nodes)]
            edges = list(zip(n1, n2))
            edges.append((depot, r._nodes[0]))
            edges.append((r._nodes[-1], depot))

            # create MV Branch object for every edge in `edges`
            mv_branches = [BranchDing0() for _ in edges]
            edges_with_branches = list(zip(edges, mv_branches))

            # recalculate circuit breaker positions for final solution, create it and set associated branch.
            # if circ. breaker position is not set manually (routes with more than one load area, see above)
            if not circ_breaker_pos:
                circ_breaker_pos = r.calc_circuit_breaker_position()

            node1 = node_list[edges[circ_breaker_pos - 1][0].name()]
            node2 = node_list[edges[circ_breaker_pos - 1][1].name()]

            # ALTERNATIVE TO METHOD ABOVE: DO NOT CREATE 2 BRANCHES (NO RING) -> LA IS CONNECTED AS SATELLITE
            # IF THIS IS COMMENTED-IN, THE IF-BLOCK IN LINE 87 HAS TO BE COMMENTED-OUT
            # See issue #114
            # ===============================
            # do not add circuit breaker for routes which are aggregated load areas or
            # routes that contain only one load area
            # if not (node1 == depot_node and solution._problem._is_aggregated[edges[circ_breaker_pos - 1][1].name()] or
            #         node2 == depot_node and solution._problem._is_aggregated[edges[circ_breaker_pos - 1][0].name()] or
            #         len(r._nodes) == 1):
            # ===============================

            # do not add circuit breaker for routes which are aggregated load areas
            if not (node1 == depot_node and solution._problem._is_aggregated[
                    edges[circ_breaker_pos - 1][1].name()]
                    or node2 == depot_node and solution._problem.
                    _is_aggregated[edges[circ_breaker_pos - 1][0].name()]):
                branch = mv_branches[circ_breaker_pos - 1]
                circ_breaker = CircuitBreakerDing0(
                    grid=depot_node.grid,
                    branch=branch,
                    geo_data=calc_geo_centre_point(node1, node2))
                branch.circuit_breaker = circ_breaker

            # create new ring object for route
            ring = RingDing0(grid=depot_node.grid)

            # translate solution's node names to graph node objects using dict created before
            # note: branch object is assigned to edge using an attribute ('branch' is used here), it can be accessed
            # using the method `graph_edges()` of class `GridDing0`
            edges_graph = []
            for ((n1, n2), b) in edges_with_branches:
                # get node objects
                node1 = node_list[n1.name()]
                node2 = node_list[n2.name()]

                # set branch's ring attribute
                b.ring = ring
                # set LVLA's ring attribute
                if isinstance(node1, LVLoadAreaCentreDing0):
                    node1.lv_load_area.ring = ring

                # set branch length
                b.length = calc_geo_dist_vincenty(node1, node2)

                # set branch kind and type
                # 1) default
                b.kind = depot_node.grid.default_branch_kind
                b.type = depot_node.grid.default_branch_type
                # 2) aggregated load area types
                if node1 == depot_node and solution._problem._is_aggregated[
                        n2.name()]:
                    b.connects_aggregated = True
                    b.kind = depot_node.grid.default_branch_kind_aggregated
                    b.type = depot_node.grid.default_branch_type_aggregated
                elif node2 == depot_node and solution._problem._is_aggregated[
                        n1.name()]:
                    b.connects_aggregated = True
                    b.kind = depot_node.grid.default_branch_kind_aggregated
                    b.type = depot_node.grid.default_branch_type_aggregated

                # append to branch list
                edges_graph.append((node1, node2, dict(branch=b)))

            # add branches to graph
            graph.add_edges_from(edges_graph)

    except:
        logger.exception(
            'unexpected error while converting routing solution to DING0 graph (NetworkX).'
        )

    return graph
コード例 #7
0
def mv_connect_generators(mv_grid_district, graph, debug=False):
    """Connect MV generators to MV grid

    Parameters
    ----------
    mv_grid_district: MVGridDistrictDing0
        MVGridDistrictDing0 object for which the connection process has to be
        done
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes
    debug: bool, defaults to False
        If True, information is printed during process.

    Returns
    -------
    :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes and newly created branches
    """

    generator_buffer_radius = cfg_ding0.get('mv_connect',
                                            'generator_buffer_radius')
    generator_buffer_radius_inc = cfg_ding0.get('mv_connect',
                                                'generator_buffer_radius_inc')

    # WGS84 (conformal) to ETRS (equidistant) projection
    proj1 = partial(
        pyproj.transform,
        pyproj.Proj(init='epsg:4326'),  # source coordinate system
        pyproj.Proj(init='epsg:3035'))  # destination coordinate system

    # ETRS (equidistant) to WGS84 (conformal) projection
    proj2 = partial(
        pyproj.transform,
        pyproj.Proj(init='epsg:3035'),  # source coordinate system
        pyproj.Proj(init='epsg:4326'))  # destination coordinate system

    for generator in sorted(mv_grid_district.mv_grid.generators(),
                            key=lambda x: repr(x)):

        # ===== voltage level 4: generator has to be connected to MV station =====
        if generator.v_level == 4:
            mv_station = mv_grid_district.mv_grid.station()

            branch_length = calc_geo_dist_vincenty(generator, mv_station)

            # TODO: set branch type to something reasonable (to be calculated)
            branch_kind = mv_grid_district.mv_grid.default_branch_kind
            branch_type = mv_grid_district.mv_grid.default_branch_type

            branch = BranchDing0(length=branch_length,
                                 kind=branch_kind,
                                 type=branch_type,
                                 ring=None)
            graph.add_edge(generator, mv_station, branch=branch)

            if debug:
                logger.debug('Generator {0} was connected to {1}'.format(
                    generator, mv_station))

        # ===== voltage level 5: generator has to be connected to MV grid (next-neighbor) =====
        elif generator.v_level == 5:
            generator_shp = transform(proj1, generator.geo_data)

            # get branches within a the predefined radius `generator_buffer_radius`
            branches = calc_geo_branches_in_buffer(
                generator, mv_grid_district.mv_grid, generator_buffer_radius,
                generator_buffer_radius_inc, proj1)

            # calc distance between generator and grid's lines -> find nearest line
            conn_objects_min_stack = find_nearest_conn_objects(
                generator_shp,
                branches,
                proj1,
                conn_dist_weight=1,
                debug=debug,
                branches_only=False)

            # connect!
            # go through the stack (from nearest to most far connection target object)
            generator_connected = False
            for dist_min_obj in conn_objects_min_stack:
                # Note 1: conn_dist_ring_mod=0 to avoid re-routing of existent lines
                # Note 2: In connect_node(), the default cable/line type of grid is used. This is reasonable since
                #         the max. allowed power of the smallest possible cable/line type (3.64 MVA for overhead
                #         line of type 48-AL1/8-ST1A) exceeds the max. allowed power of a generator (4.5 MVA (dena))
                #         (if connected separately!)
                target_obj_result = connect_node(generator,
                                                 generator_shp,
                                                 mv_grid_district.mv_grid,
                                                 dist_min_obj,
                                                 proj2,
                                                 graph,
                                                 conn_dist_ring_mod=0,
                                                 debug=debug)

                if target_obj_result is not None:
                    if debug:
                        logger.debug(
                            'Generator {0} was connected to {1}'.format(
                                generator, target_obj_result))
                    generator_connected = True
                    break

            if not generator_connected and debug:
                logger.debug(
                    'Generator {0} could not be connected, try to '
                    'increase the parameter `generator_buffer_radius` in '
                    'config file `config_calc.cfg` to gain more possible '
                    'connection points.'.format(generator))

    return graph
コード例 #8
0
def mv_connect_stations(mv_grid_district, graph, debug=False):
    """ Connect LV stations to MV grid

    Parameters
    ----------
    mv_grid_district: MVGridDistrictDing0
        MVGridDistrictDing0 object for which the connection process has to be done
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes
    debug: bool, defaults to False
        If True, information is printed during process

    Returns
    -------
    :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes and newly created branches
    """

    # WGS84 (conformal) to ETRS (equidistant) projection
    proj1 = partial(
        pyproj.transform,
        pyproj.Proj(init='epsg:4326'),  # source coordinate system
        pyproj.Proj(init='epsg:3035'))  # destination coordinate system

    # ETRS (equidistant) to WGS84 (conformal) projection
    proj2 = partial(
        pyproj.transform,
        pyproj.Proj(init='epsg:3035'),  # source coordinate system
        pyproj.Proj(init='epsg:4326'))  # destination coordinate system

    conn_dist_weight = cfg_ding0.get('mv_connect',
                                     'load_area_sat_conn_dist_weight')
    conn_dist_ring_mod = cfg_ding0.get('mv_connect',
                                       'load_area_stat_conn_dist_ring_mod')

    for lv_load_area in mv_grid_district.lv_load_areas():

        # exclude aggregated Load Areas and choose only load areas that were connected to grid before
        if not lv_load_area.is_aggregated and \
           lv_load_area.lv_load_area_centre not in mv_grid_district.mv_grid.graph_isolated_nodes():

            lv_load_area_centre = lv_load_area.lv_load_area_centre

            # there's only one station: Replace Load Area centre by station in graph
            if lv_load_area.lv_grid_districts_count() == 1:
                # get station
                lv_station = list(
                    lv_load_area.lv_grid_districts())[0].lv_grid.station()

                # get branches that are connected to Load Area centre
                branches = mv_grid_district.mv_grid.graph_branches_from_node(
                    lv_load_area_centre)

                # connect LV station, delete Load Area centre
                for node, branch in branches:
                    # backup kind and type of branch
                    branch_kind = branch['branch'].kind
                    branch_type = branch['branch'].type
                    branch_ring = branch['branch'].ring

                    # respect circuit breaker if existent
                    circ_breaker = branch['branch'].circuit_breaker
                    if circ_breaker is not None:
                        branch[
                            'branch'].circuit_breaker.geo_data = calc_geo_centre_point(
                                lv_station, node)

                    # delete old branch to Load Area centre and create a new one to LV station
                    graph.remove_edge(lv_load_area_centre, node)

                    branch_length = calc_geo_dist_vincenty(lv_station, node)
                    branch = BranchDing0(length=branch_length,
                                         circuit_breaker=circ_breaker,
                                         kind=branch_kind,
                                         type=branch_type,
                                         ring=branch_ring)
                    if circ_breaker is not None:
                        circ_breaker.branch = branch
                    graph.add_edge(lv_station, node, branch=branch)

                # delete Load Area centre from graph
                graph.remove_node(lv_load_area_centre)

            # there're more than one station: Do normal connection process (as in satellites)
            else:
                # connect LV stations of all grid districts
                # =========================================
                for lv_grid_district in lv_load_area.lv_grid_districts():
                    # get branches that are partly or fully located in load area
                    branches = calc_geo_branches_in_polygon(
                        mv_grid_district.mv_grid,
                        lv_load_area.geo_area,
                        mode='intersects',
                        proj=proj1)

                    # filter branches that belong to satellites (load area groups) if Load Area is not a satellite
                    # itself
                    if not lv_load_area.is_satellite:
                        branches_valid = []
                        for branch in branches:
                            node1 = branch['adj_nodes'][0]
                            node2 = branch['adj_nodes'][1]
                            lv_load_area_group = get_lv_load_area_group_from_node_pair(
                                node1, node2)

                            # delete branch as possible conn. target if it belongs to a group (=satellite) or
                            # if it belongs to a ring different from the ring of the current LVLA
                            if (lv_load_area_group is None) and\
                               (branch['branch'].ring is lv_load_area.ring):
                                branches_valid.append(branch)
                        branches = branches_valid

                    # find possible connection objects
                    lv_station = lv_grid_district.lv_grid.station()
                    lv_station_shp = transform(proj1, lv_station.geo_data)
                    conn_objects_min_stack = find_nearest_conn_objects(
                        lv_station_shp,
                        branches,
                        proj1,
                        conn_dist_weight,
                        debug,
                        branches_only=False)

                    # connect!
                    connect_node(lv_station, lv_station_shp,
                                 mv_grid_district.mv_grid,
                                 conn_objects_min_stack[0], proj2, graph,
                                 conn_dist_ring_mod, debug)

                # Replace Load Area centre by cable distributor
                # ================================================
                # create cable distributor and add it to grid
                cable_dist = MVCableDistributorDing0(
                    geo_data=lv_load_area_centre.geo_data,
                    grid=mv_grid_district.mv_grid)
                mv_grid_district.mv_grid.add_cable_distributor(cable_dist)

                # get branches that are connected to Load Area centre
                branches = mv_grid_district.mv_grid.graph_branches_from_node(
                    lv_load_area_centre)

                # connect LV station, delete Load Area centre
                for node, branch in branches:
                    # backup kind and type of branch
                    branch_kind = branch['branch'].kind
                    branch_type = branch['branch'].type
                    branch_ring = branch['branch'].ring

                    # respect circuit breaker if existent
                    circ_breaker = branch['branch'].circuit_breaker
                    if circ_breaker is not None:
                        branch[
                            'branch'].circuit_breaker.geo_data = calc_geo_centre_point(
                                cable_dist, node)

                    # delete old branch to Load Area centre and create a new one to LV station
                    graph.remove_edge(lv_load_area_centre, node)

                    branch_length = calc_geo_dist_vincenty(cable_dist, node)
                    branch = BranchDing0(length=branch_length,
                                         circuit_breaker=circ_breaker,
                                         kind=branch_kind,
                                         type=branch_type,
                                         ring=branch_ring)
                    if circ_breaker is not None:
                        circ_breaker.branch = branch
                    graph.add_edge(cable_dist, node, branch=branch)

                # delete Load Area centre from graph
                graph.remove_node(lv_load_area_centre)

            # Replace all overhead lines by cables
            # ====================================
            # if grid's default type is overhead line
            if mv_grid_district.mv_grid.default_branch_kind == 'line':
                # get all branches in load area
                branches = calc_geo_branches_in_polygon(
                    mv_grid_district.mv_grid,
                    lv_load_area.geo_area,
                    mode='contains',
                    proj=proj1)
                # set type
                for branch in branches:
                    branch[
                        'branch'].kind = mv_grid_district.mv_grid.default_branch_kind_settle
                    branch[
                        'branch'].type = mv_grid_district.mv_grid.default_branch_type_settle

    return graph
コード例 #9
0
def connect_node(node, node_shp, mv_grid, target_obj, proj, graph,
                 conn_dist_ring_mod, debug):
    """ Connects `node` to `target_obj`.

    Parameters
    ----------
    node: LVLoadAreaCentreDing0, i.e.
        Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0)
    node_shp: :shapely:`Shapely Point object<points>`
        Shapely Point object of origin node
    target_obj: type
        object that node shall be connected to
    proj: :pyproj:`pyproj Proj object< >`
        equidistant CRS to conformal CRS (e.g. ETRS -> WGS84)
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes and newly created branches
    conn_dist_ring_mod: float
        Max. distance when nodes are included into route instead of creating a 
        new line.
    debug: bool
        If True, information is printed during process.

    Returns
    -------
    :obj:`LVLoadAreaCentreDing0`
        object that node was connected to.
        
        (instance of :obj:`LVLoadAreaCentreDing0` or :obj:`MVCableDistributorDing0`.
        
        If node is included into line instead of creating a new line (see arg
        `conn_dist_ring_mod`), `target_obj_result` is None.
                           
    See Also
    --------
    ding0.grid.mv_grid.mv_connect : for details on the `conn_dist_ring_mod` parameter.
    """

    target_obj_result = None

    # MV line is nearest connection point
    if isinstance(target_obj['shp'], LineString):

        adj_node1 = target_obj['obj']['adj_nodes'][0]
        adj_node2 = target_obj['obj']['adj_nodes'][1]

        # find nearest point on MV line
        conn_point_shp = target_obj['shp'].interpolate(
            target_obj['shp'].project(node_shp))
        conn_point_shp = transform(proj, conn_point_shp)

        # target MV line does currently not connect a load area of type aggregated
        if not target_obj['obj']['branch'].connects_aggregated:

            # Node is close to line
            # -> insert node into route (change existing route)
            if (target_obj['dist'] < conn_dist_ring_mod):
                # backup kind and type of branch
                branch_type = graph.adj[adj_node1][adj_node2]['branch'].type
                branch_kind = graph.adj[adj_node1][adj_node2]['branch'].kind
                branch_ring = graph.adj[adj_node1][adj_node2]['branch'].ring

                # check if there's a circuit breaker on current branch,
                # if yes set new position between first node (adj_node1) and newly inserted node
                circ_breaker = graph.adj[adj_node1][adj_node2][
                    'branch'].circuit_breaker
                if circ_breaker is not None:
                    circ_breaker.geo_data = calc_geo_centre_point(
                        adj_node1, node)

                # split old ring main route into 2 segments (delete old branch and create 2 new ones
                # along node)
                graph.remove_edge(adj_node1, adj_node2)

                branch_length = calc_geo_dist_vincenty(adj_node1, node)
                branch = BranchDing0(length=branch_length,
                                     circuit_breaker=circ_breaker,
                                     kind=branch_kind,
                                     type=branch_type,
                                     ring=branch_ring)
                if circ_breaker is not None:
                    circ_breaker.branch = branch
                graph.add_edge(adj_node1, node, branch=branch)

                branch_length = calc_geo_dist_vincenty(adj_node2, node)
                graph.add_edge(adj_node2,
                               node,
                               branch=BranchDing0(length=branch_length,
                                                  kind=branch_kind,
                                                  type=branch_type,
                                                  ring=branch_ring))

                target_obj_result = 're-routed'

                if debug:
                    logger.debug('Ring main route modified to include '
                                 'node {}'.format(node))

            # Node is too far away from route
            # => keep main route and create new line from node to (cable distributor on) route.
            else:

                # create cable distributor and add it to grid
                cable_dist = MVCableDistributorDing0(geo_data=conn_point_shp,
                                                     grid=mv_grid)
                mv_grid.add_cable_distributor(cable_dist)

                # check if there's a circuit breaker on current branch,
                # if yes set new position between first node (adj_node1) and newly created cable distributor
                circ_breaker = graph.adj[adj_node1][adj_node2][
                    'branch'].circuit_breaker
                if circ_breaker is not None:
                    circ_breaker.geo_data = calc_geo_centre_point(
                        adj_node1, cable_dist)

                # split old branch into 2 segments (delete old branch and create 2 new ones along cable_dist)
                # ===========================================================================================

                # backup kind and type of branch
                branch_kind = graph.adj[adj_node1][adj_node2]['branch'].kind
                branch_type = graph.adj[adj_node1][adj_node2]['branch'].type
                branch_ring = graph.adj[adj_node1][adj_node2]['branch'].ring

                graph.remove_edge(adj_node1, adj_node2)

                branch_length = calc_geo_dist_vincenty(adj_node1, cable_dist)
                branch = BranchDing0(length=branch_length,
                                     circuit_breaker=circ_breaker,
                                     kind=branch_kind,
                                     type=branch_type,
                                     ring=branch_ring)
                if circ_breaker is not None:
                    circ_breaker.branch = branch
                graph.add_edge(adj_node1, cable_dist, branch=branch)

                branch_length = calc_geo_dist_vincenty(adj_node2, cable_dist)
                graph.add_edge(adj_node2,
                               cable_dist,
                               branch=BranchDing0(length=branch_length,
                                                  kind=branch_kind,
                                                  type=branch_type,
                                                  ring=branch_ring))

                # add new branch for satellite (station to cable distributor)
                # ===========================================================

                # get default branch kind and type from grid to use it for new branch
                branch_kind = mv_grid.default_branch_kind
                branch_type = mv_grid.default_branch_type

                branch_length = calc_geo_dist_vincenty(node, cable_dist)
                graph.add_edge(node,
                               cable_dist,
                               branch=BranchDing0(length=branch_length,
                                                  kind=branch_kind,
                                                  type=branch_type,
                                                  ring=branch_ring))
                target_obj_result = cable_dist

                # debug info
                if debug:
                    logger.debug('Nearest connection point for object {0} '
                                 'is branch {1} (distance={2} m)'.format(
                                     node, target_obj['obj']['adj_nodes'],
                                     target_obj['dist']))

    # node ist nearest connection point
    else:

        # what kind of node is to be connected? (which type is node of?)
        #   LVLoadAreaCentreDing0: Connect to LVLoadAreaCentreDing0 only
        #   LVStationDing0: Connect to LVLoadAreaCentreDing0, LVStationDing0 or MVCableDistributorDing0
        #   GeneratorDing0: Connect to LVLoadAreaCentreDing0, LVStationDing0, MVCableDistributorDing0 or GeneratorDing0
        if isinstance(node, LVLoadAreaCentreDing0):
            valid_conn_objects = LVLoadAreaCentreDing0
        elif isinstance(node, LVStationDing0):
            valid_conn_objects = (LVLoadAreaCentreDing0, LVStationDing0,
                                  MVCableDistributorDing0)
        elif isinstance(node, GeneratorDing0):
            valid_conn_objects = (LVLoadAreaCentreDing0, LVStationDing0,
                                  MVCableDistributorDing0, GeneratorDing0)
        else:
            raise ValueError(
                'Oops, the node you are trying to connect is not a valid connection object'
            )

        # if target is Load Area centre or LV station, check if it belongs to a load area of type aggregated
        # (=> connection not allowed)
        if isinstance(target_obj['obj'],
                      (LVLoadAreaCentreDing0, LVStationDing0)):
            target_is_aggregated = target_obj['obj'].lv_load_area.is_aggregated
        else:
            target_is_aggregated = False

        # target node is not a load area of type aggregated
        if isinstance(target_obj['obj'],
                      valid_conn_objects) and not target_is_aggregated:

            # get default branch kind and type from grid to use it for new branch
            branch_kind = mv_grid.default_branch_kind
            branch_type = mv_grid.default_branch_type

            # get branch ring obj
            branch_ring = mv_grid.get_ring_from_node(target_obj['obj'])

            # add new branch for satellite (station to station)
            branch_length = calc_geo_dist_vincenty(node, target_obj['obj'])
            graph.add_edge(node,
                           target_obj['obj'],
                           branch=BranchDing0(length=branch_length,
                                              kind=branch_kind,
                                              type=branch_type,
                                              ring=branch_ring))
            target_obj_result = target_obj['obj']

            # debug info
            if debug:
                logger.debug(
                    'Nearest connection point for object {0} is station {1} '
                    '(distance={2} m)'.format(node, target_obj['obj'],
                                              target_obj['dist']))

    return target_obj_result
コード例 #10
0
def lv_connect_generators(lv_grid_district, graph, debug=False):
    """ Connect LV generators to LV grid
    
    Args
    ----
    lv_grid_district: LVGridDistrictDing0
        LVGridDistrictDing0 object for which the connection process has to be done
    graph: :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes
    debug: bool, defaults to False
        If True, information is printed during process

    Returns
    -------
    :networkx:`NetworkX Graph Obj< >`
        NetworkX graph object with nodes and newly created branches
    """

    cable_lf = cfg_ding0.get('assumptions', 'load_factor_lv_cable_fc_normal')
    cos_phi_gen = cfg_ding0.get('assumptions', 'cos_phi_gen')
    v_nom = cfg_ding0.get('assumptions',
                          'lv_nominal_voltage') / 1e3  # v_nom in kV
    seed = int(cfg_ding0.get('random', 'seed'))
    random.seed(a=seed)

    # generate random list (without replacement => unique elements)
    # of loads (residential) to connect genos (P <= 30kW) to.
    lv_loads_res = sorted(lv_grid_district.lv_grid.loads_sector(sector='res'),
                          key=lambda _: repr(_))
    if len(lv_loads_res) > 0:
        lv_loads_res_rnd = (random.sample(lv_loads_res, len(lv_loads_res)))
    else:
        lv_loads_res_rnd = None

    # generate random list (without replacement => unique elements)
    # of loads (retail, industrial, agricultural) to connect genos
    # (30kW <= P <= 100kW) to.
    lv_loads_ria = sorted(lv_grid_district.lv_grid.loads_sector(sector='ria'),
                          key=lambda _: repr(_))
    if len(lv_loads_ria) > 0:
        lv_loads_ria_rnd = (random.sample(lv_loads_ria, len(lv_loads_ria)))
    else:
        lv_loads_ria_rnd = None

    for generator in sorted(lv_grid_district.lv_grid.generators(),
                            key=lambda x: repr(x)):

        # generator is of v_level 6 -> connect to LV station
        if generator.v_level == 6:
            lv_station = lv_grid_district.lv_grid.station()

            branch_length = calc_geo_dist_vincenty(generator, lv_station)
            branch_type = cable_type(
                generator.capacity / (cable_lf * cos_phi_gen), v_nom,
                lv_grid_district.lv_grid.network.static_data['LV_cables'])

            branch = BranchDing0(length=branch_length,
                                 kind='cable',
                                 type=branch_type)

            graph.add_edge(generator, lv_station, branch=branch)

        # generator is of v_level 7 -> assign geno to load
        elif generator.v_level == 7:

            # connect genos with P <= 30kW to residential loads, if available
            if (generator.capacity <= 30) and (lv_loads_res_rnd is not None):
                if len(lv_loads_res_rnd) > 0:
                    lv_load = lv_loads_res_rnd.pop()
                # if random load list is empty, create new one
                else:
                    lv_loads_res_rnd = (random.sample(lv_loads_res,
                                                      len(lv_loads_res)))
                    lv_load = lv_loads_res_rnd.pop()

                # get cable distributor of building
                lv_conn_target = list(graph.neighbors(lv_load))[0]

            # connect genos with 30kW <= P <= 100kW to residential loads
            # to retail, industrial, agricultural loads, if available
            elif (generator.capacity > 30) and (lv_loads_ria_rnd is not None):
                if len(lv_loads_ria_rnd) > 0:
                    lv_load = lv_loads_ria_rnd.pop()
                # if random load list is empty, create new one
                else:
                    lv_loads_ria_rnd = (random.sample(lv_loads_ria,
                                                      len(lv_loads_ria)))
                    lv_load = lv_loads_ria_rnd.pop()

                # get cable distributor of building
                lv_conn_target = list(graph.neighbors(lv_load))[0]

            # fallback: connect to station
            else:
                lv_conn_target = lv_grid_district.lv_grid.station()

                logger.warning('No valid conn. target found for {}.'
                               'Connected to {}.'.format(
                                   repr(generator), repr(lv_conn_target)))

            # determine appropriate type of cable
            branch_type = cable_type(
                generator.capacity / (cable_lf * cos_phi_gen), v_nom,
                lv_grid_district.lv_grid.network.static_data['LV_cables'])

            # connect to cable dist. of building
            branch = BranchDing0(length=1, kind='cable', type=branch_type)

            graph.add_edge(generator, lv_conn_target, branch=branch)

    return graph