diff --git a/.gitignore b/.gitignore index 87c519b4f..278a3bb4d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,6 @@ doc/_html # exclude egg-info -eDisGo.egg-info/ \ No newline at end of file +eDisGo.egg-info/ +/edisgo/examples/Exemplary_PyPSA_bus_results.csv +/edisgo/examples/Exemplary_PyPSA_line_results.csv diff --git a/edisgo/data/import_data.py b/edisgo/data/import_data.py index 814806277..9cb4990e5 100644 --- a/edisgo/data/import_data.py +++ b/edisgo/data/import_data.py @@ -271,12 +271,15 @@ def _build_mv_grid(dingo_grid, network): grid=grid, transformers=[Transformer( grid=grid, - id=t.grid.id_db, + id='_'.join(['LV_station', + str(_.id_db), + 'transformer', + str(count)]), geom=_.geo_data, voltage_op=t.v_level, type=pd.Series(dict( s=t.s_max_a, x=t.x, r=t.r)) - ) for t in _.transformers()]) + ) for (count, t) in enumerate(_.transformers(), 1)]) for _ in dingo_grid._graph.nodes() if isinstance(_, LVStationDing0) and _ not in aggr_stations} grid.graph.add_nodes_from(stations.values(), type='lv_station') @@ -287,12 +290,15 @@ def _build_mv_grid(dingo_grid, network): geom=dingo_grid.station().geo_data, transformers=[Transformer( grid=grid, - id=_.grid.id_db, + id='_'.join(['MV_station', + str(dingo_grid.station().id_db), + 'transformer', + str(count)]), geom=dingo_grid.station().geo_data, voltage_op=_.v_level, type=pd.Series(dict( s=_.s_max_a, x=_.x, r=_.r))) - for _ in dingo_grid.station().transformers()]) + for (count, _) in enumerate(dingo_grid.station().transformers())]) grid.graph.add_node(mv_station, type='mv_station') # Merge node above defined above to a single dict diff --git a/edisgo/examples/example.py b/edisgo/examples/example.py index c453767eb..d77794bda 100644 --- a/edisgo/examples/example.py +++ b/edisgo/examples/example.py @@ -54,4 +54,3 @@ # ToDo: wie halten wir fest, welche Betriebsmittel erneuert wurden, um hinterher Kosten berechnen zu können? # ToDo: Parameter bei Komponenten einführen mit dem man feststellen kann, ob die Komponente bereits in einer ersten Maßnahme verstärkt oder ausgebaut wurde # ToDo: config mit Standardbetriebsmitteln? - diff --git a/edisgo/grid/components.py b/edisgo/grid/components.py index 4a73f1424..e96fd3c2a 100644 --- a/edisgo/grid/components.py +++ b/edisgo/grid/components.py @@ -26,6 +26,7 @@ def geom(self): @property def grid(self): """:class:`~.grid.grids.MVGrid` or :class:`~.grid.grids.LVGrid` : The MV or LV grid this component belongs to""" + return self._grid def __repr__(self): return '_'.join([self.__class__.__name__, str(self._id)]) diff --git a/edisgo/grid_expansion/check_tech_constraints.py b/edisgo/grid_expansion/check_tech_constraints.py index d7d7fc033..0169cb716 100644 --- a/edisgo/grid_expansion/check_tech_constraints.py +++ b/edisgo/grid_expansion/check_tech_constraints.py @@ -67,7 +67,7 @@ def check_line_load(network, results_lines, **kwargs): # MV for line in list(network.mv_grid.graph.graph_edges()): s_max_th = (3 ** 0.5 * line['line']._type['U_n'] * - line['line']._type['I_max_th']) * \ + line['line']._type['I_max_th']) * \ load_factor_mv_line * line['line']._quantity try: # check if maximum s_0 from power flow analysis exceeds allowed @@ -77,7 +77,7 @@ def check_line_load(network, results_lines, **kwargs): mw2kw / s_max_th) except: logger.debug('No results for line {} '.format(str(line)) + - 'to check overloading.') + 'to check overloading.') # LV for lv_grid in network.mv_grid.lv_grids: for line in list(lv_grid.graph.graph_edges()): @@ -93,7 +93,7 @@ def check_line_load(network, results_lines, **kwargs): mw2kw / s_max_th) except: logger.debug('No results for line {} '.format(str(line)) + - 'to check overloading.') + 'to check overloading.') if crit_lines: logger.info('==> {} lines have load issues.'.format( @@ -109,7 +109,7 @@ def check_station_load(network, results_lines, **kwargs): ---------- network: edisgo Network object results_lines: pandas.DataFrame - power flow analysis results (pfa_nodes) from edisgo Results object + power flow analysis results (pfa_edges) from edisgo Results object **kwargs: load_factor_mv_lv_transformer: float (optional) allowed load of MV/LV transformer in uninterrupted operation @@ -117,7 +117,7 @@ def check_station_load(network, results_lines, **kwargs): Returns ------- Dict of critical stations (edisgo Station objects) - Format: {station_1: overloading_1, ..., station_n: overloading_n}, + Format: {station_1: overloading_1, ..., station_n: overloading_n} Notes ----- @@ -171,53 +171,80 @@ def check_station_load(network, results_lines, **kwargs): return crit_stations -def check_voltage(grid, mode): - """ Checks for voltage stability issues at all nodes for MV or LV grid +def check_voltage(network, results_nodes, **kwargs): + """ Checks for voltage stability issues at all nodes for MV and LV grid Parameters ---------- - grid: GridDing0 object - mode: String - kind of grid ('MV' or 'LV') + network: edisgo Network object + results_nodes: pandas.DataFrame + power flow analysis results (pfa_nodes) from edisgo Results object + **kwargs: + mv_max_v_deviation: float (optional) + allowed voltage deviation in MV grid + lv_max_v_deviation: float (optional) + allowed voltage deviation in LV grid Returns ------- List of critical nodes, sorted descending by voltage difference + Format: {grid_1: [node_1A, node_1B, ...], ..., grid_n: [node_nA, ...]} Notes ----- The voltage is checked against a max. allowed voltage deviation. """ - # crit_nodes = {} - # - # if mode == 'MV': - # # load max. voltage difference for load and feedin case - # mv_max_v_level_lc_diff_normal = float(cfg_ding0.get('mv_routing_tech_constraints', - # 'mv_max_v_level_lc_diff_normal')) - # mv_max_v_level_fc_diff_normal = float(cfg_ding0.get('mv_routing_tech_constraints', - # 'mv_max_v_level_fc_diff_normal')) - # - # # check nodes' voltages - # voltage_station = grid._station.voltage_res - # for node in grid.graph_nodes_sorted(): - # try: - # # compare node's voltage with max. allowed voltage difference for load and feedin case - # if (abs(voltage_station[0] - node.voltage_res[0]) > mv_max_v_level_lc_diff_normal) or\ - # (abs(voltage_station[1] - node.voltage_res[1]) > mv_max_v_level_fc_diff_normal): - # - # crit_nodes[node] = {'node': node, - # 'v_diff': max([abs(v2-v1) for v1, v2 in zip(node.voltage_res, voltage_station)])} - # except: - # pass - # - # elif mode == 'LV': - # raise NotImplementedError - # - # if crit_nodes: - # logger.info('==> {} nodes have voltage issues.'.format(len(crit_nodes))) - # - # return [_['node'] for _ in sorted(crit_nodes.values(), key=lambda _: _['v_diff'], reverse=True)] + # ToDo: delta_U wird auch benötigt, deshalb crit_nodes als dict mit series + # ToDo: crit_nodes innerhalb einer Series sortieren + crit_nodes = {} + + # load max. voltage deviation for load and feedin case + mv_max_v_deviation = kwargs.get('mv_max_v_deviation', 0.1) + lv_max_v_deviation = kwargs.get('lv_max_v_deviation', 0.1) + + # check nodes' voltages + # MV + voltage_station = network.mv_grid.station.transformers[0]._voltage_op + for node in network.mv_grid.graph.nodes(): + try: + # check if maximum deviation in v_mag_pu exceeds allowed deviation + if (max(results_nodes.loc[node, 'v_mag_pu']) > + 1 + mv_max_v_deviation or + min(results_nodes.loc[ + node, 'v_mag_pu']) < 1 - mv_max_v_deviation): + try: + crit_nodes[network.mv_grid].append(node) + except: + crit_nodes[network.mv_grid] = [node] + except: + logger.debug('No results for node {} '.format(str(node)) + + 'to check overvoltage.') + + # LV + for lv_grid in network.mv_grid.lv_grids: + for node in lv_grid.graph.nodes(): + try: + # check if maximum deviation in v_mag_pu exceeds allowed + # deviation + if (max(results_nodes.loc[node, 'v_mag_pu']) > + 1 + lv_max_v_deviation or + min(results_nodes.loc[ + node, 'v_mag_pu']) < 1 - lv_max_v_deviation): + try: + crit_nodes[lv_grid].append(node) + except: + crit_nodes[lv_grid] = [node] + except: + logger.debug('No results for node {} '.format(str(node)) + + 'in LV grid {} '.format(str(lv_grid)) + + 'to check overvoltage.') + + if crit_nodes: + logger.info( + '==> {} nodes have voltage issues.'.format(len(crit_nodes))) + + return crit_nodes def get_critical_voltage_at_nodes(grid): diff --git a/edisgo/grid_expansion/reinforce_grid.py b/edisgo/grid_expansion/reinforce_grid.py index 6e76b8c7d..cf45af4b5 100644 --- a/edisgo/grid_expansion/reinforce_grid.py +++ b/edisgo/grid_expansion/reinforce_grid.py @@ -1,5 +1,5 @@ -from .check_tech_constraints import check_line_load, check_station_load - #check_voltage, get_critical_line_loading, get_critical_voltage_at_nodes +from .check_tech_constraints import check_line_load, check_station_load, \ + check_voltage #, get_critical_line_loading, get_critical_voltage_at_nodes from .reinforce_measures import reinforce_branches_current, \ reinforce_branches_voltage, extend_distribution_substation import logging @@ -80,6 +80,7 @@ def reinforce_grid(network, results): crit_lines = {overloaded_line: 2.3} # do reinforcement + # ToDo: erst MV dann LV reinforce_branches_current(crit_lines) # if lines have been reinforced: run PF again and check if all @@ -92,7 +93,7 @@ def reinforce_grid(network, results): # STEP 3: reinforce branches due to voltage problems - # crit_nodes = check_voltage(grid, mode) + #crit_nodes = check_voltage(network, results.pfa_nodes) # crit_nodes_count_prev_step = len(crit_nodes) # ToDo: get nodes with overvoltage (als dict mit grid und liste von Knoten {GridXY: [NodeA, NodeB]}) diff --git a/edisgo/grid_expansion/reinforce_measures.py b/edisgo/grid_expansion/reinforce_measures.py index 8c52ed531..4fc3f8159 100644 --- a/edisgo/grid_expansion/reinforce_measures.py +++ b/edisgo/grid_expansion/reinforce_measures.py @@ -124,6 +124,10 @@ def reinforce_branches_voltage(grid, crit_nodes): References ---------- .. [1] "Verteilnetzstudie für das Land Baden-Württemberg" + .. [2] "Technische Richtlinie Erzeugungsanlagen am Mittelspannungsnetz - + Richtlinie für Anschluss und Parallelbetrieb von + Erzeugungsanlagen am Mittelspannungsnetz, Juni 2008" + """ # ToDo: gilt Methodik auch für die MS? @@ -177,15 +181,11 @@ def reinforce_branches_voltage(grid, crit_nodes): # if critical line is not yet a standard line check if one or # several standard lines are needed else: - # check if new standard line might solve the voltage - # problem - # ToDo: welche Kenngröße verwenden? - if crit_line._type['I_max_th'] < standard_line['I_max_th']: - crit_line._type = standard_line.copy() - else: - # ToDo: wie viele Standardbetriebsmittel? - crit_line._type = standard_line.copy() - crit_line._quantity = 2 + # number of parallel standard lines could be calculated + # following [2] p.103, for now number of parallel standard + # lines is iterated + crit_line._type = standard_line.copy() + crit_line._quantity = 1 # if node_2_3 is not a representative, disconnect line else: