Instruction:
Write a Python 3 function for
calculating the voltage delta for a stub branch.

Response:
def voltage_delta_stub(grid, tree, main_branch_node, stub_node, r_preceeding,
                       x_preceedig):
    """
    Determine voltage for stub branches

    Parameters
    ----------
    grid : LVGridDing0
        Ding0 grid object
    tree : :networkx:`NetworkX Graph Obj< >`
        Tree of grid topology
    main_branch_node : graph node
        Node of main branch that stub branch node in connected to
    main_branch : dict
        Nodes of main branch
    r_preceeding : float
        Resitance of preceeding grid
    x_preceeding : float
        Reactance of preceeding grid

    Return
    ------
    :any:`float`
        Delta voltage for node
    """
    cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load')
    cos_phi_feedin = cfg_ding0.get('assumptions', 'cos_phi_gen')
    v_nom = cfg_ding0.get('assumptions', 'lv_nominal_voltage')
    omega = 2 * math.pi * 50

    stub_branch = [_ for _ in grid.graph_branches_from_node(main_branch_node) if
                   _[0] == stub_node][0][1]
    r_stub = stub_branch['branch'].type['R'] * stub_branch[
        'branch'].length / 1e3
    x_stub = stub_branch['branch'].type['L'] / 1e3 * omega * \
             stub_branch['branch'].length / 1e3
    s_max_gen = [_.capacity / cos_phi_feedin
                 for _ in tree.successors(stub_node)
                 if isinstance(_, GeneratorDing0)]
    if s_max_gen:
        s_max_gen = s_max_gen[0]
        v_delta_stub_gen = voltage_delta_vde(v_nom, s_max_gen, r_stub + r_preceeding,
                                             x_stub + x_preceedig, cos_phi_feedin)
    else:
        v_delta_stub_gen = 0

    s_max_load = [_.peak_load / cos_phi_load
                  for _ in tree.successors(stub_node)
                  if isinstance(_, LVLoadDing0)]
    if s_max_load:
        s_max_load = s_max_load[0]
        v_delta_stub_load = voltage_delta_vde(v_nom, s_max_load, r_stub + r_preceeding,
                                              x_stub + x_preceedig, cos_phi_load)
    else:
        v_delta_stub_load = 0

    return [v_delta_stub_load, v_delta_stub_gen]


Instruction:
Can you generate the documentation for the following Python 3 function
def get_voltage_at_bus_bar(grid, tree):

    # voltage at substation bus bar
    r_mv_grid, x_mv_grid = get_mv_impedance(grid)

    r_trafo = sum([tr.r for tr in grid._station._transformers])
    x_trafo = sum([tr.x for tr in grid._station._transformers])

    cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load')
    cos_phi_feedin = cfg_ding0.get('assumptions', 'cos_phi_gen')
    v_nom = cfg_ding0.get('assumptions', 'lv_nominal_voltage')

    # loads and generators connected to bus bar
    bus_bar_load = sum(
        [node.peak_load for node in tree.successors(grid._station)
         if isinstance(node, LVLoadDing0)]) / cos_phi_load
    bus_bar_generation = sum(
        [node.capacity for node in tree.successors(grid._station)
         if isinstance(node, GeneratorDing0)]) / cos_phi_feedin

    v_delta_load_case_bus_bar = voltage_delta_vde(v_nom,
                                                  bus_bar_load,
                                                  (r_mv_grid + r_trafo),
                                                  (x_mv_grid + x_trafo),
                                                  cos_phi_load)
    v_delta_gen_case_bus_bar = voltage_delta_vde(v_nom,
                                                 bus_bar_generation,
                                                 (r_mv_grid + r_trafo),
                                                 -(x_mv_grid + x_trafo),
                                                 cos_phi_feedin)

    return v_delta_load_case_bus_bar, v_delta_gen_case_bus_bar

Response: Returns voltage level at bus bar of MV - LV substation


Instruction:
Given the following Python 3 function, write the documentation
def add_lv_load_area(self, lv_load_area):
        # TODO: check docstring
        """Adds a LV load_area to _lv_load_areas if not already existing

        Args
        ----
        lv_load_area: :shapely:`Shapely Polygon object<polygons>`
            Descr
        """
        self._lv_load_areas.append(lv_load_area)
        if not isinstance(lv_load_area, MVCableDistributorDing0):
            self.peak_load += lv_load_area.peak_load

Response: Adds a LV load_area to _lv_load_areas if not already existing.


Instruction:
Here you have a function in Python 3, explain what it does
def can_add_lv_load_area(self, node):
        # TODO: check docstring
        """Sums up peak load of LV stations

        That is, total peak load for satellite string

        Args
        ----
        node: GridDing0
            Descr

        Returns
        -------
        bool
            True if ????

        """
        # get power factor for loads
        cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load')

        lv_load_area = node.lv_load_area
        if lv_load_area not in self.lv_load_areas():  # and isinstance(lv_load_area, LVLoadAreaDing0):
            path_length_to_root = lv_load_area.mv_grid_district.mv_grid.graph_path_length(self.root_node, node)
            if ((path_length_to_root <= self.branch_length_max) and
                (lv_load_area.peak_load + self.peak_load) / cos_phi_load <= self.peak_load_max):
                return True
            else:
                return False

Response: Check if a node can add LV load area.


Instruction:
Can you write a function in Python 3 where it
applies Or - Opt intra - route operator to a given solution.

Response:
def operator_oropt(self, graph, solution, op_diff_round_digits, anim=None):
        # TODO: check docstring
        """Applies Or-Opt intra-route operator to solution

        Takes chains of nodes (length=3..1 consecutive nodes) from a given
        route and calculates savings when inserted into another position on the
        same route (all possible positions). Performes best move (max. saving)
        and starts over again with new route until no improvement is found.

        Args
        ----
        graph: :networkx:`NetworkX Graph Obj< >`
            A NetworkX graaph is used.
        solution: BaseSolution
            BaseSolution instance
        op_diff_round_digits: float
            Precision (floating point digits) for rounding route length differences.

            *Details*: In some cases when an exchange is performed on two routes with one node each,
            the difference between the both solutions (before and after the exchange) is not zero.
            This is due to internal rounding errors of float type. So the loop won't break
            (alternating between these two solutions), we need an additional criterion to avoid
            this behaviour: A threshold to handle values very close to zero as if they were zero
            (for a more detailed description of the matter see http://floating-point-gui.de or
            https://docs.python.org/3.5/tutorial/floatingpoint.html)
        anim: AnimationDing0
            AnimationDing0 object

        Returns
        -------
        LocalSearchSolution
           A solution (LocalSearchSolution class)

        Notes
        -----
        Since Or-Opt is an intra-route operator, it has not to be checked if route can allocate (Route's method
        can_allocate()) nodes during relocation regarding max. peak load/current because the line/cable type is the
        same along the entire route. However, node order within a route has an impact on the voltage stability
        so the check would be actually required. Due to large line capacity (load factor of lines/cables ~60 %)
        the voltage stability issues are neglected.

        (Inner) Loop variables:

        * s: length (count of consecutive nodes) of the chain that is moved. Values: 3..1
        * i: node that precedes the chain before moving (position in the route `tour`, not node name)
        * j: node that precedes the chain after moving (position in the route `tour`, not node name)

        Todo
        ----
        * insert literature reference for Or-algorithm here
        * Remove ugly nested loops, convert to more efficient matrix operations
        """
        no_ctr = 100
        # shorter var names for loop
        dm = graph._matrix
        dn = graph._nodes

        for route in solution.routes():

            # exclude routes with single high-demand nodes (Load Areas)
            if len(route._nodes) == 1:
                if solution._problem._is_aggregated[str(route._nodes[0])]:
                    continue

            n = len(route._nodes)+1

            # create tour by adding depot at start and end
            tour = [graph._depot] + route._nodes + [graph._depot]

            # Or-Opt: Search better solutions by checking possible chain moves
            while True:
                length = route.length()
                length_best = length

                for s in range(3,0,-1):
                    for i in range(1,n-s):
                        length_diff = (length -
                                       dm[dn[tour[i-1].name()]][dn[tour[i].name()]] -
                                       dm[dn[tour[i+s-1].name()]][dn[tour[i+s].name()]] +
                                       dm[dn[tour[i-1].name()]][dn[tour[i+s].name()]])
                        for j in range(i+s+1,n+1):
                            if j == n:
                                j2 = 1
                            else:
                                j2 = j+1
                            length_new = (length_diff +
                                          dm[dn[tour[j-1].name()]][dn[tour[i].name()]] +
                                          dm[dn[tour[i+s-1].name()]][dn[tour[j2-1].name()]] -
                                          dm[dn[tour[j-1].name()]][dn[tour[j2-1].name()]])
                            if length_new < length_best:
                                length_best = length_new
                                s_best, i_best, j_best = s, i, j
                if length_best < length:
                    tour = tour[0:i_best] + tour[i_best+s_best:j_best] + tour[i_best:i_best+s_best] + tour[j_best:n+1]

                    if anim is not None:
                        solution.draw_network(anim)

                # no improvement found
                if length_best == length:
                    # replace old route by new (same arg for allocation and deallocation since node order is considered at allocation)
                    solution._routes[solution._routes.index(route)].deallocate(tour[1:-1])
                    solution._routes[solution._routes.index(route)].allocate(tour[1:-1])

                    break

        #solution = LocalSearchSolution(solution, graph, new_routes)
        return solution


Instruction:
Make a summary of the following Python 3 code
def operator_relocate(self, graph, solution, op_diff_round_digits, anim):
        # shorter var names for loop
        dm = graph._matrix
        dn = graph._nodes

        # Relocate: Search better solutions by checking possible node moves
        while True:
            length_diff_best = 0

            for route in solution.routes():

                # exclude origin routes with single high-demand nodes (Load Areas)
                if len(route._nodes) == 1:
                    if solution._problem._is_aggregated[str(route._nodes[0])]:
                        continue

                # create tour by adding depot at start and end
                tour = [graph._depot] + route._nodes + [graph._depot]

                for target_route in solution.routes():

                    # exclude (origin+target) routes with single high-demand nodes (Load Areas)
                    if len(target_route._nodes) == 1:
                        if solution._problem._is_aggregated[str(target_route._nodes[0])]:
                            continue

                    target_tour = [graph._depot] + target_route._nodes + [graph._depot]

                    if route == target_route:
                        continue

                    n = len(route._nodes)
                    nt = len(target_route._nodes)+1

                    for i in range(0,n):
                        node = route._nodes[i]
                        for j in range(0,nt):
                            #target_node = target_route._nodes[j]

                            if target_route.can_allocate([node]):
                                length_diff = (-dm[dn[tour[i].name()]][dn[tour[i+1].name()]] -
                                                dm[dn[tour[i+1].name()]][dn[tour[i+2].name()]] +
                                                dm[dn[tour[i].name()]][dn[tour[i+2].name()]] +
                                                dm[dn[target_tour[j].name()]][dn[tour[i+1].name()]] +
                                                dm[dn[tour[i+1].name()]][dn[target_tour[j+1].name()]] -
                                                dm[dn[target_tour[j].name()]][dn[target_tour[j+1].name()]])

                                if length_diff < length_diff_best:
                                    length_diff_best = length_diff
                                    node_best, target_route_best, j_best = node, target_route, j

            if length_diff_best < 0:
                # insert new node
                target_route_best.insert([node_best], j_best)
                # remove empty routes from solution
                solution._routes = [route for route in solution._routes if route._nodes]

                if anim is not None:
                    solution.draw_network(anim)

                #print('Bessere Loesung gefunden:', node_best, target_node_best, target_route_best, length_diff_best)

            # no improvement found
            if round(length_diff_best, op_diff_round_digits) == 0:
                break

        return solution

Response: Applies Relocate inter - route operator to solution.


Instruction:
Can you tell what is the following Python 3 function doing
def operator_cross(self, graph, solution, op_diff_round_digits):
        # TODO: check docstring
        """applies Cross inter-route operator to solution

        Takes every node from every route and calculates savings when inserted
        into all possible positions in other routes. Insertion is done at
        position with max. saving and procedure starts over again with newly
        created graph as input. Stops when no improvement is found.

        Args
        ----
        graph: :networkx:`NetworkX Graph Obj< >`
            Descr
        solution: BaseSolution
            Descr
        op_diff_round_digits: float
            Precision (floating point digits) for rounding route length differences.

            *Details*: In some cases when an exchange is performed on two routes with one node each,
            the difference between the both solutions (before and after the exchange) is not zero.
            This is due to internal rounding errors of float type. So the loop won't break
            (alternating between these two solutions), we need an additional criterion to avoid
            this behaviour: A threshold to handle values very close to zero as if they were zero
            (for a more detaisled description of the matter see http://floating-point-gui.de or
            https://docs.python.org/3.5/tutorial/floatingpoint.html)

        Returns
        -------
        LocalSearchSolution
           A solution (LocalSearchSolution class)

        Todo
        ----
        * allow moves of a 2-node chain
        * Remove ugly nested loops, convert to more efficient matrix operations
        """

        # shorter var names for loop
        dm = graph._matrix
        dn = graph._nodes

Response: This function applies Cross inter - route operator to solution.


Instruction:
Implement a Python 3 function for
solving a given set of savings solution using local search.

Response:
def solve(self, graph, savings_solution, timeout, debug=False, anim=None):
        """Improve initial savings solution using local search

        Parameters
        ----------
        graph: :networkx:`NetworkX Graph Obj< >`
            Graph instance
        savings_solution: SavingsSolution
            initial solution of CVRP problem (instance of `SavingsSolution` class)
        timeout: int
            max processing time in seconds
        debug: bool, defaults to False
            If True, information is printed while routing
        anim: AnimationDing0
            AnimationDing0 object

        Returns
        -------
        LocalSearchSolution
           A solution (LocalSearchSolution class)

        """
        # TODO: If necessary, use timeout to set max processing time of local search

        # load threshold for operator (see exchange or relocate operator's description for more information)
        op_diff_round_digits = int(cfg_ding0.get('mv_routing', 'operator_diff_round_digits'))

        solution = LocalSearchSolution(graph, savings_solution)

        # FOR BENCHMARKING OF OPERATOR'S ORDER:
        #self.benchmark_operator_order(graph, savings_solution, op_diff_round_digits)

        for run in range(10):
            start = time.time()
            solution = self.operator_exchange(graph, solution, op_diff_round_digits, anim)
            time1 = time.time()
            if debug:
                logger.debug('Elapsed time (exchange, run {1}): {0}, '
                             'Solution\'s length: {2}'.format(
                    time1 - start, str(run), solution.length()))

            solution = self.operator_relocate(graph, solution, op_diff_round_digits, anim)
            time2 = time.time()
            if debug:
                logger.debug('Elapsed time (relocate, run {1}): {0}, '
                             'Solution\'s length: {2}'.format(
                    time2 - time1, str(run), solution.length()))

            solution = self.operator_oropt(graph, solution, op_diff_round_digits, anim)
            time3 = time.time()
            if debug:
                logger.debug('Elapsed time (oropt, run {1}): {0}, '
                             'Solution\'s length: {2}'.format(
                    time3 - time2, str(run), solution.length()))

        return solution


Instruction:
Make a summary of the following Python 3 code
def get_branches(grid):

    station = grid._station

    tree = nx.dfs_tree(grid._graph, station)

    # TODO: idea
    # 1. build tree from lv_grid station as root -> diretions should point to
    # descending leafs
    # 2. for analysis of current issues get list of descendants with
    # nx.descendants(tree, station). Sum peak load / gen capacity
    # 3. Extract nodes belonging to main route of a branch by checking all
    # successors if these are LVCalbleDistributors
    # notes and hints:
    # 1. associated edges can be accessed via grid._graph.in_edges(<node>)
    # respectively grid._graph.out_edges(<node>)
    # 2. when using nx.descendants(tree, station) make sure the order of nodes
    # is maintained as this is important to properly assess voltage and over-
    # loading issues

    # first_cbl_dists = [x for x in grid._graph.neighbors(station)
    #                    if isinstance(x, LVCableDistributorDing0)]

    # if len(first_cbl_dists) > 0:
    #     ancestors =  nx.ancestors(grid._graph, first_cbl_dists[0])
    # else:
    #     ancestors = None
    # return ancestors
    branch_heads = list(nx.neighbors(tree, station))

    descendants = {branch_head: list(nx.descendants(tree, branch_head)) for
                   branch_head in branch_heads}

    return descendants

Response: Get branches of sectoral loads


Instruction:
Here you have a function in Python 3, explain what it does
def add_mv_grid_district(self, mv_grid_district):
        # TODO: use setter method here (make attribute '_mv_grid_districts' private)
        if mv_grid_district not in self.mv_grid_districts():
            self._mv_grid_districts.append(mv_grid_district)

Response: Adds a MV grid_district to _mv_grid_districts if not already existing


Instruction:
Write a Python 3 script for
letting DING0 run by shouting at this method (or just call it from NetworkDing0 instance). This method is a wrapper for the main functionality of DING0. Parameters ---------- session : sqlalchemy.orm.session.Session Database session mv_grid_districts_no : List of Integers List of MV grid_districts/stations to be imported (if empty, all grid_districts & stations are imported) debug : bool, defaults to False If True, information is printed during process export_figures : bool, defaults to False If True, figures are shown or exported (default path: ~/.ding0/) during run. Returns ------- msg : str Message of invalidity of a grid district Notes ----- The steps performed in this method are to be kept in the given order since there are hard dependencies between them. Short description of all steps performed: * STEP 1: Import MV Grid Districts and subjacent objects Imports MV Grid Districts, HV-MV stations, Load Areas, LV Grid Districts and MV-LV stations, instantiates and initiates objects. * STEP 2: Import generators Conventional and renewable generators of voltage levels 4..7 are imported and added to corresponding grid. * STEP 3: Parametrize grid Parameters of MV grid are set such as voltage level and cable/line types according to MV Grid District's characteristics. * STEP 4: Validate MV Grid Districts Tests MV grid districts for validity concerning imported data such as count of Load Areas. * STEP 5: Build LV grids Builds LV grids for every non-aggregated LA in every MV Grid District using model grids. * STEP 6: Build MV grids Builds MV grid by performing a routing on Load Area centres to build ring topology. * STEP 7: Connect MV and LV generators Generators are connected to grids, used approach depends on voltage level. * STEP 8: Set IDs for all branches in MV and LV grids While IDs of imported objects can be derived from dataset's ID, branches are created in steps 5+6 and need unique IDs (e.g. for PF calculation). * STEP 9: Relocate switch disconnectors in MV grid Switch disconnectors are set during routing process (step 6) according to the load distribution within a ring. After further modifications of the grid within step 6+7 they have to be relocated (note: switch disconnectors are called circuit breakers in DING0 for historical reasons). * STEP 10: Open all switch disconnectors in MV grid Under normal conditions, rings are operated in open state (half-rings). Furthermore, this is required to allow powerflow for MV grid. * STEP 11: Do power flow analysis of MV grid The technically working MV grid created in step 6 was extended by satellite loads and generators. It is finally tested again using powerflow calculation. * STEP 12: Reinforce MV grid MV grid is eventually reinforced persuant to results from step 11. STEP 13: Close all switch disconnectors in MV grid The rings are finally closed to hold a complete graph (if the SDs are open, the edges adjacent to a SD will not be exported!)

Response:
def run_ding0(self, session, mv_grid_districts_no=None, debug=False, export_figures=False):
        """ Let DING0 run by shouting at this method (or just call
            it from NetworkDing0 instance). This method is a wrapper
            for the main functionality of DING0.

        Parameters
        ----------
        session : sqlalchemy.orm.session.Session
            Database session
        mv_grid_districts_no : List of Integers
            List of MV grid_districts/stations to be imported (if empty,
            all grid_districts & stations are imported)
        debug : bool, defaults to False
            If True, information is printed during process
        export_figures : bool, defaults to False
            If True, figures are shown or exported (default path: ~/.ding0/) during run.

        Returns
        -------
        msg : str
            Message of invalidity of a grid district

        Notes
        -----
        The steps performed in this method are to be kept in the given order
        since there are hard dependencies between them. Short description of
        all steps performed:

        * STEP 1: Import MV Grid Districts and subjacent objects

            Imports MV Grid Districts, HV-MV stations, Load Areas, LV Grid Districts
            and MV-LV stations, instantiates and initiates objects.

        * STEP 2: Import generators

            Conventional and renewable generators of voltage levels 4..7 are imported
            and added to corresponding grid.

        * STEP 3: Parametrize grid

            Parameters of MV grid are set such as voltage level and cable/line types
            according to MV Grid District's characteristics.

        * STEP 4: Validate MV Grid Districts

            Tests MV grid districts for validity concerning imported data such as
            count of Load Areas.

        * STEP 5: Build LV grids

            Builds LV grids for every non-aggregated LA in every MV Grid District
            using model grids.

        * STEP 6: Build MV grids

            Builds MV grid by performing a routing on Load Area centres to build
            ring topology.

        * STEP 7: Connect MV and LV generators

            Generators are connected to grids, used approach depends on voltage
            level.

        * STEP 8: Set IDs for all branches in MV and LV grids

            While IDs of imported objects can be derived from dataset's ID, branches
            are created in steps 5+6 and need unique IDs (e.g. for PF calculation).

        * STEP 9: Relocate switch disconnectors in MV grid

            Switch disconnectors are set during routing process (step 6) according
            to the load distribution within a ring. After further modifications of
            the grid within step 6+7 they have to be relocated (note: switch
            disconnectors are called circuit breakers in DING0 for historical reasons).

        * STEP 10: Open all switch disconnectors in MV grid

            Under normal conditions, rings are operated in open state (half-rings).
            Furthermore, this is required to allow powerflow for MV grid.

        * STEP 11: Do power flow analysis of MV grid

            The technically working MV grid created in step 6 was extended by satellite
            loads and generators. It is finally tested again using powerflow calculation.

        * STEP 12: Reinforce MV grid

            MV grid is eventually reinforced persuant to results from step 11.

        STEP 13: Close all switch disconnectors in MV grid
            The rings are finally closed to hold a complete graph (if the SDs are open,
            the edges adjacent to a SD will not be exported!)
        """
        if debug:
            start = time.time()

        # STEP 1: Import MV Grid Districts and subjacent objects
        self.import_mv_grid_districts(session,
                                      mv_grid_districts_no=mv_grid_districts_no)

        # STEP 2: Import generators
        self.import_generators(session, debug=debug)

        # STEP 3: Parametrize MV grid
        self.mv_parametrize_grid(debug=debug)

        # STEP 4: Validate MV Grid Districts
        msg = self.validate_grid_districts()

        # STEP 5: Build LV grids
        self.build_lv_grids()

        # STEP 6: Build MV grids
        self.mv_routing(debug=False)
        if export_figures:
            grid = self._mv_grid_districts[0].mv_grid
            plot_mv_topology(grid, subtitle='Routing completed', filename='1_routing_completed.png')

        # STEP 7: Connect MV and LV generators
        self.connect_generators(debug=False)
        if export_figures:
            plot_mv_topology(grid, subtitle='Generators connected', filename='2_generators_connected.png')

        # STEP 8: Set IDs for all branches in MV and LV grids
        self.set_branch_ids()

        # STEP 9: Relocate switch disconnectors in MV grid
        self.set_circuit_breakers(debug=debug)
        if export_figures:
            plot_mv_topology(grid, subtitle='Circuit breakers relocated', filename='3_circuit_breakers_relocated.png')

        # STEP 10: Open all switch disconnectors in MV grid
        self.control_circuit_breakers(mode='open')

        # STEP 11: Do power flow analysis of MV grid
        self.run_powerflow(session, method='onthefly', export_pypsa=False, debug=debug)
        if export_figures:
            plot_mv_topology(grid, subtitle='PF result (load case)',
                             filename='4_PF_result_load.png',
                             line_color='loading', node_color='voltage', testcase='load')
            plot_mv_topology(grid, subtitle='PF result (feedin case)',
                             filename='5_PF_result_feedin.png',
                             line_color='loading', node_color='voltage', testcase='feedin')

        # STEP 12: Reinforce MV grid
        self.reinforce_grid()

        # STEP 13: Close all switch disconnectors in MV grid
        self.control_circuit_breakers(mode='close')

        if export_figures:
            plot_mv_topology(grid, subtitle='Final grid PF result (load case)',
                             filename='6_final_grid_PF_result_load.png',
                             line_color='loading', node_color='voltage', testcase='load')
            plot_mv_topology(grid, subtitle='Final grid PF result (feedin case)',
                             filename='7_final_grid_PF_result_feedin.png',
                             line_color='loading', node_color='voltage', testcase='feedin')

        if debug:
            logger.info('Elapsed time for {0} MV Grid Districts (seconds): {1}'.format(
                str(len(mv_grid_districts_no)), time.time() - start))

        return msg


Instruction:
Make a summary of the following Python 3 code
def get_mvgd_lvla_lvgd_obj_from_id(self):

        mv_grid_districts_dict = {}
        lv_load_areas_dict = {}
        lv_grid_districts_dict = {}
        lv_stations_dict = {}

        for mv_grid_district in self.mv_grid_districts():
            mv_grid_districts_dict[mv_grid_district.id_db] = mv_grid_district
            for lv_load_area in mv_grid_district.lv_load_areas():
                lv_load_areas_dict[lv_load_area.id_db] = lv_load_area
                for lv_grid_district in lv_load_area.lv_grid_districts():
                    lv_grid_districts_dict[lv_grid_district.id_db] = lv_grid_district
                    lv_stations_dict[lv_grid_district.lv_grid.station().id_db] = lv_grid_district.lv_grid.station()

        return mv_grid_districts_dict, lv_load_areas_dict, lv_grid_districts_dict, lv_stations_dict

Response: Build dict with mapping from MVLoadAreaDing0 id to LVStationDing0 object and LVLoadAreaDing0 id to LVStationDing0 object.


Instruction:
Given the following Python 3 function, write the documentation
def build_mv_grid_district(self, poly_id, subst_id, grid_district_geo_data,
                        station_geo_data):
        """Initiates single MV grid_district including station and grid

        Parameters
        ----------
        poly_id: int
            ID of grid_district according to database table. Also used as ID for created grid #TODO: check type
        subst_id: int
            ID of station according to database table #TODO: check type
        grid_district_geo_data: :shapely:`Shapely Polygon object<polygons>`
            Polygon of grid district
        station_geo_data: :shapely:`Shapely Point object<points>`
            Point of station

        Returns
        -------
        :shapely:`Shapely Polygon object<polygons>`
            Description of return #TODO: check

        """

        mv_station = MVStationDing0(id_db=subst_id, geo_data=station_geo_data)

        mv_grid = MVGridDing0(network=self,
                              id_db=poly_id,
                              station=mv_station)
        mv_grid_district = MVGridDistrictDing0(id_db=poly_id,
                                               mv_grid=mv_grid,
                                               geo_data=grid_district_geo_data)
        mv_grid.grid_district = mv_grid_district
        mv_station.grid = mv_grid

        self.add_mv_grid_district(mv_grid_district)

        return mv_grid_district

Response: Builds MV grid district and station for a single MV grid.


Instruction:
Can you implement a function in Python 3 that
builds and associates lv_grid_districts and lv_stations from LV load area and LV stations.

Response:
def build_lv_grid_district(self,
                               lv_load_area,
                               lv_grid_districts,
                               lv_stations):
        """Instantiates and associates lv_grid_district incl grid and station.

        The instantiation creates more or less empty objects including relevant
        data for transformer choice and grid creation

        Parameters
        ----------
        lv_load_area: :shapely:`Shapely Polygon object<polygons>`
            load_area object
        lv_grid_districts: :pandas:`pandas.DataFrame<dataframe>`
            Table containing lv_grid_districts of according load_area
        lv_stations : :pandas:`pandas.DataFrame<dataframe>`
            Table containing lv_stations of according load_area
        """

        # There's no LVGD for current LA
        # -> TEMP WORKAROUND: Create single LVGD from LA, replace unknown valuess by zero
        # TODO: Fix #155 (see also: data_processing #68)
        if len(lv_grid_districts) == 0:
            # raise ValueError(
            #     'Load Area {} has no LVGD - please re-open #155'.format(
            #         repr(lv_load_area)))
            geom = wkt_dumps(lv_load_area.geo_area)

            lv_grid_districts = \
                lv_grid_districts.append(
                    pd.DataFrame(
                        {'la_id': [lv_load_area.id_db],
                         'geom': [geom],
                         'population': [0],

                         'peak_load_residential': [lv_load_area.peak_load_residential],
                         'peak_load_retail': [lv_load_area.peak_load_retail],
                         'peak_load_industrial': [lv_load_area.peak_load_industrial],
                         'peak_load_agricultural': [lv_load_area.peak_load_agricultural],

                         'sector_count_residential': [0],
                         'sector_count_retail': [0],
                         'sector_count_industrial': [0],
                         'sector_count_agricultural': [0],

                         'sector_consumption_residential': [0],
                         'sector_consumption_retail': [0],
                         'sector_consumption_industrial': [0],
                         'sector_consumption_agricultural': [0]
                         },
                        index=[lv_load_area.id_db]
                    )
                )

        lv_nominal_voltage = cfg_ding0.get('assumptions', 'lv_nominal_voltage')

        # Associate lv_grid_district to load_area
        for id, row in lv_grid_districts.iterrows():
            lv_grid_district = LVGridDistrictDing0(
                id_db=id,
                lv_load_area=lv_load_area,
                geo_data=wkt_loads(row['geom']),
                population=0 if isnan(row['population']) else int(row['population']),
                peak_load_residential=row['peak_load_residential'],
                peak_load_retail=row['peak_load_retail'],
                peak_load_industrial=row['peak_load_industrial'],
                peak_load_agricultural=row['peak_load_agricultural'],
                peak_load=(row['peak_load_residential'] +
                               row['peak_load_retail'] +
                               row['peak_load_industrial'] +
                               row['peak_load_agricultural']),
                sector_count_residential=int(row['sector_count_residential']),
                sector_count_retail=int(row['sector_count_retail']),
                sector_count_industrial=int(row['sector_count_industrial']),
                sector_count_agricultural=int(row['sector_count_agricultural']),
                sector_consumption_residential=row[
                    'sector_consumption_residential'],
                sector_consumption_retail=row['sector_consumption_retail'],
                sector_consumption_industrial=row[
                    'sector_consumption_industrial'],
                sector_consumption_agricultural=row[
                    'sector_consumption_agricultural'])

            # be aware, lv_grid takes grid district's geom!
            lv_grid = LVGridDing0(network=self,
                                  grid_district=lv_grid_district,
                                  id_db=id,
                                  geo_data=wkt_loads(row['geom']),
                                  v_level=lv_nominal_voltage)

            # create LV station
            lv_station = LVStationDing0(
                id_db=id,
                grid=lv_grid,
                lv_load_area=lv_load_area,
                geo_data=wkt_loads(lv_stations.loc[id, 'geom'])
                            if id in lv_stations.index.values
                            else lv_load_area.geo_centre,
                peak_load=lv_grid_district.peak_load)

            # assign created objects
            # note: creation of LV grid is done separately,
            # see NetworkDing0.build_lv_grids()
            lv_grid.add_station(lv_station)
            lv_grid_district.lv_grid = lv_grid
            lv_load_area.add_lv_grid_district(lv_grid_district)


Instruction:
Explain what the following Python 3 code does
def import_mv_grid_districts(self, session, mv_grid_districts_no=None):

        # check arguments
        if not all(isinstance(_, int) for _ in mv_grid_districts_no):
            raise TypeError('`mv_grid_districts` has to be a list of integers.')

        # get srid settings from config
        try:
            srid = str(int(cfg_ding0.get('geo', 'srid')))
        except OSError:
            logger.exception('cannot open config file.')

        # build SQL query
        grid_districts = session.query(self.orm['orm_mv_grid_districts'].subst_id,
                                       func.ST_AsText(func.ST_Transform(
                                           self.orm['orm_mv_grid_districts'].geom, srid)). \
                                       label('poly_geom'),
                                       func.ST_AsText(func.ST_Transform(
                                           self.orm['orm_mv_stations'].point, srid)). \
                                       label('subs_geom')).\
            join(self.orm['orm_mv_stations'], self.orm['orm_mv_grid_districts'].subst_id ==
                 self.orm['orm_mv_stations'].subst_id).\
            filter(self.orm['orm_mv_grid_districts'].subst_id.in_(mv_grid_districts_no)). \
            filter(self.orm['version_condition_mvgd']). \
            filter(self.orm['version_condition_mv_stations']). \
            distinct()

        # read MV data from db
        mv_data = pd.read_sql_query(grid_districts.statement,
                                    session.bind,
                                    index_col='subst_id')

        # iterate over grid_district/station datasets and initiate objects
        for poly_id, row in mv_data.iterrows():
            subst_id = poly_id
            region_geo_data = wkt_loads(row['poly_geom'])

            # transform `region_geo_data` to epsg 3035
            # to achieve correct area calculation of mv_grid_district
            station_geo_data = wkt_loads(row['subs_geom'])
            # projection = partial(
            #     pyproj.transform,
            #     pyproj.Proj(init='epsg:4326'),  # source coordinate system
            #     pyproj.Proj(init='epsg:3035'))  # destination coordinate system
            #
            # region_geo_data = transform(projection, region_geo_data)

            mv_grid_district = self.build_mv_grid_district(poly_id,
                                             subst_id,
                                             region_geo_data,
                                             station_geo_data)

            # import all lv_stations within mv_grid_district
            lv_stations = self.import_lv_stations(session)

            # import all lv_grid_districts within mv_grid_district
            lv_grid_districts = self.import_lv_grid_districts(session, lv_stations)

            # import load areas
            self.import_lv_load_areas(session,
                                      mv_grid_district,
                                      lv_grid_districts,
                                      lv_stations)

            # add sum of peak loads of underlying lv grid_districts to mv_grid_district
            mv_grid_district.add_peak_demand()

        logger.info('=====> MV Grid Districts imported')

Response: Imports MV Grid Districts HV - MV stations Load Areas LV Grid Districts and LV grid districts from database.


Instruction:
How would you code a function in Python 3 to
import load areas from database for a single MV grid district and LV stations.

Response:
def import_lv_load_areas(self, session, mv_grid_district, lv_grid_districts,
                             lv_stations):
        """Imports load_areas (load areas) from database for a single MV grid_district

        Parameters
        ----------
        session : sqlalchemy.orm.session.Session
            Database session
        mv_grid_district : MV grid_district/station (instance of MVGridDistrictDing0 class) for
            which the import of load areas is performed
        lv_grid_districts: DataFrame
            LV grid districts within this mv_grid_district
        lv_stations: :pandas:`pandas.DataFrame<dataframe>`
            LV stations within this mv_grid_district
        """

        # get ding0s' standard CRS (SRID)
        srid = str(int(cfg_ding0.get('geo', 'srid')))
        # SET SRID 3035 to achieve correct area calculation of lv_grid_district
        #srid = '3035'

        # threshold: load area peak load, if peak load < threshold => disregard
        # load area
        lv_loads_threshold = cfg_ding0.get('mv_routing', 'load_area_threshold')

        gw2kw = 10 ** 6  # load in database is in GW -> scale to kW

        # build SQL query
        lv_load_areas_sqla = session.query(
            self.orm['orm_lv_load_areas'].id.label('id_db'),
            self.orm['orm_lv_load_areas'].zensus_sum,
            self.orm['orm_lv_load_areas'].zensus_count.label('zensus_cnt'),
            self.orm['orm_lv_load_areas'].ioer_sum,
            self.orm['orm_lv_load_areas'].ioer_count.label('ioer_cnt'),
            self.orm['orm_lv_load_areas'].area_ha.label('area'),
            self.orm['orm_lv_load_areas'].sector_area_residential,
            self.orm['orm_lv_load_areas'].sector_area_retail,
            self.orm['orm_lv_load_areas'].sector_area_industrial,
            self.orm['orm_lv_load_areas'].sector_area_agricultural,
            self.orm['orm_lv_load_areas'].sector_share_residential,
            self.orm['orm_lv_load_areas'].sector_share_retail,
            self.orm['orm_lv_load_areas'].sector_share_industrial,
            self.orm['orm_lv_load_areas'].sector_share_agricultural,
            self.orm['orm_lv_load_areas'].sector_count_residential,
            self.orm['orm_lv_load_areas'].sector_count_retail,
            self.orm['orm_lv_load_areas'].sector_count_industrial,
            self.orm['orm_lv_load_areas'].sector_count_agricultural,
            self.orm['orm_lv_load_areas'].nuts.label('nuts_code'),
            func.ST_AsText(func.ST_Transform(self.orm['orm_lv_load_areas'].geom, srid)).\
                label('geo_area'),
            func.ST_AsText(func.ST_Transform(self.orm['orm_lv_load_areas'].geom_centre, srid)).\
                label('geo_centre'),
            (self.orm['orm_lv_load_areas'].sector_peakload_residential * gw2kw).\
                label('peak_load_residential'),
            (self.orm['orm_lv_load_areas'].sector_peakload_retail * gw2kw).\
                label('peak_load_retail'),
            (self.orm['orm_lv_load_areas'].sector_peakload_industrial * gw2kw).\
                label('peak_load_industrial'),
            (self.orm['orm_lv_load_areas'].sector_peakload_agricultural * gw2kw).\
                label('peak_load_agricultural'),
            ((self.orm['orm_lv_load_areas'].sector_peakload_residential
              + self.orm['orm_lv_load_areas'].sector_peakload_retail
              + self.orm['orm_lv_load_areas'].sector_peakload_industrial
              + self.orm['orm_lv_load_areas'].sector_peakload_agricultural)
             * gw2kw).label('peak_load')). \
            filter(self.orm['orm_lv_load_areas'].subst_id == mv_grid_district. \
                   mv_grid._station.id_db).\
            filter(((self.orm['orm_lv_load_areas'].sector_peakload_residential  # only pick load areas with peak load > lv_loads_threshold
                     + self.orm['orm_lv_load_areas'].sector_peakload_retail
                     + self.orm['orm_lv_load_areas'].sector_peakload_industrial
                     + self.orm['orm_lv_load_areas'].sector_peakload_agricultural)
                       * gw2kw) > lv_loads_threshold). \
            filter(self.orm['version_condition_la'])

        # read data from db
        lv_load_areas = pd.read_sql_query(lv_load_areas_sqla.statement,
                                          session.bind,
                                          index_col='id_db')

        # create load_area objects from rows and add them to graph
        for id_db, row in lv_load_areas.iterrows():

            # create LV load_area object
            lv_load_area = LVLoadAreaDing0(id_db=id_db,
                                           db_data=row,
                                           mv_grid_district=mv_grid_district,
                                           peak_load=row['peak_load'])

            # sub-selection of lv_grid_districts/lv_stations within one
            # specific load area
            lv_grid_districts_per_load_area = lv_grid_districts.\
                loc[lv_grid_districts['la_id'] == id_db]
            lv_stations_per_load_area = lv_stations.\
                loc[lv_stations['la_id'] == id_db]

            self.build_lv_grid_district(lv_load_area,
                                        lv_grid_districts_per_load_area,
                                        lv_stations_per_load_area)

            # create new centre object for Load Area
            lv_load_area_centre = LVLoadAreaCentreDing0(id_db=id_db,
                                                        geo_data=wkt_loads(row['geo_centre']),
                                                        lv_load_area=lv_load_area,
                                                        grid=mv_grid_district.mv_grid)
            # links the centre object to Load Area
            lv_load_area.lv_load_area_centre = lv_load_area_centre

            # add Load Area to MV grid district (and add centre object to MV gris district's graph)
            mv_grid_district.add_lv_load_area(lv_load_area)


Instruction:
Make a summary of the following Python 3 code
def import_lv_grid_districts(self, session, lv_stations):

        # get ding0s' standard CRS (SRID)
        srid = str(int(cfg_ding0.get('geo', 'srid')))
        # SET SRID 3035 to achieve correct area calculation of lv_grid_district
        # srid = '3035'

        gw2kw = 10 ** 6  # load in database is in GW -> scale to kW

        # 1. filter grid districts of relevant load area
        lv_grid_districs_sqla = session.query(
            self.orm['orm_lv_grid_district'].mvlv_subst_id,
            self.orm['orm_lv_grid_district'].la_id,
            self.orm['orm_lv_grid_district'].zensus_sum.label('population'),
            (self.orm[
                 'orm_lv_grid_district'].sector_peakload_residential * gw2kw).
                label('peak_load_residential'),
            (self.orm['orm_lv_grid_district'].sector_peakload_retail * gw2kw).
                label('peak_load_retail'),
            (self.orm[
                 'orm_lv_grid_district'].sector_peakload_industrial * gw2kw).
                label('peak_load_industrial'),
            (self.orm[
                 'orm_lv_grid_district'].sector_peakload_agricultural * gw2kw).
                label('peak_load_agricultural'),
            ((self.orm['orm_lv_grid_district'].sector_peakload_residential
              + self.orm['orm_lv_grid_district'].sector_peakload_retail
              + self.orm['orm_lv_grid_district'].sector_peakload_industrial
              + self.orm['orm_lv_grid_district'].sector_peakload_agricultural)
             * gw2kw).label('peak_load'),
            func.ST_AsText(func.ST_Transform(
                self.orm['orm_lv_grid_district'].geom, srid)).label('geom'),
            self.orm['orm_lv_grid_district'].sector_count_residential,
            self.orm['orm_lv_grid_district'].sector_count_retail,
            self.orm['orm_lv_grid_district'].sector_count_industrial,
            self.orm['orm_lv_grid_district'].sector_count_agricultural,
            (self.orm[
                 'orm_lv_grid_district'].sector_consumption_residential * gw2kw). \
                label('sector_consumption_residential'),
            (self.orm['orm_lv_grid_district'].sector_consumption_retail * gw2kw). \
                label('sector_consumption_retail'),
            (self.orm[
                'orm_lv_grid_district'].sector_consumption_industrial * gw2kw). \
                label('sector_consumption_industrial'),
            (self.orm[
                'orm_lv_grid_district'].sector_consumption_agricultural * gw2kw). \
                label('sector_consumption_agricultural'),
            self.orm['orm_lv_grid_district'].mvlv_subst_id). \
            filter(self.orm['orm_lv_grid_district'].mvlv_subst_id.in_(
            lv_stations.index.tolist())). \
            filter(self.orm['version_condition_lvgd'])

        # read data from db
        lv_grid_districts = pd.read_sql_query(lv_grid_districs_sqla.statement,
                                              session.bind,
                                              index_col='mvlv_subst_id')

        lv_grid_districts[
            ['sector_count_residential',
             'sector_count_retail',
             'sector_count_industrial',
             'sector_count_agricultural']] = lv_grid_districts[
            ['sector_count_residential',
             'sector_count_retail',
             'sector_count_industrial',
             'sector_count_agricultural']].fillna(0)

        return lv_grid_districts

Response: Imports all LV grid districts within given load area.


Instruction:
Can you tell what is the following Python 3 function doing
def import_lv_stations(self, session):

        # get ding0s' standard CRS (SRID)
        srid = str(int(cfg_ding0.get('geo', 'srid')))

        # get list of mv grid districts
        mv_grid_districts = list(self.get_mvgd_lvla_lvgd_obj_from_id()[0])

        lv_stations_sqla = session.query(self.orm['orm_lv_stations'].mvlv_subst_id,
                                         self.orm['orm_lv_stations'].la_id,
                                         func.ST_AsText(func.ST_Transform(
                                           self.orm['orm_lv_stations'].geom, srid)). \
                                         label('geom')).\
            filter(self.orm['orm_lv_stations'].subst_id.in_(mv_grid_districts)). \
            filter(self.orm['version_condition_mvlvst'])

        # read data from db
        lv_grid_stations = pd.read_sql_query(lv_stations_sqla.statement,
                                             session.bind,
                                             index_col='mvlv_subst_id')
        return lv_grid_stations

Response: Import LV stations within the given load area.


Instruction:
Create a Python 3 function for
importing renewable and conventional generators and returns a new tuple of the new generators and conventional generators.

Response:
def import_generators(self, session, debug=False):
        """
        Imports renewable (res) and conventional (conv) generators

        Args:
            session : sqlalchemy.orm.session.Session
                Database session
            debug: If True, information is printed during process
        Notes:
            Connection of generators is done later on in NetworkDing0's method connect_generators()
        """

        def import_res_generators():
            """Imports renewable (res) generators"""

            # build query
            generators_sqla = session.query(
                self.orm['orm_re_generators'].columns.id,
                self.orm['orm_re_generators'].columns.subst_id,
                self.orm['orm_re_generators'].columns.la_id,
                self.orm['orm_re_generators'].columns.mvlv_subst_id,
                self.orm['orm_re_generators'].columns.electrical_capacity,
                self.orm['orm_re_generators'].columns.generation_type,
                self.orm['orm_re_generators'].columns.generation_subtype,
                self.orm['orm_re_generators'].columns.voltage_level,
                self.orm['orm_re_generators'].columns.w_id,
                func.ST_AsText(func.ST_Transform(
                    self.orm['orm_re_generators'].columns.rea_geom_new, srid)).label('geom_new'),
                func.ST_AsText(func.ST_Transform(
                    self.orm['orm_re_generators'].columns.geom, srid)).label('geom')
            ). \
                filter(
                self.orm['orm_re_generators'].columns.subst_id.in_(list(mv_grid_districts_dict))). \
                filter(self.orm['orm_re_generators'].columns.voltage_level.in_([4, 5, 6, 7])). \
                filter(self.orm['version_condition_re'])

            # read data from db
            generators = pd.read_sql_query(generators_sqla.statement,
                                           session.bind,
                                           index_col='id')
            # define generators with unknown subtype as 'unknown'
            generators.loc[generators[
                               'generation_subtype'].isnull(),
                           'generation_subtype'] = 'unknown'

            for id_db, row in generators.iterrows():

                # treat generators' geom:
                # use geom_new (relocated genos from data processing)
                # otherwise use original geom from EnergyMap
                if row['geom_new']:
                    geo_data = wkt_loads(row['geom_new'])
                elif not row['geom_new']:
                    geo_data = wkt_loads(row['geom'])
                    logger.warning(
                        'Generator {} has no geom_new entry,'
                        'EnergyMap\'s geom entry will be used.'.format(
                        id_db))
                # if no geom is available at all, skip generator
                elif not row['geom']:
                    #geo_data =
                    logger.error('Generator {} has no geom entry either'
                                 'and will be skipped.'.format(id_db))
                    continue

                # look up MV grid
                mv_grid_district_id = row['subst_id']
                mv_grid = mv_grid_districts_dict[mv_grid_district_id].mv_grid

                # create generator object
                if row['generation_type'] in ['solar', 'wind']:
                    generator = GeneratorFluctuatingDing0(
                        id_db=id_db,
                        mv_grid=mv_grid,
                        capacity=row['electrical_capacity'],
                        type=row['generation_type'],
                        subtype=row['generation_subtype'],
                        v_level=int(row['voltage_level']),
                        weather_cell_id=row['w_id'])
                else:
                    generator = GeneratorDing0(
                        id_db=id_db,
                        mv_grid=mv_grid,
                        capacity=row['electrical_capacity'],
                        type=row['generation_type'],
                        subtype=row['generation_subtype'],
                        v_level=int(row['voltage_level']))

                # MV generators
                if generator.v_level in [4, 5]:
                    generator.geo_data = geo_data
                    mv_grid.add_generator(generator)

                # LV generators
                elif generator.v_level in [6, 7]:

                    # look up MV-LV substation id
                    mvlv_subst_id = row['mvlv_subst_id']

                    # if there's a LVGD id
                    if mvlv_subst_id and not isnan(mvlv_subst_id):
                        # assume that given LA exists
                        try:
                            # get LVGD
                            lv_station = lv_stations_dict[mvlv_subst_id]
                            lv_grid_district = lv_station.grid.grid_district
                            generator.lv_grid = lv_station.grid

                            # set geom (use original from db)
                            generator.geo_data = geo_data

                        # if LA/LVGD does not exist, choose random LVGD and move generator to station of LVGD
                        # this occurs due to exclusion of LA with peak load < 1kW
                        except:
                            lv_grid_district = random.choice(list(lv_grid_districts_dict.values()))

                            generator.lv_grid = lv_grid_district.lv_grid
                            generator.geo_data = lv_grid_district.lv_grid.station().geo_data

                            logger.warning('Generator {} cannot be assigned to '
                                           'non-existent LV Grid District and was '
                                           'allocated to a random LV Grid District ({}).'.format(
                                            repr(generator), repr(lv_grid_district)))
                            pass

                    else:
                        lv_grid_district = random.choice(list(lv_grid_districts_dict.values()))

                        generator.lv_grid = lv_grid_district.lv_grid
                        generator.geo_data = lv_grid_district.lv_grid.station().geo_data

                        logger.warning('Generator {} has no la_id and was '
                                       'assigned to a random LV Grid District ({}).'.format(
                                        repr(generator), repr(lv_grid_district)))

                    generator.lv_load_area = lv_grid_district.lv_load_area
                    lv_grid_district.lv_grid.add_generator(generator)

        def import_conv_generators():
            """Imports conventional (conv) generators"""

            # build query
            generators_sqla = session.query(
                self.orm['orm_conv_generators'].columns.id,
                self.orm['orm_conv_generators'].columns.subst_id,
                self.orm['orm_conv_generators'].columns.name,
                self.orm['orm_conv_generators'].columns.capacity,
                self.orm['orm_conv_generators'].columns.fuel,
                self.orm['orm_conv_generators'].columns.voltage_level,
                func.ST_AsText(func.ST_Transform(
                    self.orm['orm_conv_generators'].columns.geom, srid)).label('geom')). \
                filter(
                self.orm['orm_conv_generators'].columns.subst_id.in_(list(mv_grid_districts_dict))). \
                filter(self.orm['orm_conv_generators'].columns.voltage_level.in_([4, 5, 6])). \
                filter(self.orm['version_condition_conv'])

            # read data from db
            generators = pd.read_sql_query(generators_sqla.statement,
                                           session.bind,
                                           index_col='id')

            for id_db, row in generators.iterrows():

                # look up MV grid
                mv_grid_district_id = row['subst_id']
                mv_grid = mv_grid_districts_dict[mv_grid_district_id].mv_grid

                # create generator object
                generator = GeneratorDing0(id_db=id_db,
                                           name=row['name'],
                                           geo_data=wkt_loads(row['geom']),
                                           mv_grid=mv_grid,
                                           capacity=row['capacity'],
                                           type=row['fuel'],
                                           subtype='unknown',
                                           v_level=int(row['voltage_level']))

                # add generators to graph
                if generator.v_level in [4, 5]:
                    mv_grid.add_generator(generator)
                # there's only one conv. geno with v_level=6 -> connect to MV grid
                elif generator.v_level in [6]:
                    generator.v_level = 5
                    mv_grid.add_generator(generator)

        # get ding0s' standard CRS (SRID)
        srid = str(int(cfg_ding0.get('geo', 'srid')))

        # get predefined random seed and initialize random generator
        seed = int(cfg_ding0.get('random', 'seed'))
        random.seed(a=seed)

        # build dicts to map MV grid district and Load Area ids to related objects
        mv_grid_districts_dict,\
        lv_load_areas_dict,\
        lv_grid_districts_dict,\
        lv_stations_dict = self.get_mvgd_lvla_lvgd_obj_from_id()

        # import renewable generators
        import_res_generators()

        # import conventional generators
        import_conv_generators()

        logger.info('=====> Generators imported')


Instruction:
Can you implement a function in Python 3 that
loads parameters from config files Returns ------- cfg_dict int-----------

Response:
def import_config(self):
        """ Loads parameters from config files

        Returns
        -------
        int
            config object #TODO check type
        """

        # load parameters from configs
        cfg_ding0.load_config('config_db_tables.cfg')
        cfg_ding0.load_config('config_calc.cfg')
        cfg_ding0.load_config('config_files.cfg')
        cfg_ding0.load_config('config_misc.cfg')

        cfg_dict = cfg_ding0.cfg._sections

        return cfg_dict


Instruction:
Write a Python 3 function for
creating a new PFConfigDing0 object and imports config from file

Response:
def import_pf_config(self):
        """ Creates power flow config class and imports config from file

        Returns
        -------
        PFConfigDing0
            PFConfigDing0 object
        """

        scenario = cfg_ding0.get("powerflow", "test_grid_stability_scenario")
        start_hour = int(cfg_ding0.get("powerflow", "start_hour"))
        end_hour = int(cfg_ding0.get("powerflow", "end_hour"))
        start_time = datetime(1970, 1, 1, 00, 00, 0)

        resolution = cfg_ding0.get("powerflow", "resolution")
        srid = str(int(cfg_ding0.get('geo', 'srid')))

        return PFConfigDing0(scenarios=[scenario],
                             timestep_start=start_time,
                             timesteps_count=end_hour-start_hour,
                             srid=srid,
                             resolution=resolution)


Instruction:
Make a summary of the following Python 3 code
def import_static_data(self):

        package_path = ding0.__path__[0]

        static_data = {}

        equipment_mv_parameters_trafos = cfg_ding0.get('equipment',
                                                       'equipment_mv_parameters_trafos')
        static_data['MV_trafos'] = pd.read_csv(os.path.join(package_path, 'data',
                                   equipment_mv_parameters_trafos),
                                   comment='#',
                                   delimiter=',',
                                   decimal='.',
                                   converters={'S_nom': lambda x: int(x)})

        # import equipment
        equipment_mv_parameters_lines = cfg_ding0.get('equipment',
                                                      'equipment_mv_parameters_lines')
        static_data['MV_overhead_lines'] = pd.read_csv(os.path.join(package_path, 'data',
                                           equipment_mv_parameters_lines),
                                           comment='#',
                                           converters={'I_max_th': lambda x: int(x),
                                                       'U_n': lambda x: int(x),
                                                       'reinforce_only': lambda x: int(x)})

        equipment_mv_parameters_cables = cfg_ding0.get('equipment',
                                                       'equipment_mv_parameters_cables')
        static_data['MV_cables'] = pd.read_csv(os.path.join(package_path, 'data',
                                   equipment_mv_parameters_cables),
                                   comment='#',
                                   converters={'I_max_th': lambda x: int(x),
                                               'U_n': lambda x: int(x),
                                               'reinforce_only': lambda x: int(x)})

        equipment_lv_parameters_cables = cfg_ding0.get('equipment',
                                                       'equipment_lv_parameters_cables')
        static_data['LV_cables'] = pd.read_csv(os.path.join(package_path, 'data',
                                   equipment_lv_parameters_cables),
                                   comment='#',
                                   index_col='name',
                                   converters={'I_max_th': lambda x: int(x), 'U_n': lambda x: int(x)})

        equipment_lv_parameters_trafos = cfg_ding0.get('equipment',
                                                       'equipment_lv_parameters_trafos')
        static_data['LV_trafos'] = pd.read_csv(os.path.join(package_path, 'data',
                                   equipment_lv_parameters_trafos),
                                   comment='#',
                                   delimiter=',',
                                   decimal='.',
                                   converters={'S_nom': lambda x: int(x)})

        # import LV model grids
        model_grids_lv_string_properties = cfg_ding0.get('model_grids',
                                                         'model_grids_lv_string_properties')
        static_data['LV_model_grids_strings'] = pd.read_csv(os.path.join(package_path, 'data',
                                                model_grids_lv_string_properties),
                                                comment='#',
                                                delimiter=';',
                                                decimal=',',
                                                index_col='string_id',
                                                converters={'string_id': lambda x: int(x),
                                                            'type': lambda x: int(x),
                                                            'Kerber Original': lambda x: int(x),
                                                            'count house branch': lambda x: int(x),
                                                            'distance house branch': lambda x: int(x),
                                                            'cable width': lambda x: int(x),
                                                            'string length': lambda x: int(x),
                                                            'length house branch A': lambda x: int(x),
                                                            'length house branch B': lambda x: int(x),
                                                            'cable width A': lambda x: int(x),
                                                            'cable width B': lambda x: int(x)})

        model_grids_lv_apartment_string = cfg_ding0.get('model_grids',
                                                        'model_grids_lv_apartment_string')
        converters_ids = {}
        for id in range(1,47):  # create int() converter for columns 1..46
            converters_ids[str(id)] = lambda x: int(x)
        static_data['LV_model_grids_strings_per_grid'] = pd.read_csv(os.path.join(package_path, 'data',
                                                         model_grids_lv_apartment_string),
                                                         comment='#',
                                                         delimiter=';',
                                                         decimal=',',
                                                         index_col='apartment_count',
                                                         converters=dict({'apartment_count': lambda x: int(x)},
                                                                         **converters_ids))

        return static_data

Response: Imports static data into NetworkDing0 such as equipment.


Instruction:
Can you write a function in Python 3 where it
imports the ORM classes for oedb access depending on input in config

Response:
def import_orm(self):
        #TODO: check docstring
        """ Import ORM classes for oedb access depending on input in config in
        self.config which is loaded from 'config_db_tables.cfg'

        Returns
        -------
        int
            Descr #TODO check type
        """

        orm = {}

        data_source = self.config['input_data_source']['input_data']
        mv_grid_districts_name = self.config[data_source]['mv_grid_districts']
        mv_stations_name = self.config[data_source]['mv_stations']
        lv_load_areas_name = self.config[data_source]['lv_load_areas']
        lv_grid_district_name = self.config[data_source]['lv_grid_district']
        lv_stations_name = self.config[data_source]['lv_stations']
        conv_generators_name = self.config[data_source]['conv_generators']
        re_generators_name = self.config[data_source]['re_generators']

        from egoio.db_tables import model_draft as orm_model_draft, \
            supply as orm_supply, \
            demand as orm_demand, \
            grid as orm_grid

        if data_source == 'model_draft':
            orm['orm_mv_grid_districts'] = orm_model_draft.__getattribute__(mv_grid_districts_name)
            orm['orm_mv_stations'] = orm_model_draft.__getattribute__(mv_stations_name)
            orm['orm_lv_load_areas'] = orm_model_draft.__getattribute__(lv_load_areas_name)
            orm['orm_lv_grid_district'] = orm_model_draft.__getattribute__(lv_grid_district_name)
            orm['orm_lv_stations'] = orm_model_draft.__getattribute__(lv_stations_name)
            orm['orm_conv_generators'] = orm_model_draft.__getattribute__(conv_generators_name)
            orm['orm_re_generators'] = orm_model_draft.__getattribute__(re_generators_name)
            orm['version_condition_mvgd'] = 1 == 1
            orm['version_condition_mv_stations'] = 1 == 1
            orm['version_condition_la'] = 1 == 1
            orm['version_condition_lvgd'] = 1 == 1
            orm['version_condition_mvlvst'] = 1 == 1
            orm['version_condition_re'] = 1 == 1
            orm['version_condition_conv'] = 1 == 1
        elif data_source == 'versioned':
            orm['orm_mv_grid_districts'] = orm_grid.__getattribute__(mv_grid_districts_name)
            orm['orm_mv_stations'] = orm_grid.__getattribute__(mv_stations_name)
            orm['orm_lv_load_areas'] = orm_demand.__getattribute__(lv_load_areas_name)
            orm['orm_lv_grid_district'] = orm_grid.__getattribute__(lv_grid_district_name)
            orm['orm_lv_stations'] = orm_grid.__getattribute__(lv_stations_name)
            orm['orm_conv_generators'] = orm_supply.__getattribute__(conv_generators_name)
            orm['orm_re_generators'] = orm_supply.__getattribute__(re_generators_name)
            orm['data_version'] = self.config[data_source]['version']
            orm['version_condition_mvgd'] =\
                orm['orm_mv_grid_districts'].version == orm['data_version']
            orm['version_condition_mv_stations'] = \
                orm['orm_mv_stations'].version == orm['data_version']
            orm['version_condition_la'] =\
                orm['orm_lv_load_areas'].version == orm['data_version']
            orm['version_condition_lvgd'] =\
                orm['orm_lv_grid_district'].version == orm['data_version']
            orm['version_condition_mvlvst'] =\
                orm['orm_lv_stations'].version == orm['data_version']
            orm['version_condition_re'] =\
                orm['orm_re_generators'].columns.version == orm['data_version']
            orm['version_condition_conv'] =\
                orm['orm_conv_generators'].columns.version == orm['data_version']
        else:
            logger.error("Invalid data source {} provided. Please re-check the file "
                         "`config_db_tables.cfg`".format(data_source))
            raise NameError("{} is no valid data source!".format(data_source))

        return orm


Instruction:
Create a Python 3 function for
testing MV grid districts for validity concerning imported data.

Response:
def validate_grid_districts(self):
        #TODO: check docstring
        """ Tests MV grid districts for validity concerning imported data such as:

            i) Uno
            ii) Dos

        Invalid MV grid districts are subsequently deleted from Network.
        """

        msg_invalidity = []
        invalid_mv_grid_districts = []

        for grid_district in self.mv_grid_districts():

            # there's only one node (MV station) => grid is empty
            if len(grid_district.mv_grid._graph.nodes()) == 1:
                invalid_mv_grid_districts.append(grid_district)
                msg_invalidity.append('MV Grid District {} seems to be empty ' \
                                      'and ' \
                                      'was removed'.format(grid_district))
            # there're only aggregated load areas
            elif all([lvla.is_aggregated for lvla in
                      grid_district.lv_load_areas()]):
                invalid_mv_grid_districts.append(grid_district)
                msg_invalidity.append("MV Grid District {} contains only " \
                                 "aggregated Load Areas and was removed" \
                                 "".format(grid_district))

        for grid_district in invalid_mv_grid_districts:
            self._mv_grid_districts.remove(grid_district)

        logger.warning("\n".join(msg_invalidity))
        logger.info('=====> MV Grids validated')
        return msg_invalidity


Instruction:
How would you code a function in Python 3 to
export MV grids to database for visualization purposes.

Response:
def export_mv_grid(self, session, mv_grid_districts):
        """ Exports MV grids to database for visualization purposes

        Parameters
        ----------
        session : sqlalchemy.orm.session.Session
            Database session
        mv_grid_districts : List of MV grid_districts (instances of MVGridDistrictDing0 class)
            whose MV grids are exported.

        Returns
        -------
        int
            Description #TODO
        """

        # check arguments
        if not all(isinstance(_, int) for _ in mv_grid_districts):
            raise TypeError('`mv_grid_districts` has to be a list of integers.')

        srid = str(int(cfg_ding0.get('geo', 'srid')))

        # delete all existing datasets
        # db_int.sqla_mv_grid_viz.__table__.create(conn) # create if not exist
        # change_owner_to(conn,
        #                 db_int.sqla_mv_grid_viz.__table_args__['schema'],
        #                 db_int.sqla_mv_grid_viz.__tablename__,
        #                 'oeuser')
        session.query(db_int.sqla_mv_grid_viz).delete()
        session.commit()

        # build data array from MV grids (nodes and branches)
        for grid_district in self.mv_grid_districts():

            grid_id = grid_district.mv_grid.id_db

            # init arrays for nodes
            mv_stations = []
            mv_cable_distributors = []
            mv_circuit_breakers = []
            lv_load_area_centres = []
            lv_stations = []
            mv_generators = []
            lines = []

            # get nodes from grid's graph and append to corresponding array
            for node in grid_district.mv_grid._graph.nodes():
                if isinstance(node, LVLoadAreaCentreDing0):
                    lv_load_area_centres.append((node.geo_data.x, node.geo_data.y))
                elif isinstance(node, MVCableDistributorDing0):
                    mv_cable_distributors.append((node.geo_data.x, node.geo_data.y))
                elif isinstance(node, MVStationDing0):
                    mv_stations.append((node.geo_data.x, node.geo_data.y))
                elif isinstance(node, CircuitBreakerDing0):
                    mv_circuit_breakers.append((node.geo_data.x, node.geo_data.y))
                elif isinstance(node, GeneratorDing0):
                    mv_generators.append((node.geo_data.x, node.geo_data.y))

            # create shapely obj from stations and convert to
            # geoalchemy2.types.WKBElement
            # set to None if no objects found (otherwise SQLAlchemy will throw an error).
            if lv_load_area_centres:
                lv_load_area_centres_wkb = from_shape(MultiPoint(lv_load_area_centres), srid=srid)
            else:
                lv_load_area_centres_wkb = None

            if mv_cable_distributors:
                mv_cable_distributors_wkb = from_shape(MultiPoint(mv_cable_distributors), srid=srid)
            else:
                mv_cable_distributors_wkb = None

            if mv_circuit_breakers:
                mv_circuit_breakers_wkb = from_shape(MultiPoint(mv_circuit_breakers), srid=srid)
            else:
                mv_circuit_breakers_wkb = None

            if mv_stations:
                mv_stations_wkb = from_shape(Point(mv_stations), srid=srid)
            else:
                mv_stations_wkb = None

            if mv_generators:
                mv_generators_wkb = from_shape(MultiPoint(mv_generators), srid=srid)
            else:
                mv_generators_wkb = None

            # get edges (lines) from grid's graph and append to corresponding array
            for branch in grid_district.mv_grid.graph_edges():
                line = branch['adj_nodes']
                lines.append(((line[0].geo_data.x,
                               line[0].geo_data.y),
                              (line[1].geo_data.x,
                               line[1].geo_data.y)))

            # create shapely obj from lines and convert to
            # geoalchemy2.types.WKBElement
            mv_lines_wkb = from_shape(MultiLineString(lines), srid=srid)

            # get nodes from lv grid districts and append to corresponding array
            for lv_load_area in grid_district.lv_load_areas():
                for lv_grid_district in lv_load_area.lv_grid_districts():
                    station = lv_grid_district.lv_grid.station()
                    if station not in grid_district.mv_grid.graph_isolated_nodes():
                        lv_stations.append((station.geo_data.x, station.geo_data.y))
            lv_stations_wkb = from_shape(MultiPoint(lv_stations), srid=srid)

            # add dataset to session
            dataset = db_int.sqla_mv_grid_viz(
                grid_id=grid_id,
                geom_mv_station=mv_stations_wkb,
                geom_mv_cable_dists=mv_cable_distributors_wkb,
                geom_mv_circuit_breakers=mv_circuit_breakers_wkb,
                geom_lv_load_area_centres=lv_load_area_centres_wkb,
                geom_lv_stations=lv_stations_wkb,
                geom_mv_generators=mv_generators_wkb,
                geom_mv_lines=mv_lines_wkb)
            session.add(dataset)

        # commit changes to db
        session.commit()

        # logger.info('=====> MV Grids exported')
        logger.info('MV Grids exported')


Instruction:
Can you tell what is the following Python 3 function doing
def export_mv_grid_new(self, session, mv_grid_districts):

        # check arguments
        if not all(isinstance(_, int) for _ in mv_grid_districts):
            raise TypeError('`mv_grid_districts` has to be a list of integers.')

        srid = str(int(cfg_ding0.get('geo', 'srid')))

        # delete all existing datasets
        # db_int.sqla_mv_grid_viz_branches.__table__.create(conn) # create if not exist
        # change_owner_to(conn,
        #                 db_int.sqla_mv_grid_viz_branches.__table_args__['schema'],
        #                 db_int.sqla_mv_grid_viz_branches.__tablename__,
        #                 'oeuser')
        # db_int.sqla_mv_grid_viz_nodes.__table__.create(conn) # create if not exist
        # change_owner_to(conn,
        #                 db_int.sqla_mv_grid_viz_nodes.__table_args__['schema'],
        #                 db_int.sqla_mv_grid_viz_nodes.__tablename__,
        #                 'oeuser')
        session.query(db_int.sqla_mv_grid_viz_branches).delete()
        session.query(db_int.sqla_mv_grid_viz_nodes).delete()
        session.commit()

        # build data array from MV grids (nodes and branches)
        for grid_district in self.mv_grid_districts():

            # get nodes from grid's graph and create datasets
            for node in grid_district.mv_grid._graph.nodes():
                if hasattr(node, 'voltage_res'):
                    node_name = '_'.join(['MV',
                                          str(grid_district.mv_grid.id_db),
                                          repr(node)])

                    node_dataset = db_int.sqla_mv_grid_viz_nodes(
                        node_id=node_name,
                        grid_id=grid_district.mv_grid.id_db,
                        v_nom=grid_district.mv_grid.v_level,
                        geom=from_shape(Point(node.geo_data), srid=srid),
                        v_res0=node.voltage_res[0],
                        v_res1=node.voltage_res[1]
                    )
                    session.add(node_dataset)
                # LA centres of agg. LA
                elif isinstance(node, LVLoadAreaCentreDing0):
                    if node.lv_load_area.is_aggregated:
                        node_name = '_'.join(['MV',
                                              str(grid_district.mv_grid.id_db),
                                              repr(node)])

                        node_dataset = db_int.sqla_mv_grid_viz_nodes(
                            node_id=node_name,
                            grid_id=grid_district.mv_grid.id_db,
                            v_nom=grid_district.mv_grid.v_level,
                            geom=from_shape(Point(node.geo_data), srid=srid),
                            v_res0=0,
                            v_res1=0
                        )
                        session.add(node_dataset)

            # get branches (lines) from grid's graph and create datasets
            for branch in grid_district.mv_grid.graph_edges():
                if hasattr(branch['branch'], 's_res'):
                    branch_name = '_'.join(['MV',
                                            str(grid_district.mv_grid.id_db),
                                            'lin',
                                            str(branch['branch'].id_db)])

                    branch_dataset = db_int.sqla_mv_grid_viz_branches(
                        branch_id=branch_name,
                        grid_id=grid_district.mv_grid.id_db,
                        type_name=branch['branch'].type['name'],
                        type_kind=branch['branch'].kind,
                        type_v_nom=branch['branch'].type['U_n'],
                        type_s_nom=3**0.5 * branch['branch'].type['I_max_th'] * branch['branch'].type['U_n'],
                        length=branch['branch'].length / 1e3,
                        geom=from_shape(LineString([branch['adj_nodes'][0].geo_data,
                                                    branch['adj_nodes'][1].geo_data]),
                                        srid=srid),
                        s_res0=branch['branch'].s_res[0],
                        s_res1=branch['branch'].s_res[1]
                    )
                    session.add(branch_dataset)
                else:
                    branch_name = '_'.join(['MV',
                                            str(grid_district.mv_grid.id_db),
                                            'lin',
                                            str(branch['branch'].id_db)])

                    branch_dataset = db_int.sqla_mv_grid_viz_branches(
                        branch_id=branch_name,
                        grid_id=grid_district.mv_grid.id_db,
                        type_name=branch['branch'].type['name'],
                        type_kind=branch['branch'].kind,
                        type_v_nom=branch['branch'].type['U_n'],
                        type_s_nom=3**0.5 * branch['branch'].type['I_max_th'] * branch['branch'].type['U_n'],
                        length=branch['branch'].length / 1e3,
                        geom=from_shape(LineString([branch['adj_nodes'][0].geo_data,
                                                    branch['adj_nodes'][1].geo_data]),
                                        srid=srid),
                        s_res0=0,
                        s_res1=0
                    )
                    session.add(branch_dataset)

        # commit changes to db
        session.commit()

        logger.info('=====> MV Grids exported (NEW)')

Response: Exports MV grids to database for visualization purposes.


Instruction:
Write a Python 3 script to
export grid data to dataframe for statistical analysis.

Response:
def to_dataframe(self):
        """Export grid data to dataframes for statistical analysis.

        The export to dataframe is similar to db tables exported by `export_mv_grid_new`.

        Returns
        -------
        :pandas:`pandas.DataFrame<dataframe>`
            Pandas Data Frame

        See Also
        --------
        ding0.core.NetworkDing0.export_mv_grid_new :

        """

        node_cols = ['node_id', 'grid_id', 'v_nom', 'geom', 'v_res0', 'v_res1',
                     'peak_load', 'generation_capacity', 'type']
        edges_cols = ['branch_id', 'grid_id', 'type_name', 'type_kind',
                      'type_v_nom', 'type_s_nom', 'length', 'geom', 's_res0',
                      's_res1']

        nodes_df = pd.DataFrame(columns=node_cols)
        edges_df = pd.DataFrame(columns=edges_cols)

        srid = str(int(self.config['geo']['srid']))

        for grid_district in self.mv_grid_districts():

            # get nodes from grid's graph and create datasets
            for node in grid_district.mv_grid.graph_nodes_sorted():
                node_name = '_'.join(['MV',
                                      str(grid_district.mv_grid.id_db),
                                      repr(node)])
                geom = from_shape(Point(node.geo_data), srid=srid)
                if isinstance(node, LVStationDing0):
                    peak_load = node.peak_load
                    generation_capacity = node.peak_generation
                    if hasattr(node, 'voltage_res'):
                        type = 'LV Station'
                    else:
                        type = 'LV station (aggregated)'
                elif isinstance(node, GeneratorDing0):
                    peak_load = 0
                    generation_capacity = node.capacity
                    type = node.type
                elif isinstance(node, MVCableDistributorDing0):
                    peak_load = 0
                    generation_capacity = 0
                    type = 'Cable distributor'
                elif isinstance(node, LVLoadAreaCentreDing0):
                    peak_load = 0
                    generation_capacity = 0
                    type = 'Load area center of aggregated load area'
                elif isinstance(node, CircuitBreakerDing0):
                    peak_load = 0
                    generation_capacity = 0
                    type = 'Switch Disconnector'
                    #round coordinates of circuit breaker
                    geosjson = mapping(node.geo_data)
                    decimal_places = 4 #with 4, its around 10m error N-S or E-W
                    geosjson['coordinates'] = np.round(np.array(geosjson['coordinates']), decimal_places)
                    geom = from_shape(Point(shape(geosjson)), srid=srid)
                else:
                    peak_load = 0
                    generation_capacity = 0
                    type = 'Unknown'

                # add res voltages from nodes which were part of PF only
                if hasattr(node, 'voltage_res'):
                    v_res0 = node.voltage_res[0]
                    v_res1 = node.voltage_res[1]
                else:
                    v_res0 = v_res1 = 0

                nodes_df = nodes_df.append(pd.Series(
                    {'node_id': node_name,
                     'grid_id': grid_district.mv_grid.id_db,
                     'v_nom': grid_district.mv_grid.v_level,
                     'geom': geom,
                     'peak_load': peak_load,
                     'generation_capacity': generation_capacity,
                     'v_res0': v_res0,
                     'v_res1': v_res1,
                     'type': type,
                     'rings': len(grid_district.mv_grid._rings)
                    }), ignore_index=True)

            # get branches (lines) from grid's graph and create datasets
            for branch in grid_district.mv_grid.graph_edges():
                if hasattr(branch['branch'], 's_res'):
                    branch_name = '_'.join(['MV',
                                            str(
                                                grid_district.mv_grid.id_db),
                                            'lin',
                                            str(branch[
                                                    'branch'].id_db)])

                    edges_df = edges_df.append(pd.Series(
                        {'branch_id': branch_name,
                        'grid_id': grid_district.mv_grid.id_db,
                        'type_name': branch['branch'].type['name'],
                        'type_kind': branch['branch'].kind,
                        'type_v_nom': branch['branch'].type['U_n'],
                        'type_s_nom': 3 ** 0.5 * branch['branch'].type[
                            'I_max_th'] * branch['branch'].type['U_n'],
                        'length': branch['branch'].length / 1e3,
                        'geom': from_shape(
                            LineString([branch['adj_nodes'][0].geo_data,
                                        branch['adj_nodes'][
                                            1].geo_data]),
                            srid=srid),
                        's_res0': branch['branch'].s_res[0],
                        's_res1': branch['branch'].s_res[1]}), ignore_index=True)

        return nodes_df, edges_df


Instruction:
Can you create a Python 3 function that
performs routing on all MV grids in MV grids.

Response:
def mv_routing(self, debug=False, animation=False):
        """ Performs routing on all MV grids.

        Parameters
        ----------
        debug: bool, default to False
            If True, information is printed while routing
        animation: bool, default to False
            If True, images of route modification steps are exported during routing process. A new animation object is created.

        See Also
        --------
        ding0.core.network.grids.MVGridDing0.routing : for details on MVGridDing0 objects routing
        ding0.tools.animation.AnimationDing0 : for details on animation function.
        """

        if animation:
            anim = AnimationDing0()
        else:
            anim = None

        for grid_district in self.mv_grid_districts():
            grid_district.mv_grid.routing(debug=debug, anim=anim)

        logger.info('=====> MV Routing (Routing, Connection of Satellites & '
                    'Stations) performed')


Instruction:
Write a Python 3 script to
build LV grids for every non - aggregated LA in every MV grid district using model grids.

Response:
def build_lv_grids(self):
        """ Builds LV grids for every non-aggregated LA in every MV grid
        district using model grids.
        """

        for mv_grid_district in self.mv_grid_districts():
            for load_area in mv_grid_district.lv_load_areas():
                if not load_area.is_aggregated:
                    for lv_grid_district in load_area.lv_grid_districts():

                        lv_grid_district.lv_grid.build_grid()
                else:
                    logger.info(
                        '{} is of type aggregated. No grid is created.'.format(repr(load_area)))

        logger.info('=====> LV model grids created')


Instruction:
How would you explain what the following Python 3 function does
def connect_generators(self, debug=False):

        for mv_grid_district in self.mv_grid_districts():
            mv_grid_district.mv_grid.connect_generators(debug=debug)

            # get predefined random seed and initialize random generator
            seed = int(cfg_ding0.get('random', 'seed'))
            random.seed(a=seed)

            for load_area in mv_grid_district.lv_load_areas():
                if not load_area.is_aggregated:
                    for lv_grid_district in load_area.lv_grid_districts():

                        lv_grid_district.lv_grid.connect_generators(debug=debug)
                        if debug:
                            lv_grid_district.lv_grid.graph_draw(mode='LV')
                else:
                    logger.info(
                        '{} is of type aggregated. LV generators are not connected to LV grids.'.format(repr(load_area)))

        logger.info('=====> Generators connected')

Response: Connect generators to grids for every MV and LV grid district.


Instruction:
Implement a function in Python 3 to
perform Parametrization of all MV grids in the MV grid districts.

Response:
def mv_parametrize_grid(self, debug=False):
        """ Performs Parametrization of grid equipment of all MV grids.

        Parameters
        ----------
        debug: bool, defaults to False
            If True, information is printed during process.

        See Also
        --------
        ding0.core.network.grids.MVGridDing0.parametrize_grid
        """

        for grid_district in self.mv_grid_districts():
            grid_district.mv_grid.parametrize_grid(debug=debug)

        logger.info('=====> MV Grids parametrized')


Instruction:
Implement a Python 3 function for
setting branch ids for all MV and LV grids in this MV grid.

Response:
def set_branch_ids(self):
        """ Performs generation and setting of ids of branches for all MV and underlying LV grids.

        See Also
        --------
        ding0.core.network.grids.MVGridDing0.set_branch_ids
        """

        for grid_district in self.mv_grid_districts():
            grid_district.mv_grid.set_branch_ids()

        logger.info('=====> Branch IDs set')


Instruction:
Can you tell what is the following Python 3 function doing
def set_circuit_breakers(self, debug=False):

        for grid_district in self.mv_grid_districts():
            grid_district.mv_grid.set_circuit_breakers(debug=debug)

        logger.info('=====> MV Circuit Breakers relocated')

Response: Calculates the optimal position of the existing circuit breakers and relocates them within the MV grids.


Instruction:
Implement a Python 3 function for
opening or closes all circuit breakers of all MV grids.

Response:
def control_circuit_breakers(self, mode=None):
        """ Opens or closes all circuit breakers of all MV grids.

        Args
        ----
        mode: str
            Set mode='open' to open, mode='close' to close
        """

        for grid_district in self.mv_grid_districts():
            if mode == 'open':
                grid_district.mv_grid.open_circuit_breakers()
            elif mode == 'close':
                grid_district.mv_grid.close_circuit_breakers()
            else:
                raise ValueError('\'mode\' is invalid.')

        if mode == 'open':
            logger.info('=====> MV Circuit Breakers opened')
        elif mode == 'close':
            logger.info('=====> MV Circuit Breakers closed')


Instruction:
Given the following Python 3 function, write the documentation
def run_powerflow(self, session, method='onthefly', export_pypsa=False, debug=False):

        if method == 'db':
            # Empty tables
            pypsa_io.delete_powerflow_tables(session)

            for grid_district in self.mv_grid_districts():
                if export_pypsa:
                    export_pypsa_dir = repr(grid_district.mv_grid)
                else:
                    export_pypsa_dir = None
                grid_district.mv_grid.run_powerflow(session, method='db',
                                                    export_pypsa_dir=export_pypsa_dir,
                                                    debug=debug)

        elif method == 'onthefly':
            for grid_district in self.mv_grid_districts():
                if export_pypsa:
                    export_pypsa_dir = repr(grid_district.mv_grid)
                else:
                    export_pypsa_dir = None
                grid_district.mv_grid.run_powerflow(session,
                                                    method='onthefly',
                                                    export_pypsa_dir=export_pypsa_dir,
                                                    debug=debug)

Response: Runs power flow calculation for all MV grids in the database.


Instruction:
Can you write a function in Python 3 where it
performs grid reinforcement measures for all MV and LV grids in this instance.

Response:
def reinforce_grid(self):
        """ Performs grid reinforcement measures for all MV and LV grids
        Args:

        Returns:

        """
        # TODO: Finish method and enable LV case

        for grid_district in self.mv_grid_districts():

            # reinforce MV grid
            grid_district.mv_grid.reinforce_grid()

            # reinforce LV grids
            for lv_load_area in grid_district.lv_load_areas():
                if not lv_load_area.is_aggregated:
                    for lv_grid_district in lv_load_area.lv_grid_districts():
                        lv_grid_district.lv_grid.reinforce_grid()