diff --git a/README.md b/README.md index fe8365e8..4db4f45c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ pip3 install ding0 ``` Further details regarding the installation including dependencies are provided -in the [documentation](https://ding0.readthedocs.io) +in the [documentation](https://dingo.readthedocs.io) A [set of examples](https://ding0.readthedocs.io/en/dev/usage_details.html#examples) is provided to show how to use Ding0. diff --git a/ding0/__init__.py b/ding0/__init__.py index 3e18f730..4c95d540 100644 --- a/ding0/__init__.py +++ b/ding0/__init__.py @@ -18,13 +18,24 @@ # TODO: (Maybe) move to more general place (ego.io repo) +# TODO: check docstring def adapt_numpy_int64(numpy_int64): - """ Adapting numpy.int64 type to SQL-conform int type using psycopg extension, see [1]_ for more info. + """ Adapting numpy.int64 type to SQL-conform int type using psycopg extension, see [#]_ for more info. + Parameters + ---------- + numpy_int64 : int + numpty 64bits integer. + + Returns + ------- + type + #TODO: Description of return. Change type in the previous line accordingly + References ---------- - .. [1] http://initd.org/psycopg/docs/advanced.html#adapting-new-python-types-to-sql-syntax + .. [#] http://initd.org/psycopg/docs/advanced.html#adapting-new-python-types-to-sql-syntax """ return AsIs(numpy_int64) diff --git a/ding0/config/config_db_interfaces.py b/ding0/config/config_db_interfaces.py index 16a0b905..a2415561 100644 --- a/ding0/config/config_db_interfaces.py +++ b/ding0/config/config_db_interfaces.py @@ -22,57 +22,87 @@ Base = declarative_base() +# TODO: check docstrings + + # ================ DEFINITIONS FOR EXPORTED DATA =============== class sqla_mv_grid_viz(Base): """ SQLAlchemy table definition for the export of MV grids for visualization purposes - Notes - ----- + #TODO: Check docstrings *before* definitions! is that ok? """ __tablename__ = 'ego_grid_mv_visualization_bunch' __table_args__ = {'schema': 'model_draft'} + #::obj:`type`: Description. grid_id = sa.Column('grid_id', sa.Integer(), primary_key=True) + #::obj:`type`: Description. geom_mv_station = sa.Column('geom_mv_station', Geometry(geometry_type='POINT', srid=4326)) + #::obj:`type`: Description. geom_mv_cable_dists = sa.Column('geom_mv_cable_dists', Geometry(geometry_type='MULTIPOINT', srid=4326)) + #::obj:`type`: Description. geom_mv_circuit_breakers = sa.Column('geom_mv_circuit_breakers', Geometry(geometry_type='MULTIPOINT', srid=4326)) + #::obj:`type`: Description. geom_lv_load_area_centres = sa.Column('geom_lv_load_area_centres', Geometry(geometry_type='MULTIPOINT', srid=4326)) + #::obj:`type`: Description. geom_lv_stations = sa.Column('geom_lv_stations', Geometry(geometry_type='MULTIPOINT', srid=4326)) + #::obj:`type`: Description. geom_mv_generators = sa.Column('geom_mv_generators', Geometry(geometry_type='MULTIPOINT', srid=4326)) + #::obj:`type`: Description. geom_mv_lines = sa.Column('geom_mv_lines', Geometry(geometry_type='MULTILINESTRING', srid=4326)) class sqla_mv_grid_viz_branches(Base): """ SQLAlchemy table definition for the export of MV grids' branches for visualization purposes + + #TODO: Check docstrings *after* definitions! is that ok? """ __tablename__ = 'ego_grid_mv_visualization_branches' __table_args__ = {'schema': 'model_draft'} branch_id = sa.Column(sa.String(25), primary_key=True) + """:obj:`type`: Description.""" grid_id = sa.Column('grid_id', sa.Integer) + """:obj:`type`: Description.""" type_name = sa.Column('type_name', sa.String(25)) + """:obj:`type`: Description.""" type_kind = sa.Column('type_kind', sa.String(5)) + """:obj:`type`: Description.""" type_v_nom = sa.Column('type_v_nom', sa.Integer) + """:obj:`type`: Description.""" type_s_nom = sa.Column('type_s_nom', sa.Float(53)) + """:obj:`type`: Description.""" length = sa.Column('length', sa.Float(53)) + """:obj:`type`: Description.""" geom = sa.Column('geom', Geometry(geometry_type='LINESTRING', srid=4326)) + """:obj:`type`: Description.""" s_res0 = sa.Column('s_res0', sa.Float(53)) + """:obj:`type`: Description.""" s_res1 = sa.Column('s_res1', sa.Float(53)) + """:obj:`type`: Description.""" class sqla_mv_grid_viz_nodes(Base): """ SQLAlchemy table definition for the export of MV grids' branches for visualization purposes + + #TODO: Check docstrings *before* definitions! is that ok? """ __tablename__ = 'ego_grid_mv_visualization_nodes' __table_args__ = {'schema': 'model_draft'} + #::obj:`type`: Description. node_id = sa.Column(sa.String(100), primary_key=True) + #::obj:`type`: Description. grid_id = sa.Column('grid_id', sa.Integer) + #::obj:`type`: Description. v_nom = sa.Column('v_nom', sa.Integer) + #::obj:`type`: Description. geom = sa.Column('geom', Geometry(geometry_type='POINT', srid=4326)) + #::obj:`type`: Description. v_res0 = sa.Column('v_res0', sa.Float(53)) + #::obj:`type`: Description. v_res1 = sa.Column('v_res1', sa.Float(53)) diff --git a/ding0/config/config_db_tables.cfg b/ding0/config/config_db_tables.cfg index 4b280cf0..9c3f5184 100644 --- a/ding0/config/config_db_tables.cfg +++ b/ding0/config/config_db_tables.cfg @@ -27,4 +27,4 @@ conv_generators = t_ego_dp_conv_powerplant_sq_mview version = v0.3.0 [input_data_source] -input_data = versioned \ No newline at end of file +input_data = model_draft \ No newline at end of file diff --git a/ding0/core/__init__.py b/ding0/core/__init__.py index 46524b3c..a154f73a 100644 --- a/ding0/core/__init__.py +++ b/ding0/core/__init__.py @@ -11,11 +11,12 @@ __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" __url__ = "https://github.com/openego/ding0/blob/master/LICENSE" __author__ = "nesnoj, gplssm" +# TODO: check docstrings import ding0 from ding0.config import config_db_interfaces as db_int -from ding0.core.network import GeneratorDing0 +from ding0.core.network import GeneratorDing0, GeneratorFluctuatingDing0 from ding0.core.network.cable_distributors import MVCableDistributorDing0 from ding0.core.network.grids import * from ding0.core.network.stations import * @@ -27,12 +28,12 @@ import os import logging - import pandas as pd import random import time from math import isnan +from sqlalchemy.orm import sessionmaker from sqlalchemy import func from geoalchemy2.shape import from_shape from shapely.wkt import loads as wkt_loads @@ -48,8 +49,12 @@ class NetworkDing0: """ Defines the DING0 Network - not a real grid but a container for the MV-grids. Contains the NetworkX graph and associated attributes. - Parameters + + Attributes ---------- + name : :obj:`str` + Name of the grid + """ def __init__(self, **kwargs): @@ -105,7 +110,7 @@ def run_ding0(self, session, mv_grid_districts_no=None, debug=False): 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 : Boolean + debug : bool, defaults to False If True, information is printed during process Returns @@ -119,53 +124,65 @@ def run_ding0(self, session, mv_grid_districts_no=None, debug=False): since there are hard dependencies between them. Short description of all steps performed: - STEP 1: Import MV Grid Districts and subjacent objects + * 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 + * STEP 2: Import generators + Conventional and renewable generators of voltage levels 4..7 are imported and added to corresponding grid. - STEP 3: Parametrize 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 @@ -227,19 +244,40 @@ def get_mvgd_lvla_lvgd_obj_from_id(self): LVGridDistrictDing0 id to LVGridDistrictDing0 object and LVStationDing0 id to LVStationDing0 object - Returns: - mv_grid_districts_dict: dict with Format {mv_grid_district_id_1: mv_grid_district_obj_1, - ..., - mv_grid_district_id_n: mv_grid_district_obj_n} - lv_load_areas_dict: dict with Format {lv_load_area_id_1: lv_load_area_obj_1, - ..., - lv_load_area_id_n: lv_load_area_obj_n} - lv_grid_districts_dict: dict with Format {lv_grid_district_id_1: lv_grid_district_obj_1, - ..., - lv_grid_district_id_n: lv_grid_district_obj_n} - lv_stations_dict: dict with Format {lv_station_id_1: lv_station_obj_1, - ..., - lv_station_id_n: lv_station_obj_n} + Returns + ------- + :obj:`dict` + mv_grid_districts_dict:: + + { + mv_grid_district_id_1: mv_grid_district_obj_1, + ..., + mv_grid_district_id_n: mv_grid_district_obj_n + } + :obj:`dict` + lv_load_areas_dict:: + + { + lv_load_area_id_1: lv_load_area_obj_1, + ..., + lv_load_area_id_n: lv_load_area_obj_n + } + :obj:`dict` + lv_grid_districts_dict:: + + { + lv_grid_district_id_1: lv_grid_district_obj_1, + ..., + lv_grid_district_id_n: lv_grid_district_obj_n + } + :obj:`dict` + lv_stations_dict:: + + { + lv_station_id_1: lv_station_obj_1, + ..., + lv_station_id_n: lv_station_obj_n + } """ mv_grid_districts_dict = {} @@ -259,15 +297,23 @@ def get_mvgd_lvla_lvgd_obj_from_id(self): 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 + """Initiates single MV grid_district including station and grid Parameters ---------- - poly_id: ID of grid_district according to database table. Also used as ID for - created grid - subst_id: ID of station according to database table - grid_district_geo_data: Polygon (shapely object) of grid district - station_geo_data: Point (shapely object) of station + 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` + Polygon of grid district + station_geo_data: :shapely:`Shapely Point object` + Point of station + + Returns + ------- + :shapely:`Shapely Polygon object` + Description of return #TODO: check """ @@ -290,17 +336,18 @@ def build_lv_grid_district(self, lv_load_area, lv_grid_districts, lv_stations): - """ - Instantiates and associates lv_grid_district incl grid and station. + """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: load_area object - lv_grid_districts: DataFrame - Table containing lv_grid_districts of according load_area - lv_stations : DataFrame + lv_load_area: :shapely:`Shapely Polygon object` + load_area object + lv_grid_districts: :pandas:`pandas.DataFrame` + Table containing lv_grid_districts of according load_area + lv_stations : :pandas:`pandas.DataFrame` Table containing lv_stations of according load_area """ @@ -408,7 +455,7 @@ def import_mv_grid_districts(self, session, mv_grid_districts_no=None): -------- build_mv_grid_district : used to instantiate MV grid_district objects import_lv_load_areas : used to import load_areas for every single MV grid_district - add_peak_demand : used to summarize peak loads of underlying load_areas + ding0.core.structure.regions.MVGridDistrictDing0.add_peak_demand : used to summarize peak loads of underlying load_areas """ # check arguments @@ -480,7 +527,7 @@ def import_mv_grid_districts(self, session, mv_grid_districts_no=None): 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 + """Imports load_areas (load areas) from database for a single MV grid_district Parameters ---------- @@ -490,7 +537,7 @@ def import_lv_load_areas(self, session, mv_grid_district, lv_grid_districts, which the import of load areas is performed lv_grid_districts: DataFrame LV grid districts within this mv_grid_district - lv_stations: DataFrame + lv_stations: :pandas:`pandas.DataFrame` LV stations within this mv_grid_district """ @@ -598,7 +645,7 @@ def import_lv_grid_districts(self, session, lv_stations): Returns ------- - lv_grid_districts: pandas Dataframe + lv_grid_districts: :pandas:`pandas.DataFrame` Table of lv_grid_districts """ @@ -679,7 +726,7 @@ def import_lv_stations(self, session): Returns ------- - lv_stations: pandas Dataframe + lv_stations: :pandas:`pandas.DataFrame` Table of lv_stations """ @@ -712,10 +759,7 @@ def import_generators(self, session, debug=False): Database session debug: If True, information is printed during process Notes: - Connection of generators is done later on in NetworkDing0's method - :func:`connect_generators()`. - - If subtype is not specified it's set to 'unknown'. + Connection of generators is done later on in NetworkDing0's method connect_generators() """ def import_res_generators(): @@ -731,6 +775,7 @@ def import_res_generators(): 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( @@ -775,12 +820,23 @@ def import_res_generators(): mv_grid = mv_grid_districts_dict[mv_grid_district_id].mv_grid # create generator object - 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'])) + 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]: @@ -837,7 +893,7 @@ def import_conv_generators(): # build query generators_sqla = session.query( - self.orm['orm_conv_generators'].columns.gid, + 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, @@ -853,7 +909,7 @@ def import_conv_generators(): # read data from db generators = pd.read_sql_query(generators_sqla.statement, session.bind, - index_col='gid') + index_col='id') for id_db, row in generators.iterrows(): @@ -905,7 +961,8 @@ def import_config(self): Returns ------- - config object + int + config object #TODO check type """ # load parameters from configs @@ -923,7 +980,8 @@ def import_pf_config(self): Returns ------- - PFConfigDing0 object + PFConfigDing0 + PFConfigDing0 object """ scenario = cfg_ding0.get("powerflow", "test_grid_stability_scenario") @@ -1035,8 +1093,14 @@ def import_static_data(self): return static_data 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' + self.config which is loaded from 'config_db_tables.cfg' + + Returns + ------- + int + Descr #TODO check type """ orm = {} @@ -1101,8 +1165,12 @@ def import_orm(self): return orm def validate_grid_districts(self): - """ Tests MV grid districts for validity concerning imported data such as count of Load Areas. - + #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. """ @@ -1142,6 +1210,10 @@ def export_mv_grid(self, session, mv_grid_districts): mv_grid_districts : List of MV grid_districts (instances of MVGridDistrictDing0 class) whose MV grids are exported. + Returns + ------- + int + Description #TODO """ # check arguments @@ -1262,6 +1334,10 @@ def export_mv_grid_new(self, session, mv_grid_districts): mv_grid_districts : List of MV grid_districts (instances of MVGridDistrictDing0 class) whose MV grids are exported. + Returns + ------- + int + Description of return. #TODO """ # check arguments @@ -1373,14 +1449,19 @@ def export_mv_grid_new(self, session, mv_grid_districts): logger.info('=====> MV Grids exported (NEW)') def to_dataframe(self): - """Export grid data to dataframes for statistical analysis + """Export grid data to dataframes for statistical analysis. - The export to dataframe is similar to db tables exported by - `export_mv_grid_new`. + The export to dataframe is similar to db tables exported by `export_mv_grid_new`. Returns ------- - df : pandas.DataFrame + :pandas:`pandas.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', @@ -1485,16 +1566,19 @@ def to_dataframe(self): return nodes_df, edges_df def mv_routing(self, debug=False, animation=False): - """ Performs routing on Load Area centres to build MV grid with ring topology, - see method `routing` in class `MVGridDing0` for details. + """ Performs routing on all MV grids. Parameters ---------- - debug: If True, information is printed while routing - animation: If True, images of route modification steps are exported - during routing process - a new animation - object is created, refer to class 'AnimationDing0()' for a more - detailed description. + 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: @@ -1528,8 +1612,10 @@ def build_lv_grids(self): def connect_generators(self, debug=False): """ Connects generators (graph nodes) to grid (graph) for every MV and LV Grid District - Args: - debug: If True, information is printed during process + Args + ---- + debug: bool, defaults to False + If True, information is printed during process. """ for mv_grid_district in self.mv_grid_districts(): @@ -1553,12 +1639,16 @@ def connect_generators(self, debug=False): logger.info('=====> Generators connected') def mv_parametrize_grid(self, debug=False): - """ Performs Parametrization of grid equipment of all MV grids, see - method `parametrize_grid()` in class `MVGridDing0` for details. - + """ Performs Parametrization of grid equipment of all MV grids. + Parameters ---------- - debug: If True, information is printed while parametrization + 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(): @@ -1567,8 +1657,11 @@ def mv_parametrize_grid(self, debug=False): logger.info('=====> MV Grids parametrized') def set_branch_ids(self): - """ Performs generation and setting of ids of branches for all MV and underlying LV grids, see - method `set_branch_ids()` in class `MVGridDing0` for details. + """ 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(): @@ -1577,10 +1670,18 @@ def set_branch_ids(self): logger.info('=====> Branch IDs set') def set_circuit_breakers(self, debug=False): - """ Calculates the optimal position of the existing circuit breakers and relocates them within the graph for - all MV grids, see method `set_circuit_breakers` in ding0.grid.mv_grid.tools for details. - Args: - debug: If True, information is printed during process + """ Calculates the optimal position of the existing circuit breakers + and relocates them within the graph for all MV grids. + + Args + ---- + debug: bool, defaults to False + If True, information is printed during process + + See Also + -------- + ding0.grid.mv_grid.tools.set_circuit_breakers + """ for grid_district in self.mv_grid_districts(): @@ -1591,9 +1692,10 @@ def set_circuit_breakers(self, debug=False): def control_circuit_breakers(self, mode=None): """ Opens or closes all circuit breakers of all MV grids. - Args: - mode: Set mode='open' to open, mode='close' to close - debug: If True, information is printed during process + Args + ---- + mode: str + Set mode='open' to open, mode='close' to close """ for grid_district in self.mv_grid_districts(): @@ -1618,10 +1720,13 @@ def run_powerflow(self, session, method='onthefly', export_pypsa=False, debug=Fa method: str Specify export method If method='db' grid data will be exported to database + If method='onthefly' grid data will be passed to PyPSA directly (default) - export_pypsa: bool - If True PyPSA networks will be exported as csv to output/debug/grid// - debug: If True, information is printed during process + export_pypsa: bool + If True PyPSA networks will be exported as csv to output/debug/grid// + debug: bool, defaults to False + If True, information is printed during process + """ if method == 'db': diff --git a/ding0/core/network/__init__.py b/ding0/core/network/__init__.py index 9a9d0ad7..be2d9d35 100644 --- a/ding0/core/network/__init__.py +++ b/ding0/core/network/__init__.py @@ -24,8 +24,13 @@ class GridDing0: Parameters ---------- - id_db : id according to database table - grid_district: class, area that is covered by the lv grid + network : :obj:`int` + Name of the grid #TODO:check + id_db : :obj:`int` + id according to database table #TODO:check + grid_district : :shapely:`Shapely Polygon object` + class, area that is covered by the lv grid #TODO:check + """ def __init__(self, **kwargs): @@ -40,37 +45,81 @@ def __init__(self, **kwargs): self._graph = nx.Graph() def cable_distributors(self): - """Returns a generator for iterating over cable distributors""" + """Returns a generator for iterating over cable distributors + + Yields + ------ + int + Description #TODO check + """ for cable_dist in self._cable_distributors: yield cable_dist def cable_distributors_count(self): - """Returns the count of cable distributors in grid""" + """Returns the count of cable distributors in grid + + Returns + ------- + int + Description #TODO check + """ return len(self._cable_distributors) def loads(self): - """Returns a generator for iterating over grid's loads""" + """Returns a generator for iterating over grid's loads + + Yields + ------ + int + Description #TODO check + """ for load in self._loads: yield load def loads_count(self): - """Returns the count of loads in grid""" + """Returns the count of loads in grid + + Returns + ------- + int + Description #TODO check + """ return len(self._loads) def generators(self): - """Returns a generator for iterating over grid's generators""" + """Returns a generator for iterating over grid's generators + + Yields + ------ + GridDing0 + Description #TODO check + """ for generator in self._generators: yield generator def add_generator(self, generator): - """Adds a generator to _generators and grid graph if not already existing""" + """Adds a generator to _generators and grid graph if not already existing + + Parameters + ---------- + generator : GridDing0 + Description #TODO + + """ if generator not in self._generators and isinstance(generator, GeneratorDing0): self._generators.append(generator) self.graph_add_node(generator) def graph_add_node(self, node_object): - """Adds a station or cable distributor object to grid graph if not already existing""" + """Adds a station or cable distributor object to grid graph if not already existing + + Parameters + ---------- + node_object : GridDing0 + Description #TODO + + """ if ((node_object not in self._graph.nodes()) and (isinstance(node_object, (StationDing0, CableDistributorDing0, @@ -82,9 +131,16 @@ def graph_add_node(self, node_object): def graph_draw(self, mode): """ Draws grid graph using networkx - caution: The geo coords (for used crs see database import in class `NetworkDing0`) are used as positions for - drawing but networkx uses cartesian crs. Since no coordinate transformation is performed, the drawn - graph representation is falsified! + Parameters + ---------- + mode : str + Mode selection 'MV' or 'LV'. #TODO: check + + Notes + ----- + The geo coords (for used crs see database import in class `NetworkDing0`) + are used as positions for drawing but networkx uses cartesian crs. + Since no coordinate transformation is performed, the drawn graph representation is falsified! """ g = self._graph @@ -167,6 +223,11 @@ def graph_draw(self, mode): def graph_nodes_sorted(self): """ Returns an (ascending) sorted list of graph's nodes (name is used as key). + + Returns + ------- + :any:`list` + Description #TODO check """ return sorted(self._graph.nodes(), key=lambda _: repr(_)) @@ -174,10 +235,15 @@ def graph_nodes_sorted(self): def graph_nodes_from_branch(self, branch): """ Returns nodes that are connected by `branch` - Args: - branch: BranchDing0 object - Returns: - 2-tuple of nodes (Ding0 objects) + Args + ---- + branch: BranchDing0 + Description #TODO + + Returns + ------- + (:obj:`GridDing0`, :obj:`GridDing0`) + 2-tuple of nodes (Ding0 objects) #TODO:Check """ edges = nx.get_edge_attributes(self._graph, 'branch') nodes = list(edges.keys())[list(edges.values()).index(branch)] @@ -186,11 +252,20 @@ def graph_nodes_from_branch(self, branch): def graph_branches_from_node(self, node): """ Returns branches that are connected to `node` - Args: - node: Ding0 object (member of graph) - Returns: - branches: List of tuples (node, branch), content: node=Ding0 object (member of graph), - branch=BranchDing0 object + Args + ---- + node: GridDing0 + Ding0 object (member of graph) + + Returns + ------- + :any:`list` + List of tuples (node in :obj:`GridDing0`, branch in :obj:`BranchDing0`) :: + + (node , branch_0 ), + ..., + (node , branch_N ), + """ # TODO: This method can be replaced and speed up by using NetworkX' neighbors() @@ -207,6 +282,11 @@ def graph_edges(self): object itself. Whereas the branch object is used to hold all relevant power system parameters. + Yields + ------ + int + Description #TODO check + Note ---- There are generator functions for nodes (`Graph.nodes()`) and edges @@ -226,7 +306,6 @@ def graph_edges(self): # get edges with attributes edges = nx.get_edge_attributes(self._graph, 'branch').items() - #print(edges) # sort them according to connected nodes edges_sorted = sorted(list(edges), key=lambda _: (''.join(sorted([repr(_[0][0]),repr(_[0][1])])))) @@ -234,24 +313,34 @@ def graph_edges(self): yield {'adj_nodes': edge[0], 'branch': edge[1]} def find_path(self, node_source, node_target, type='nodes'): - """ Determines the shortest path from `node_source` to `node_target` in _graph using networkx' shortest path - algorithm. + """Determines shortest path + + Determines the shortest path from `node_source` to + `node_target` in _graph using networkx' shortest path + algorithm. - Args: - node_source: source node (Ding0 object), member of _graph - node_target: target node (Ding0 object), member of _graph - type : str, Specify if nodes or edges should be returned. Default + Args + ---- + node_source: GridDing0 + source node, member of _graph + node_target: GridDing0 + target node, member of _graph + type : str + Specify if nodes or edges should be returned. Default is `nodes` - Returns: + Returns + ------- + :any:`list` of :obj:`GridDing0` path: shortest path from `node_source` to `node_target` (list of nodes in _graph) - Notes: - WARNING: The shortest path is calculated using the count of hops, not the actual line lengths! - As long as the circuit breakers are open, this works fine since there's only one path. But if - they are closed, there are 2 possible paths. The result is a path which have min. count of hops - but might have a longer total path length than the second sone. - See networkx' function shortest_path() function for details on how the path is calculated. + Notes + ----- + WARNING: The shortest path is calculated using the count of hops, not the actual line lengths! + As long as the circuit breakers are open, this works fine since there's only one path. But if + they are closed, there are 2 possible paths. The result is a path which have min. count of hops + but might have a longer total path length than the second sone. + See networkx' function shortest_path() function for details on how the path is calculated. """ if (node_source in self._graph.nodes()) and (node_target in self._graph.nodes()): path = nx.shortest_path(self._graph, node_source, node_target) @@ -267,14 +356,20 @@ def find_path(self, node_source, node_target, type='nodes'): def find_and_union_paths(self, node_source, nodes_target): """ Determines shortest paths from `node_source` to all nodes in `node_target` in _graph using find_path(). - The branches of all paths are stored in a set - the result is a list of unique branches. + + The branches of all paths are stored in a set - the result is a list of unique branches. - Args: - node_source: source node (Ding0 object), member of _graph - nodes_target: list of target nodes (Ding0 objects), members of _graph - - Returns: - branches: list of branches (list of nodes in _graph) + Args + ---- + node_source: GridDing0 + source node, member of _graph + node_target: GridDing0 + target node, member of _graph + + Returns + ------- + :any:`list` of :obj:`BranchDing0` + branches: list of branches (list of nodes in _graph) #TODO:check """ branches = set() for node_target in nodes_target: @@ -286,13 +381,18 @@ def find_and_union_paths(self, node_source, nodes_target): return list(branches) def graph_path_length(self, node_source, node_target): - """ Calculates the absolute distance between `node_source` and `node_target` in meters using find_path() and - branches' length attribute. - Args: - node_source: source node (Ding0 object), member of _graph - node_target: target node (Ding0 object), member of _graph - - Returns: + """ Calculates the absolute distance between `node_source` and `node_target` in meters using find_path() and branches' length attribute. + + Args + ---- + node_source: GridDing0 + source node, member of _graph + node_target: GridDing0 + target node, member of _graph + + Returns + ------- + float path length in m """ @@ -307,19 +407,23 @@ def graph_path_length(self, node_source, node_target): def graph_isolated_nodes(self): """ Finds isolated nodes = nodes with no neighbors (degree zero) - Args: - none - Returns: + + Returns + ------- + :any:`list` of :obj:`GridDing0` List of nodes (Ding0 objects) """ return sorted(nx.isolates(self._graph), key=lambda x: repr(x)) def control_generators(self, capacity_factor): - """ Sets capacity factor of all generators of a grid (example: A capacity factor of 0.6 means that all - generators are to provide a capacity of 60% of their nominal power). + """ Sets capacity factor of all generators of a grid. + + A capacity factor of 0.6 means that all generators are to provide a capacity of 60% of their nominal power. - Args: - capacity_factor: 0..1 + Args + ---- + capacity_factor: float + Value between 0 and 1. """ for generator in self.generators(): @@ -328,16 +432,26 @@ def control_generators(self, capacity_factor): class StationDing0: """ - Defines a HV-MV or MV-LV station in DING0 + Defines a HV-MV or MV-LV station in DINGO Parameters ---------- - - id_db: id according to database table - v_level_operation: operation voltage level at station (the station's voltage level differs from the nominal voltage - level of the grid (see attribute `v_level` in class MVGridDing0) due to grid losses. It is - usually set to a slightly higher value than the nominal voltage, e.g. 104% in MV grids - (unit: V). + id_db: :obj:`int` + id according to database table + v_level_operation: :obj:`float` + operation voltage level at station (the station's voltage level differs from the nominal voltage level of + the grid due to grid losses). + It is usually set to a slightly higher value than the nominal voltage, e.g. 104% in MV grids. + geo_data : :shapely:`Shapely Point object` + Descr #TODO + grid : :obj:`int` + Desc #TODO + busbar : :obj:`int` + Desc #TODO + + See Also + -------- + (see attribute `v_level` in class MVGridDing0) #TODO where is this? """ def __init__(self, **kwargs): @@ -352,12 +466,24 @@ def network(self): return self.grid.network def transformers(self): - """Returns a generator for iterating over transformers""" + """Returns a generator for iterating over transformers + + Yields + ------ + StationDing0 + Description + """ for trans in self._transformers: yield trans def add_transformer(self, transformer): - """Adds a transformer to _transformers if not already existing""" + """Adds a transformer to _transformers if not already existing + + Args + ---- + transformer : StationDing0 + Description #TODO + """ if transformer not in self.transformers() and isinstance(transformer, TransformerDing0): self._transformers.append(transformer) @@ -365,6 +491,7 @@ def add_transformer(self, transformer): def peak_load(self): """ Cumulative peak load of loads connected to underlying MV or LV grid + (taken from MV or LV Grid District -> top-down) Notes @@ -394,11 +521,15 @@ def network(self): return self._grid.network def branches(self): + """ #TODO: description + """ for branch in self._grid.graph_edges(): if branch['branch'].ring == self: yield branch def lv_load_areas(self): + """ #TODO: description + """ for lv_load_area in self._grid._graph.nodes(): if isinstance(lv_load_area, LVLoadAreaDing0): if lv_load_area.ring == self: @@ -409,15 +540,33 @@ def __repr__(self): class BranchDing0: - """ - Parameter - ---------------- - length : float - Length of line given - type : Association to pandas Series - - Notes: - Important: id_db is not set until whole grid is finished (setting at the end, see method set_branch_ids()) + # TODO: check docstring + """ #TODO Description of Class + + Attributes + ---------- + length : :obj:`float` + Length of line given in m + type : :pandas:`pandas.DataFrame` + Association to pandas Series. DataFrame with attributes of line/cable. + id_db : :obj:`int` + id according to database table + ring : :obj:`int` + Description #TODO + kind : :obj:`str` + 'line' or 'cable' + connects_aggregated : + Description #TODO + circuit_breaker : :obj:`CircuitBreakerDing0` + Description #TODO + + Notes + ----- + Important: id_db is not set until whole grid is finished (setting at the end). + + See Also + -------- + ding0.core.network.grids.MVGridDing0.set_branch_ids """ def __init__(self, **kwargs): @@ -441,22 +590,23 @@ def __repr__(self): class TransformerDing0: - """ - Transformers - ------------ - id_db : int + """ #TODO description Transformers + + Attributes + ---------- + id_db : :obj:`int` id according to database table - v_level : + v_level : :obj:`float` voltage level - s_max_a : float + s_max_a : :obj:`float` rated power (long term) - s_max_b : float + s_max_b : :obj:`float` rated power (short term) - s_max_c : float + s_max_c : :obj:`float` rated power (emergency) - phase_angle : float + phase_angle : :obj:`float` phase shift angle - tap_ratio: float + tap_ratio: :obj:`float` off nominal turns ratio """ @@ -479,6 +629,32 @@ def network(self): class GeneratorDing0: """ Generators (power plants of any kind) + + Attributes + ---------- + id_db : :obj:`int` + id according to database table + name : :obj:`str` + Description #TODO + v_level : :obj:`float` + voltage level + geo_data : :shapely:`Shapely Point object` + Descr #TODO + mv_grid : :obj:`int` + Descr #TODO + lv_load_area : :obj:`int` + Descr #TODO + lv_grid : :obj:`int` + Descr #TODO + capacity : :obj:`float` + Descr #TODO + capacity_factor : :obj:`float` + Descr #TODO + type : :obj:`int` + Descr #TODO + subtype : :obj:`int` + Descr #TODO + """ def __init__(self, **kwargs): @@ -514,8 +690,49 @@ def __repr__(self): '_mvgd' + str(self.mv_grid.id_db) + '_' + str(self.id_db)) +class GeneratorFluctuatingDing0(GeneratorDing0): + """Generator object for fluctuating renewable energy sources + + Attributes + ---------- + _weather_cell_id : :obj:`str` + ID of the weather cell used to generate feed-in time series + + """ + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self._weather_cell_id = kwargs.get('weather_cell_id', None) + + @property + def weather_cell_id(self): + """ + Get weather cell ID + Returns + ------- + :obj:`str` + See class definition for details. + """ + return self._weather_cell_id + + @weather_cell_id.setter + def weather_cell_id(self, weather_cell): + self._weather_cell_id = weather_cell + + class CableDistributorDing0: - """ Cable distributor (connection point) """ + """ Cable distributor (connection point) + + Attributes + ---------- + id_db : :obj:`int` + id according to database table + geo_data : :shapely:`Shapely Point object` + Descr #TODO + grid : :obj:`int` + Descr #TODO + + """ def __init__(self, **kwargs): self.id_db = kwargs.get('id_db', None) @@ -528,7 +745,19 @@ def network(self): class LoadDing0: - """ Class for modelling a load """ + """ Class for modelling a load + + Attributes + ---------- + id_db : :obj:`int` + id according to database table + geo_data : :shapely:`Shapely Point object` + Descr #TODO + grid : :obj:`int` + Descr #TODO + peak_load : :obj:`float` + Descr #TODO + """ def __init__(self, **kwargs): self.id_db = kwargs.get('id', None) @@ -547,10 +776,26 @@ def network(self): class CircuitBreakerDing0: """ Class for modelling a circuit breaker - Notes: - Circuit breakers are nodes of a graph, but are NOT connected via an edge. They are associated to a specific - `branch` of a graph (and the branch refers to the circuit breaker via the attribute `circuit_breaker`) and its - two `branch_nodes`. Via open() and close() the associated branch can be removed from or added to graph. + Attributes + ---------- + id_db : :obj:`int` + id according to database table + geo_data : :shapely:`Shapely Point object` + Descr #TODO + grid : :obj:`int` + Descr #TODO + branch : :obj:`BranchDing0` + Descr #TODO + branch_nodes : (:obj:`GridDing0`, :obj:`GridDing0`) + Tuple of nodes in the branch. + status: :obj:`str`, default 'closed' + Desc #TODO + + Notes + ----- + Circuit breakers are nodes of a graph, but are NOT connected via an edge. They are associated to a specific + `branch` of a graph (and the branch refers to the circuit breaker via the attribute `circuit_breaker`) and its + two `branch_nodes`. Via open() and close() the associated branch can be removed from or added to graph. """ @@ -570,14 +815,20 @@ def __init__(self, **kwargs): @property def network(self): + """ #Todo Description + """ return self.grid.network def open(self): + """ Open a Circuit Breaker #TODO Check + """ self.branch_nodes = self.grid.graph_nodes_from_branch(self.branch) self.grid._graph.remove_edge(self.branch_nodes[0], self.branch_nodes[1]) self.status = 'open' def close(self): + """ Close a Circuit Breaker #TODO Check + """ self.grid._graph.add_edge(self.branch_nodes[0], self.branch_nodes[1], branch=self.branch) self.status = 'closed' diff --git a/ding0/core/network/cable_distributors.py b/ding0/core/network/cable_distributors.py index 968041ce..3eea36b5 100644 --- a/ding0/core/network/cable_distributors.py +++ b/ding0/core/network/cable_distributors.py @@ -17,7 +17,13 @@ class MVCableDistributorDing0(CableDistributorDing0): - """ MV Cable distributor (connection point) """ + """ MV Cable distributor (connection point) + + Attributes + ---------- + lv_load_area_group : + Description #TODO + """ def __init__(self, **kwargs): super().__init__(**kwargs) @@ -27,7 +33,8 @@ def __init__(self, **kwargs): @property def pypsa_id(self): - + """ :obj:`str`: Returns ...#TODO + """ return '_'.join(['MV', str(self.grid.id_db), 'cld', str(self.id_db)]) @@ -36,7 +43,20 @@ def __repr__(self): class LVCableDistributorDing0(CableDistributorDing0): - """ LV Cable distributor (connection point) """ + """ LV Cable distributor (connection point) + + Attributes + ---------- + string_id : + Description #TODO + branch_no : + Description #TODO + load_no : + Description #TODO + in_building : + Description #TODO + + """ def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/ding0/core/network/grids.py b/ding0/core/network/grids.py index a1fc6f1e..0e435f53 100644 --- a/ding0/core/network/grids.py +++ b/ding0/core/network/grids.py @@ -43,9 +43,13 @@ class MVGridDing0(GridDing0): Parameters ---------- - region : MV region (instance of MVGridDistrictDing0 class) that is associated with grid - default_branch_kind: kind of branch (possible values: 'cable' or 'line') - default_branch_type: type of branch (pandas Series object with cable/line parameters) + region : :obj:`MVGridDistrictDing0` + MV region (instance of MVGridDistrictDing0 class) that is associated with grid + default_branch_kind: :obj:`str` + kind of branch (possible values: 'cable' or 'line') + default_branch_type: :pandas:`pandas.Series` + type of branch (pandas Series object with cable/line parameters) + """ # TODO: Add method to join MV graph with LV graphs to have one graph that covers whole grid (MV and LV) @@ -80,31 +84,36 @@ def circuit_breakers_count(self): return len(self._circuit_breakers) def add_circuit_breaker(self, circ_breaker): - """ Creates circuit breaker object and ... + """Creates circuit breaker object and ... - Args: - circ_breaker: CircuitBreakerDing0 object + Args + ---- + circ_breaker: CircuitBreakerDing0 + Description #TODO """ if circ_breaker not in self._circuit_breakers and isinstance(circ_breaker, CircuitBreakerDing0): self._circuit_breakers.append(circ_breaker) self.graph_add_node(circ_breaker) def open_circuit_breakers(self): - """ Opens all circuit breakers in MV grid """ + """Opens all circuit breakers in MV grid """ for circ_breaker in self.circuit_breakers(): circ_breaker.open() def close_circuit_breakers(self): - """ Closes all circuit breakers in MV grid """ + """Closes all circuit breakers in MV grid """ for circ_breaker in self.circuit_breakers(): circ_breaker.close() def add_station(self, mv_station, force=False): - """ Adds MV station if not already existing - - Args: - mv_station: MVStationDing0 object - force: bool. If True, MV Station is set even though it's not empty (override) + """Adds MV station if not already existing + + Args + ---- + mv_station: MVStationDing0 + Description #TODO + force: bool + If True, MV Station is set even though it's not empty (override) """ if not isinstance(mv_station, MVStationDing0): raise Exception('Given MV station is not a MVStationDing0 object.') @@ -118,14 +127,26 @@ def add_station(self, mv_station, force=False): raise Exception('MV Station already set, use argument `force=True` to override.') def add_load(self, lv_load): - """Adds a MV load to _loads and grid graph if not already existing""" + """Adds a MV load to _loads and grid graph if not already existing + + Args + ---- + lv_load : float + Desription #TODO + """ if lv_load not in self._loads and isinstance(lv_load, MVLoadDing0): self._loads.append(lv_load) self.graph_add_node(lv_load) def add_cable_distributor(self, cable_dist): - """Adds a cable distributor to _cable_distributors if not already existing""" + """Adds a cable distributor to _cable_distributors if not already existing + + Args + ---- + cable_dist : float + Desription #TODO + """ if cable_dist not in self.cable_distributors() and isinstance(cable_dist, MVCableDistributorDing0): # add to array and graph @@ -147,20 +168,35 @@ def add_ring(self, ring): self._rings.append(ring) def rings_count(self): - """Returns the count of rings in MV grid""" + """Returns the count of rings in MV grid + + Returns + ------- + int + Count of ringos in MV grid. + """ return len(self._rings) def rings_nodes(self, include_root_node=False, include_satellites=False): """ Returns a generator for iterating over rings (=routes of MVGrid's graph) - Args: - include_root_node: If True, the root node is included in the list of ring nodes. - include_satellites: If True, the satellite nodes (nodes that diverge from ring nodes) is included in the - list of ring nodes. - Returns: + Args + ---- + include_root_node: bool, defaults to False + If True, the root node is included in the list of ring nodes. + include_satellites: bool, defaults to False + If True, the satellite nodes (nodes that diverge from ring nodes) is included in the list of ring nodes. + + Yields + ------ + :any:`list` of :obj:`GridDing0` List with nodes of each ring of _graph in- or excluding root node (HV/MV station) (arg `include_root_node`), - format: [ring_m_node_1, ..., ring_m_node_n] - Notes: + format:: + + [ ring_m_node_1, ..., ring_m_node_n ] + + Notes + ----- Circuit breakers must be closed to find rings, this is done automatically. """ for circ_breaker in self.circuit_breakers(): @@ -217,7 +253,7 @@ def rings_full_data(self): ##Find "rings" associated to aggregated LA #for node in self.graph_nodes_sorted(): - # if isinstance(node,LVLoadAreaCentreDingo): # MVCableDistributorDingo + # if isinstance(node,LVLoadAreaCentreDing0): # MVCableDistributorDing0 # edges_ring = [] # ring_nodes = [] # if node.lv_load_area.is_aggregated: @@ -230,10 +266,15 @@ def rings_full_data(self): def get_ring_from_node(self, node): """ Determines the ring (RingDing0 object) which node is member of. - Args: - node: Ding0 object (member of graph) - Returns: - RingDing0 object + Args + ---- + node: GridDing0 + Ding0 object (member of graph) + + Returns + ------- + RingDing0 + Ringo of which node is member. """ try: return self.graph_branches_from_node(node)[0][1]['branch'].ring @@ -241,15 +282,21 @@ def get_ring_from_node(self, node): raise Exception('Cannot get node\'s associated ring.') def graph_nodes_from_subtree(self, node_source): - """ Finds all nodes of a tree that is connected to `node_source` and are (except `node_source`) not part of the - ring of `node_source` (traversal of graph from `node_source` excluding nodes along ring). - Example: A given graph with ring (edges) 0-1-2-3-4-5-0 and a tree starting at node (`node_source`) 3 with - edges 3-6-7, 3-6-8-9 will return [6,7,8,9] + """ Finds all nodes of a tree that is connected to `node_source` and are (except `node_source`) not part of the + ring of `node_source` (traversal of graph from `node_source` excluding nodes along ring). + + Example + ------- + A given graph with ring (edges) 0-1-2-3-4-5-0 and a tree starting at node (`node_source`) 3 with edges 3-6-7, 3-6-8-9 will return [6,7,8,9] - Args: - node_source: source node (Ding0 object), member of _graph + Args + ---- + node_source: GridDing0 + source node (Ding0 object), member of _graph - Returns: + Returns + ------- + :any:`list` of :obj:`GridDing0` List of nodes (Ding0 objects) """ if node_source in self._graph.nodes(): @@ -301,8 +348,12 @@ def set_branch_ids(self): def routing(self, debug=False, anim=None): """ Performs routing on Load Area centres to build MV grid with ring topology. - Args: - debug: If True, information is printed while routing + Args + ---- + debug: bool, defaults to False + If True, information is printed while routing + anim: type, defaults to None + Descr #TODO """ # do the routing @@ -334,20 +385,29 @@ def routing(self, debug=False, anim=None): def connect_generators(self, debug=False): """ Connects MV generators (graph nodes) to grid (graph) - Args: - debug: If True, information is printed during process + Args + ---- + debug: bool, defaults to False + If True, information is printed during process """ self._graph = mv_connect.mv_connect_generators(self.grid_district, self._graph, debug) def parametrize_grid(self, debug=False): - """ Performs Parametrization of grid equipment: 1. Sets voltage level of MV grid, 2. Operation voltage level - and transformer of HV/MV station, 3. Default branch types (normal, aggregated, settlement) - - Args: - debug: If True, information is printed during process - Notes: - It is assumed that only cables are used within settlements + """ Performs Parametrization of grid equipment: + + i) Sets voltage level of MV grid, + ii) Operation voltage level and transformer of HV/MV station, + iii) Default branch types (normal, aggregated, settlement) + + Args + ---- + debug: bool, defaults to False + If True, information is printed during process. + + Notes + ----- + It is assumed that only cables are used within settlements. """ # TODO: Add more detailed description @@ -371,30 +431,30 @@ def parametrize_grid(self, debug=False): def set_voltage_level(self, mode='distance'): """ Sets voltage level of MV grid according to load density of MV Grid District or max. - distance between station and Load Area. + distance between station and Load Area. Parameters ---------- - mode: String - determines how voltage level is determined: - - 'load_density': Decision on voltage level is determined by load density - of the considered region. Urban areas (load density of - >= 1 MW/km2 according to [1]_) usually got a voltage of - 10 kV whereas rural areas mostly use 20 kV. - - 'distance' (default): Decision on voltage level is determined by the max. - distance between Grid District's HV-MV station and Load - Areas (LA's centre is used). According to [2]_ a value of - 1kV/km can be assumed. The `voltage_per_km_threshold` - defines the distance threshold for distinction. - (default in config = (20km+10km)/2 = 15km) + mode: str + method to determine voltage level + + * 'load_density': Decision on voltage level is determined by load density + of the considered region. Urban areas (load density of + >= 1 MW/km2 according to [#]_) usually got a voltage of + 10 kV whereas rural areas mostly use 20 kV. + + * 'distance' (default): Decision on voltage level is determined by the max. + distance between Grid District's HV-MV station and Load + Areas (LA's centre is used). According to [#]_ a value of + 1kV/kV can be assumed. The `voltage_per_km_threshold` + defines the distance threshold for distinction. + (default in config = (20km+10km)/2 = 15km) References ---------- - .. [1] Falk Schaller et al., "Modellierung realitätsnaher zukünftiger Referenznetze im Verteilnetzsektor zur + .. [#] Falk Schaller et al., "Modellierung realitätsnaher zukünftiger Referenznetze im Verteilnetzsektor zur Überprüfung der Elektroenergiequalität", Internationaler ETG-Kongress Würzburg, 2011 - .. [2] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 + .. [#] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 """ @@ -458,32 +518,37 @@ def set_voltage_level(self, mode='distance'): def set_default_branch_type(self, debug=False): """ Determines default branch type according to grid district's peak load and standard equipment. - Args: - debug: If True, information is printed during process + Args + ---- + debug: bool, defaults to False + If True, information is printed during process - Returns: + Returns + ------- + :pandas:`pandas.Series` default branch type: pandas Series object. If no appropriate type is found, return largest possible one. + :pandas:`pandas.Series` default branch type max: pandas Series object. Largest available line/cable type Notes ----- - Parameter values for cables and lines are taken from [1]_, [2]_ and [3]_. + Parameter values for cables and lines are taken from [#]_, [#]_ and [#]_. - Lines are chosen to have 60 % load relative to their nominal capacity according to [4]_. + Lines are chosen to have 60 % load relative to their nominal capacity according to [#]_. Decision on usage of overhead lines vs. cables is determined by load density of the considered region. Urban areas usually are equipped with underground cables whereas rural areas often have overhead lines as MV - distribution system [5]_. + distribution system [#]_. References ---------- - .. [1] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 - .. [2] René Flosdorff et al., "Elektrische Energieverteilung", Vieweg+Teubner, 2005 - .. [3] Südkabel GmbH, "Einadrige VPE-isolierte Mittelspannungskabel", + .. [#] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 + .. [#] René Flosdorff et al., "Elektrische Energieverteilung", Vieweg+Teubner, 2005 + .. [#] Südkabel GmbH, "Einadrige VPE-isolierte Mittelspannungskabel", http://www.suedkabel.de/cms/upload/pdf/Garnituren/Einadrige_VPE-isolierte_Mittelspannungskabel.pdf, 2017 - .. [4] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der + .. [#] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030.", 2012 - .. [5] Tao, X., "Automatisierte Grundsatzplanung von + .. [#] Tao, X., "Automatisierte Grundsatzplanung von Mittelspannungsnetzen", Dissertation, RWTH Aachen, 2007 """ @@ -584,11 +649,11 @@ def set_default_branch_type(self, debug=False): def set_nodes_aggregation_flag(self, peak_current_branch_max): """ Set Load Areas with too high demand to aggregated type. - Args: - peak_current_branch_max: Max. allowed current for line/cable + Args + ---- + peak_current_branch_max: float + Max. allowed current for line/cable - Returns: - nothing """ for lv_load_area in self.grid_district.lv_load_areas(): @@ -607,11 +672,13 @@ def export_to_pypsa(self, session, method='onthefly'): Parameters ---------- - session: SQLalchemy database session + session: :sqlalchemy:`SQLAlchemy session object` + Description method: str - Specify export method - If method='db' grid data will be exported to database - If method='onthefly' grid data will be passed to PyPSA directly (default) + Specify export method:: + + 'db': grid data will be exported to database + 'onthefly': grid data will be passed to PyPSA directly (default) Notes ----- @@ -669,19 +736,26 @@ def export_to_pypsa(self, session, method='onthefly'): def run_powerflow(self, session, export_pypsa_dir=None, method='onthefly', debug=False): """ Performs power flow calculation for all MV grids - Args: - session: SQLalchemy database session - export_pypsa_dir: str - Sub-directory in output/debug/grid/ where csv Files of PyPSA network are exported to. - Export is omitted if argument is empty. - method: str - Specify export method - If method='db' grid data will be exported to database - If method='onthefly' grid data will be passed to PyPSA directly (default) - debug: If True, information is printed during process + Args + ---- + session: :sqlalchemy:`SQLAlchemy session object` + Description #TODO + export_pypsa_dir: str + Sub-directory in output/debug/grid/ where csv Files of PyPSA network are exported to. + + Export is omitted if argument is empty. + method: str + Specify export method:: + + 'db': grid data will be exported to database + 'onthefly': grid data will be passed to PyPSA directly (default) + + debug: bool, defaults to False + If True, information is printed during process - Notes: - It has to be proven that this method works for LV grids as well! + Notes + ----- + It has to be proven that this method works for LV grids as well! Ding0 treats two stationary case of powerflow: 1) Full load: We assume no generation and loads to be set to peak load @@ -700,15 +774,13 @@ def run_powerflow(self, session, export_pypsa_dir=None, method='onthefly', debu debug=debug) def import_powerflow_results(self, session): - """ - Assign results from power flow analysis to edges and nodes + """Assign results from power flow analysis to edges and nodes Parameters ---------- - session: SQLalchemy database session - Returns - ------- - None + session: :sqlalchemy:`SQLAlchemy session object` + Description + """ # bus data @@ -720,15 +792,24 @@ def import_powerflow_results(self, session): # transformer data def reinforce_grid(self): - """ Performs grid reinforcement measures for current MV grid """ + """Performs grid reinforcement measures for current MV grid + + """ + # TODO: Finalize docstring reinforce_grid(self, mode='MV') def set_circuit_breakers(self, debug=False): - """ Calculates the optimal position of the existing circuit breakers and relocates them within the graph, - see method `set_circuit_breakers` in ding0.grid.mv_grid.tools for details. - Args: - debug: If True, information is printed during process + """ Calculates the optimal position of the existing circuit breakers and relocates them within the graph. + + Args + ---- + debug: bool, defaults to False + If True, information is printed during process + + See Also + -------- + ding0.grid.mv_grid.tools.set_circuit_breakers """ set_circuit_breakers(self, debug=debug) @@ -741,10 +822,16 @@ class LVGridDing0(GridDing0): Parameters ---------- - region : LV region (instance of LVLoadAreaDing0 class) that is associated with grid - - Notes: - It is assumed that LV grid have got cables only (attribute 'default_branch_kind') + region : LVLoadAreaDing0 + LV region that is associated with grid + default_branch_kind : str + description #TODO + population : + description #TODO + + Notes + ----- + It is assumed that LV grid have got cables only (attribute 'default_branch_kind') """ def __init__(self, **kwargs): @@ -768,18 +855,20 @@ def add_station(self, lv_station): self.grid_district.lv_load_area.mv_grid_district.mv_grid.graph_add_node(lv_station) def loads_sector(self, sector='res'): - """ - Returns a generator for iterating over grid's sectoral loads + """Returns a generator for iterating over grid's sectoral loads Parameters ---------- sector: String - possible values: 'res' (residential), - 'ria' (retail, industrial, agricultural) + possible values:: + + 'res' (residential), + 'ria' (retail, industrial, agricultural) - Returns + Yields ------- - Generator for iterating over loads of the type specified in `sector`. + int + Generator for iterating over loads of the type specified in `sector`. """ for load in self._loads: @@ -789,22 +878,33 @@ def loads_sector(self, sector='res'): yield load def add_load(self, lv_load): - """Adds a LV load to _loads and grid graph if not already existing""" + """Adds a LV load to _loads and grid graph if not already existing + + Parameters + ---------- + lv_load : + Description #TODO + """ if lv_load not in self._loads and isinstance(lv_load, LVLoadDing0): self._loads.append(lv_load) self.graph_add_node(lv_load) def add_cable_dist(self, lv_cable_dist): - """Adds a LV cable_dist to _cable_dists and grid graph if not already existing""" + """Adds a LV cable_dist to _cable_dists and grid graph if not already existing + + Parameters + ---------- + lv_cable_dist : + Description #TODO + """ if lv_cable_dist not in self._cable_distributors and isinstance(lv_cable_dist, LVCableDistributorDing0): self._cable_distributors.append(lv_cable_dist) self.graph_add_node(lv_cable_dist) def build_grid(self): - """ - Create LV grid graph + """Create LV grid graph """ # add required transformers @@ -821,14 +921,18 @@ def build_grid(self): def connect_generators(self, debug=False): """ Connects LV generators (graph nodes) to grid (graph) - Args: - debug: If True, information is printed during process + Args + ---- + debug: bool, defaults to False + If True, information is printed during process """ self._graph = lv_connect.lv_connect_generators(self.grid_district, self._graph, debug) def reinforce_grid(self): - """ Performs grid reinforcement measures for current LV grid """ + """ Performs grid reinforcement measures for current LV grid. + """ + # TODO: Finalize docstring reinforce_grid(self, mode='LV') diff --git a/ding0/core/network/loads.py b/ding0/core/network/loads.py index 5ca5c889..efa0c915 100644 --- a/ding0/core/network/loads.py +++ b/ding0/core/network/loads.py @@ -20,6 +20,9 @@ class MVLoadDing0(LoadDing0): """ Load in MV grids + Notes + ----- + Currently not used, check later if still required """ # TODO: Currently not used, check later if still required @@ -47,4 +50,4 @@ def __init__(self, **kwargs): self.load_no = kwargs.get('load_no', None) def __repr__(self): - return 'lv_load_' + str(self.id_db) \ No newline at end of file + return 'lv_load_' + str(self.id_db) diff --git a/ding0/core/network/stations.py b/ding0/core/network/stations.py index 18fefe44..d713774a 100644 --- a/ding0/core/network/stations.py +++ b/ding0/core/network/stations.py @@ -23,31 +23,30 @@ class MVStationDing0(StationDing0): """ - Defines a MV station in DING0 - ----------------------------- + Defines a MV station in DINGO """ def __init__(self, **kwargs): super().__init__(**kwargs) def peak_generation(self, mode): - """ - Calculates cumulative peak generation of generators connected to - underlying MV grid or MV+LV grids (controlled by parameter `mode`). + """Calculates cumulative peak generation of generators connected to underlying grids + This is done instantaneously using bottom-up approach. Parameters ---------- - mode: String - determines which generators are included: + mode: str + determines which generators are included:: 'MV': Only generation capacities of MV level are considered. + 'MVLV': Generation capacities of MV and LV are considered (= cumulative generation capacities in entire MVGD). Returns ------- - capacity: Float + float Cumulative peak generation """ @@ -68,6 +67,9 @@ def peak_generation(self, mode): raise ValueError('parameter \'mode\' is invalid!') def set_operation_voltage_level(self): + """Set operation voltage level + + """ mv_station_v_level_operation = float(cfg_ding0.get('mv_routing_tech_constraints', 'mv_station_v_level_operation')) @@ -92,17 +94,20 @@ def select_transformers(self): **kwargs : dict Should contain a value behind the key 'peak_load' + Notes ----- - Potential HV-MV transformers are chosen according to [2]_. - Parametrization of transformers bases on [1]_. + Parametrization of transformers bases on [#]_. + + Potential hv-mv-transformers are chosen according to [#]_. + References ---------- - .. [1] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. + .. [#] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030.", 2012 - .. [2] X. Tao, "Automatisierte Grundsatzplanung von + .. [#] X. Tao, "Automatisierte Grundsatzplanung von Mittelspannungsnetzen", Dissertation, 2006 """ @@ -174,6 +179,9 @@ def select_transformers(self): @property def pypsa_id(self): + #TODO: docstring + """ Description + """ return '_'.join(['HV', str(self.grid.id_db), 'trd']) def __repr__(self): @@ -182,8 +190,7 @@ def __repr__(self): class LVStationDing0(StationDing0): """ - Defines a LV station in DING0 - ----------------------------- + Defines a LV station in DINGO """ def __init__(self, **kwargs): @@ -193,14 +200,13 @@ def __init__(self, **kwargs): @property def peak_generation(self): - """ - Calculates cumulative peak generation of generators connected to - underlying LV grid. This is done instantaneously using bottom-up - approach. + """Calculates cumulative peak generation of generators connected to underlying LV grid. + + This is done instantaneously using bottom-up approach. Returns ------- - capacity: Float + float Cumulative peak generation """ @@ -208,6 +214,9 @@ def peak_generation(self): @property def pypsa_id(self): + #TODO: docstring + """ Description + """ return '_'.join(['MV', str( self.grid.grid_district.lv_load_area.mv_grid_district.mv_grid.\ id_db), 'tru', str(self.id_db)]) diff --git a/ding0/core/powerflow/__init__.py b/ding0/core/powerflow/__init__.py index 41a8fb58..a9f117d0 100644 --- a/ding0/core/powerflow/__init__.py +++ b/ding0/core/powerflow/__init__.py @@ -20,23 +20,38 @@ class PFConfigDing0: """ Defines the PF scenario configuration - Args: - scenarios: List of strings describing the scenarios - timerange: List of Pandas DatetimeIndex objects - timesteps_count: int, count of timesteps the timesteps to be created - timestep_start: Datetime datetime object - resolution: String or pandas offset object, e.g. 'H'=hourly resolution, - to learn more see http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases - srid: Spatial reference system indentifier used by PyPSA's plots - - Notes: - This class can be called as follows: - 1. With scenarios and timeranges: scenarios = ['scn_1', ..., 'scn_n'], - timeranges= [timerange_1, ..., timerange_n] - 2. With scenarios, start time and count of timesteps: scenarios = ['scn_1', ..., 'scn_n'], - timesteps_count = m, - timestep_start = datetime() - (in this case, n timeranges with m timesteps starting from datetime will be created) + Parameters + ---------- + scenarios: :any:`list` of :obj:`str` + List of strings describing the scenarios + timerange: :any:`list` of :pandas:`pandas.DatetimeIndex` + List of Pandas DatetimeIndex objects + timesteps_count: int + count of timesteps the timesteps to be created + timestep_start: :pandas:`pandas.DatetimeIndex` + Description #TODO + resolution: str + String or pandas offset object, e.g. 'H'=hourly resolution, + + to learn more see http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases + srid: type + partial reference system indentifier used by PyPSA's plots #TODO + + Notes + ----- + This class can be called as follows: + + i) With scenarios and timeranges:: + + scenarios = ['scn_1', ..., 'scn_n'], + timeranges= [timerange_1, ..., timerange_n] + ii) With scenarios, start time and count of timesteps:: + + scenarios = ['scn_1', ..., 'scn_n'], + timesteps_count = m, + timestep_start = datetime() + + (in this case, n timeranges with m timesteps starting from datetime will be created) """ def __init__(self, **kwargs): @@ -86,5 +101,5 @@ def resolution(self): @property def srid(self): - """ Returns SRID """ + """ Returns SRID""" return self._srid diff --git a/ding0/core/structure/groups.py b/ding0/core/structure/groups.py index 00afcd20..34410eed 100644 --- a/ding0/core/structure/groups.py +++ b/ding0/core/structure/groups.py @@ -18,9 +18,20 @@ class LoadAreaGroupDing0: - """ Container for small load_areas / load areas (satellites) = a group of stations which are within the same - satellite string. It is required to check whether a satellite string has got more load or string length than - allowed, hence new nodes cannot be added to it. + # TODO: check docstring + """ Container for small load_areas / load areas (satellites). + + A group of stations which are within the same satellite string. It is + required to check whether a satellite string has got more load or string + length than allowed, hence new nodes cannot be added to it. + + Attributes + ---------- + id_db: :obj:`int` + Descr + mv_grid_district : :shapely:`Shapely Polygon object` + Desc + """ def __init__(self, **kwargs): @@ -43,19 +54,47 @@ def network(self): return self.mv_grid_district.network def lv_load_areas(self): - """Returns a generator for iterating over load_areas""" + # TODO: check docstring + """Returns a generator for iterating over load_areas + + Yields + ------ + int + generator for iterating over load_areas + """ for load_area in self._lv_load_areas: yield load_area def add_lv_load_area(self, lv_load_area): - """Adds a LV load_area to _lv_load_areas if not already existing""" + # TODO: check docstring + """Adds a LV load_area to _lv_load_areas if not already existing + + Args + ---- + lv_load_area: :shapely:`Shapely Polygon object` + Descr + """ self._lv_load_areas.append(lv_load_area) if not isinstance(lv_load_area, MVCableDistributorDing0): self.peak_load += lv_load_area.peak_load def can_add_lv_load_area(self, node): - """Sums up peak load of LV stations = total peak load for satellite string""" - + # 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') diff --git a/ding0/core/structure/regions.py b/ding0/core/structure/regions.py index 4cfbed1b..64de080b 100644 --- a/ding0/core/structure/regions.py +++ b/ding0/core/structure/regions.py @@ -20,10 +20,21 @@ class MVGridDistrictDing0(RegionDing0): - """ - Defines a MV-grid_district in DING0 - ---------------------------- - + # TODO: check docstring + """Defines a MV-grid_district in DINGO + + Attributes + ---------- + mv_grid: :obj:`int` + Descr + geo_data : :shapely:`Shapely Polygon object` + Descr + peak_load: :obj:`float` + Descr + peak_load_satellites: :obj:`float` + Descr + peak_load_aggregated: :obj:`float` + Descr """ def __init__(self, **kwargs): @@ -50,40 +61,62 @@ def network(self): return self.mv_grid.network def lv_load_areas(self): - """Returns a generator for iterating over load_areas""" + """Returns a generator for iterating over load_areas + + Yields + ------ + int + generator for iterating over load_areas + """ for load_area in sorted(self._lv_load_areas, key=lambda _: repr(_)): yield load_area def add_lv_load_area(self, lv_load_area): - """ Adds a Load Area `lv_load_area` to _lv_load_areas if not already existing, and adds the associated centre - object to MV grid's _graph as node. - - Args: - lv_load_area: instance of class LVLoadAreaDing0 - - Returns: - nothing + """ Adds a Load Area `lv_load_area` to _lv_load_areas if not already existing + + Additionally, adds the associated centre object to MV grid's _graph as node. + + Args + ---- + lv_load_area: LVLoadAreaDing0 + instance of class LVLoadAreaDing0 """ if lv_load_area not in self.lv_load_areas() and isinstance(lv_load_area, LVLoadAreaDing0): self._lv_load_areas.append(lv_load_area) self.mv_grid.graph_add_node(lv_load_area.lv_load_area_centre) def lv_load_area_groups(self): - """Returns a generator for iterating over LV load_area groups""" + """Returns a generator for iterating over LV load_area groups. + + Yields + ------ + int + generator for iterating over LV load_areas + """ for lv_load_area_group in self._lv_load_area_groups: yield lv_load_area_group def lv_load_area_groups_count(self): - """Returns the count of LV load_area groups in MV region""" + """Returns the count of LV load_area groups in MV region + + Returns + ------- + int + Number of LV load_area groups in MV region. + """ return len(self._lv_load_area_groups) def add_lv_load_area_group(self, lv_load_area_group): - """Adds a LV load_area to _lv_load_areas if not already existing""" + """Adds a LV load_area to _lv_load_areas if not already existing. + """ if lv_load_area_group not in self.lv_load_area_groups(): self._lv_load_area_groups.append(lv_load_area_group) def add_peak_demand(self): - """Summarizes peak loads of underlying load_areas in kVA (peak load sum and peak load of satellites)""" + """Summarizes peak loads of underlying load_areas in kVA. + + (peak load sum and peak load of satellites) + """ peak_load = peak_load_satellites = 0 for lv_load_area in self.lv_load_areas(): peak_load += lv_load_area.peak_load @@ -105,10 +138,25 @@ def __repr__(self): class LVLoadAreaDing0(RegionDing0): - """ - Defines a LV-load_area in DING0 - ---------------------------- + # TODO: check docstring + """Defines a LV-load_area in DINGO + Attributes + ---------- + ring: int + Descr + mv_grid_district : :shapely:`Shapely Polygon object` + Descr + lv_load_area_centre: :shapely:`Shapely Point object` + Descr + lv_load_area_group: :shapely:`Shapely Polygon object` + Descr + is_satellite: bool + Descr + is_aggregated: bool + Descr + db_data: DataFrame + Descr """ def __init__(self, **kwargs): @@ -163,16 +211,35 @@ def network(self): return self.mv_grid_district.network def lv_grid_districts(self): - """Returns a generator for iterating over LV grid districts""" + """Returns a generator for iterating over LV grid districts + + Yields + ------ + int + generator for iterating over LV grid districts + """ for lv_grid_district in sorted(self._lv_grid_districts, key=lambda _: repr(_)): yield lv_grid_district def lv_grid_districts_count(self): - """Returns the count of LV grid districts""" + """Returns the count of LV grid districts + + Returns + ------- + int + Number of LV grid districts. + """ return len(self._lv_grid_districts) def add_lv_grid_district(self, lv_grid_district): - """Adds a LV grid district to _lv_grid_districts if not already existing""" + # TODO: check docstring + """Adds a LV grid district to _lv_grid_districts if not already existing + + Args + ---- + lv_grid_district: :shapely:`Shapely Polygon object` + Descr + """ if lv_grid_district not in self._lv_grid_districts and \ isinstance(lv_grid_district, LVGridDistrictDing0): @@ -180,8 +247,8 @@ def add_lv_grid_district(self, lv_grid_district): @property def peak_generation(self): - """ - Cumulative peak generation of generators connected to LV grids of underlying LVGDs + """Cumulative peak generation of generators connected to LV grids of + underlying LVGDs """ cum_peak_generation = 0 @@ -195,16 +262,26 @@ def __repr__(self): class LVLoadAreaCentreDing0: - """ - Defines a region centre in Ding0 - -------------------------------- + # TODO: check docstring + """Defines a region centre in Ding0. + The centres are used in the MV routing as nodes. - Note: Centre is a point within a region's polygon that is located most central (e.g. in a simple region shape like a - circle it's the geometric center). + + Notes + ----- + Centre is a point within a region's polygon that is located most central + (e.g. in a simple region shape like a circle it's the geometric center). Parameters ---------- - id_db: unique ID in database (=id of associated load area) + id_db: int + unique ID in database (=id of associated load area) + grid: int + Descr + geo_data: :shapely:`Shapely Point object` + Descr + lv_load_area: int + Descr """ def __init__(self, **kwargs): self.id_db = kwargs.get('id_db', None) @@ -225,13 +302,37 @@ def __repr__(self): class LVGridDistrictDing0(RegionDing0): - """ - Describes region that is covered by a single LV grid + # TODO: check docstring + """Describes region that is covered by a single LV grid Parameters ---------- - RegionDing0: class - Ding0's region base class + geo_data: :shapely:`Shapely Polygon object` + Descr + lv_load_area : :shapely:`Shapely Polygon object` + Descr + lv_grid: :shapely:`Shapely Polygon object` + Descr + population: :obj:`float` + Descr + peak_load_residential: :obj:`float` + Descr + peak_load_retail: :obj:`float` + Descr + peak_load_industrial: :obj:`float` + Descr + peak_load_agricultural: :obj:`float` + Descr + peak_load: :obj:`float` + Descr + sector_count_residential: :obj:`int` + Descr + sector_count_retail: :obj:`int` + Descr + sector_count_industrial: :obj:`int` + Descr + sector_count_agricultural: :obj:`int` + Descr """ def __init__(self, **kwargs): diff --git a/ding0/flexopt/check_tech_constraints.py b/ding0/flexopt/check_tech_constraints.py index 43e4470b..cd78213c 100644 --- a/ding0/flexopt/check_tech_constraints.py +++ b/ding0/flexopt/check_tech_constraints.py @@ -29,29 +29,46 @@ def check_load(grid, mode): - """ Checks for over-loading of branches and transformers for MV or LV grid + """ Checks for over-loading of branches and transformers for MV or LV grid. Parameters ---------- - grid: GridDing0 object - mode: String - kind of grid ('MV' or 'LV') + grid : GridDing0 + Grid identifier. + mode : str + Kind of grid ('MV' or 'LV'). Returns ------- - Dict of critical branches (BranchDing0 objects) with max. relative overloading - List of critical transformers (TransformerDing0 objects), - Format: {branch_1: rel_overloading_1, ..., branch_n: rel_overloading_n}, - [trafo_1, ..., trafo_m] + :obj:`dict` + Dict of critical branches with max. relative overloading, and the + following format:: + + { + branch_1: rel_overloading_1, + ..., + branch_n: rel_overloading_n + } + + :any:`list` of :obj:`GridDing0` + List of critical transformers with the following format:: + + [trafo_1, ..., trafo_m] Notes ----- - Lines'/cables' max. capacity (load case and feed-in case) are taken from [1]_. + Lines'/cables' max. capacity (load case and feed-in case) are taken from [#]_. + References ---------- - .. [1] dena VNS - + .. [#] dena VNS + + See Also + -------- + ding0.flexopt.reinforce_measures.reinforce_branches_current : + ding0.flexopt.reinforce_measures.reinforce_branches_voltage : + """ crit_branches = {} @@ -140,17 +157,27 @@ def check_voltage(grid, mode): Parameters ---------- - grid: GridDing0 object - mode: String - kind of grid ('MV' or 'LV') + grid : GridDing0 + Grid identifier. + mode : str + Kind of grid ('MV' or 'LV'). Returns ------- - List of critical nodes, sorted descending by voltage difference + :any:`list` of :any:`GridDing0` + List of critical nodes, sorted descending by voltage difference. Notes ----- - The voltage is checked against a max. allowed voltage deviation. + The examination is done in two steps, according to [#]_ : + + 1. It is checked #TODO: what? + + 2. #TODO: what's next? + + References + ---------- + .. [#] dena VNS """ crit_nodes = {} @@ -200,9 +227,9 @@ def get_critical_line_loading(grid): Returns ------- - critical_branches : list + :any:`list` List of critical branches incl. its line loading - critical_stations : list + :any:`list` List of critical stations incl. its transformer loading """ cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load') @@ -284,15 +311,15 @@ def peak_load_generation_at_node(nodes): Parameters ---------- - nodes : list + nodes : :any:`list` Any LV grid Ding0 node object that is part of the grid topology Return ------ - peak_load : numeric - Sum of peak loads of descendant nodes - peak_generation : numeric - Sum of nominal power of generation at descendant nodes + :any:`float` + peak_load : Sum of peak loads of descendant nodes + :any:`float` + peak_generation : Sum of nominal power of generation at descendant nodes """ loads = [node.peak_load for node in nodes @@ -313,49 +340,47 @@ def get_critical_voltage_at_nodes(grid): Based on voltage level at each node of the grid critical nodes in terms of exceed tolerable voltage drop/increase are determined. - The tolerable voltage drop/increase is defined by [VDE-AR]_ a adds up to + The tolerable voltage drop/increase is defined by [#VDE]_ a adds up to 3 % of nominal voltage. The longitudinal voltage drop at each line segment is estimated by a simplified approach (neglecting the transverse voltage drop) described in - [VDE-AR]_. + [#VDE]_. Two equations are available for assessing voltage drop/ voltage increase. The first is used to assess a voltage drop in the load case .. math:: - \Delta u = \frac{S_{Amax} \cdot ( R_{kV} \cdot cos(\phi) + X_{kV} \cdot sin(\phi) )}{U_{nom}} + \\Delta u = \\frac{S_{Amax} \cdot ( R_{kV} \cdot cos(\phi) + X_{kV} \cdot sin(\phi) )}{U_{nom}} The second equation can be used to assess the voltage increase in case of feedin. The only difference is the negative sign before X. This is related to consider a voltage drop due to inductive operation of generators. .. math:: - \Delta u = \frac{S_{Amax} \cdot ( R_{kV} \cdot cos(\phi) - X_{kV} \cdot sin(\phi) )}{U_{nom}} - - .. TODO: correct docstring such that documentation builds properly - - ================ ============================= - Symbol Description - ================ ============================= - :math:`\Delta u` Voltage drop/increase at node - :math:`S_{Amax}` Apparent power - :math:`R_{kV}` Short-circuit resistance - :math:`X_{kV}` Short-circuit reactance - :math:`cos(\phi)` Power factor - :math:`U_{nom}` Nominal voltage - ================ ============================= + \\Delta u = \\frac{S_{Amax} \cdot ( R_{kV} \cdot cos(\phi) - X_{kV} \cdot sin(\phi) )}{U_{nom}} + + ================= ============================= + Symbol Description + ================= ============================= + :math:`\Delta u` Voltage drop/increase at node + :math:`S_{Amax}` Apparent power + :math:`R_{kV}` Short-circuit resistance + :math:`X_{kV}` Short-circuit reactance + :math:`cos(\phi)` Power factor + :math:`U_{nom}` Nominal voltage + ================= ============================= Parameters ---------- - grid : ding0.core.network.grids.LVGridDing0 + grid : LVGridDing0 Ding0 LV grid object Notes ----- The implementation highly depends on topology of LV grid. This must not change its topology from radial grid with stubs branching from radial - branches. In general, the approach of [VDE-AR]_ is only applicable to grids of + branches. In general, the approach of [#VDE]_ is only applicable to grids of radial topology. We consider the transverse voltage drop/increase by applying the same @@ -363,6 +388,12 @@ def get_critical_voltage_at_nodes(grid): drop/increase at each house connection branch (aka. stub branch or grid connection point) is estimated by superposition based on voltage level in the main branch cable distributor. + + References + ---------- + .. [#VDE] VDE Anwenderrichtlinie: Erzeugungsanlagen am Niederspannungsnetz – + Technische Mindestanforderungen für Anschluss und Parallelbetrieb von + Erzeugungsanlagen am Niederspannungsnetz, 2011 """ v_delta_tolerable_fc = cfg_ding0.get('assumptions', @@ -499,33 +530,34 @@ def voltage_delta_vde(v_nom, s_max, r, x, cos_phi): """ Estimate voltrage drop/increase - The VDE [VDE-AR]_ proposes a simplified method to estimate voltage drop or - increase in radial grids. + The VDE [#]_ proposes a simplified method to estimate voltage drop or + increase in radial grids. Parameters ---------- v_nom : int Nominal voltage - s_max : numeric + s_max : float Apparent power - r : numeric + r : float Short-circuit resistance from node to HV/MV substation (in ohm) - x : numeric + x : float Short-circuit reactance from node to HV/MV substation (in ohm). Must be a signed number indicating (+) inductive reactive consumer (load case) or (-) inductive reactive supplier (generation case) - cos_phi : numeric + cos_phi : float + Returns + ------- + :any:`float` + Voltage drop or increase + References ---------- - .. [VDE-AR] VDE Anwenderrichtlinie: Erzeugungsanlagen am Niederspannungsnetz – + .. [#] VDE Anwenderrichtlinie: Erzeugungsanlagen am Niederspannungsnetz – Technische Mindestanforderungen für Anschluss und Parallelbetrieb von Erzeugungsanlagen am Niederspannungsnetz, 2011 - Returns - ------- - voltage_delta : numeric - Voltage drop or increase """ delta_v = (s_max * ( r * cos_phi + x * math.sin(math.acos(cos_phi)))) / v_nom ** 2 @@ -537,19 +569,20 @@ def get_house_conn_gen_load(graph, node): Get generation capacity/ peak load of neighboring house connected to main branch - Parameter - --------- - graph : networkx.DiGraph + Parameters + ---------- + graph : :networkx:`NetworkX Graph Obj< >` Directed graph node : graph node Node of the main branch of LV grid - Return - ------ - generation_peak_load : list + Returns + ------- + :any:`list` A list containing two items - # peak load of connected house branch - # generation capacity of connected generators + + # peak load of connected house branch + # generation capacity of connected generators """ generation = 0 peak_load = 0 @@ -572,9 +605,9 @@ def get_voltage_delta_branch(grid, tree, node, r_preceeding, x_preceeding): Parameters ---------- - grid : ding0.core.network.grids.LVGridDing0 + grid : LVGridDing0 Ding0 grid object - tree : networkx.DiGraph + tree : :networkx:`NetworkX Graph Obj< >` Tree of grid topology node : graph node Node to determine voltage level at @@ -585,7 +618,7 @@ def get_voltage_delta_branch(grid, tree, node, r_preceeding, x_preceeding): Return ------ - delta_voltage : float + :any:`float` Delta voltage for node """ cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load') @@ -621,11 +654,12 @@ def get_mv_impedance(grid): Parameters ---------- - grid : ding0.core.network.grids.LVGridDing0 + grid : LVGridDing0 Returns ------- - List containing resistance and reactance of MV grid + :any:`list` + List containing resistance and reactance of MV grid """ omega = 2 * math.pi * 50 @@ -647,9 +681,9 @@ def voltage_delta_stub(grid, tree, main_branch_node, stub_node, r_preceeding, Parameters ---------- - grid : ding0.core.network.grids.LVGridDing0 + grid : LVGridDing0 Ding0 grid object - tree : networkx.DiGraph + 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 @@ -662,7 +696,7 @@ def voltage_delta_stub(grid, tree, main_branch_node, stub_node, r_preceeding, Return ------ - delta_voltage : float + :any:`float` Delta voltage for node """ cos_phi_load = cfg_ding0.get('assumptions', 'cos_phi_load') @@ -703,14 +737,16 @@ def get_voltage_at_bus_bar(grid, tree): """ Determine voltage level at bus bar of MV-LV substation - grid : ding0.core.network.grids.LVGridDing0 + Parameters + ---------- + grid : LVGridDing0 Ding0 grid object - tree : networkx.DiGraph + tree : :networkx:`NetworkX Graph Obj< >` Tree of grid topology: Returns ------- - voltage_levels : list + :any:`list` Voltage at bus bar. First item refers to load case, second item refers to voltage in feedin (generation) case """ diff --git a/ding0/flexopt/reinforce_grid.py b/ding0/flexopt/reinforce_grid.py index 751a019a..aebebdd1 100644 --- a/ding0/flexopt/reinforce_grid.py +++ b/ding0/flexopt/reinforce_grid.py @@ -26,14 +26,18 @@ def reinforce_grid(grid, mode): - """ Evaluates grid reinforcement needs and performs measures. This function - is the parent function for all grid reinforcements. + #TODO: finish docstring + """ Evaluates grid reinforcement needs and performs measures + Grid reinforcement according to methods described in [VNSRP]_ supplemented + by [DENA]_. + Parameters ---------- - grid: GridDing0 object - mode: String - kind of grid ('MV' or 'LV') + grid: GridDing0 + Grid instance + mode: str + Choose of: 'MV' or 'LV' Notes ----- @@ -42,8 +46,12 @@ def reinforce_grid(grid, mode): References ---------- - .. [1] dena VNS - .. [2] Ackermann et al. (RP VNS) + .. [DENA] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der + Stromverteilnetze in Deutschland bis 2030.", 2012 + .. [VNSRP] Ackermann, T., Untsch, S., Koch, M., & Rothfuchs, H. (2014). + Verteilnetzstudie Rheinland-Pfalz. Hg. v. Ministerium für + Wirtschaft, Klimaschutz, Energie und Landesplanung Rheinland-Pfalz + (MWKEL). energynautics GmbH. """ diff --git a/ding0/flexopt/reinforce_measures.py b/ding0/flexopt/reinforce_measures.py index 5c91ba9b..b87e1c2e 100644 --- a/ding0/flexopt/reinforce_measures.py +++ b/ding0/flexopt/reinforce_measures.py @@ -34,21 +34,20 @@ def reinforce_branches_current(grid, crit_branches): Parameters ---------- - grid : GridDing0 - Grid identifier. - crit_branches : dict - Dict of critical branches with max. relative overloading. - - Returns - ------- - type - #TODO: Description of return. Change type in the previous line accordingly + grid : GridDing0 + Grid identifier. + crit_branches : dict + Dict of critical branches with max. relative overloading. Notes ----- - The branch type to be installed is determined per branch using the rel. overloading. According to [2]_ - only cables are installed. - + The branch type to be installed is determined per branch using the rel. overloading. According to [#]_ + only cables are installed. + + References + ---------- + .. [#] Ackermann et al. (RP VNS) + See Also -------- ding0.flexopt.check_tech_constraints.check_load : @@ -76,24 +75,29 @@ def reinforce_branches_current(grid, crit_branches): if branch_ctr: logger.info('==> {} branches were reinforced.'.format(str(branch_ctr))) - def reinforce_branches_voltage(grid, crit_branches, grid_level='MV'): + #TODO: finish docstring """ Reinforce MV or LV grid by installing a new branch/line type Parameters ---------- - grid: GridDing0 object - crit_branches: List of BranchDing0 objects - list of critical branches - + grid : GridDing0 + Grid identifier. + crit_branches : :any:`list` of :obj:`int` + List of critical branches. #TODO: check if a list or a dictionary + grid_level : str + Specifying either 'MV' for medium-voltage grid or 'LV' for + low-voltage grid level. + Notes ----- - The branch type to be installed is determined per branch - the next larger cable - available is used. According to [1]_ only cables are installed. - - References - ---------- - .. [1] Ackermann et al. (RP VNS) + The branch type to be installed is determined per branch - the next larger cable available is used. + According to Ackermann only cables are installed. + + See Also + -------- + ding0.flexopt.check_tech_constraints.check_load : + ding0.flexopt.reinforce_measures.reinforce_branches_voltage : """ # load cable data, file_names and parameter @@ -122,7 +126,8 @@ def reinforce_branches_voltage(grid, crit_branches, grid_level='MV'): def extend_substation(grid, critical_stations, grid_level): - """ Reinforce MV or LV substation by exchanging the existing trafo and + """ + Reinforce MV or LV substation by exchanging the existing trafo and installing a parallel one if necessary. First, all available transformers in a `critical_stations` are extended to @@ -131,17 +136,21 @@ def extend_substation(grid, critical_stations, grid_level): Parameters ---------- - grid: GridDing0 - Ding0 grid container - critical_stations : list - List of stations with overloading - grid_level : str - Either "LV" or "MV". Basis to select right equipment. - + grid: GridDing0 + Ding0 grid container + critical_stations : :any:`list` + List of stations with overloading + grid_level : str + Either "LV" or "MV". Basis to select right equipment. + Notes ----- Curently straight forward implemented for LV stations + Returns + ------- + type + #TODO: Description of return. Change type in the previous line accordingly """ load_factor_lv_trans_lc_normal = cfg_ding0.get( 'assumptions', @@ -221,18 +230,17 @@ def extend_substation_voltage(crit_stations, grid_level='LV'): """ Extend substation if voltage issues at the substation occur - Follows a two-step procedure - #. Existing transformers are extended by replacement with large nominal - apparent power - #. New additional transformers added to substation (see ``Notes``) + Follows a two-step procedure: + + i) Existing transformers are extended by replacement with large nominal + apparent power + + ii) New additional transformers added to substation (see 'Notes') Parameters ---------- - critical_stations : list - List of stations with overloading or voltage issues - - Arguments - --------- + crit_stations : :any:`list` + List of stations with overloading or voltage issues. grid_level : str Specifiy grid level: 'MV' or 'LV' @@ -304,14 +312,8 @@ def new_substation(grid): Parameters ---------- - grid : MVGridDing0 - MV Grid identifier. - - Returns - ------- - type - #TODO: Description of return. Change type in the previous line accordingly - + grid : MVGridDing0 + MV Grid identifier. """ @@ -321,9 +323,9 @@ def reinforce_lv_branches_overloading(grid, crit_branches): Parameters ---------- - grid : ding0.core.network.grids.LVGridDing0 + grid : LVGridDing0 Ding0 LV grid object - crit_branches : list + crit_branches : :any:`list` List of critical branches incl. its line loading Notes @@ -333,9 +335,8 @@ def reinforce_lv_branches_overloading(grid, crit_branches): Returns ------- - - unsolved_branches : :obj:`list` - List of braches no suitable cable could be found + :any:`list` + unsolved_branches : List of braches no suitable cable could be found """ unsolved_branches = [] @@ -379,9 +380,9 @@ def extend_trafo_power(extendable_trafos, trafo_params): Parameters ---------- - extendable_trafos : list + extendable_trafos : :any:`list` Trafos with rated power below maximum size available trafo - trafo_params : pandas.DataFrame + trafo_params : :pandas:`pandas.DataFrame` Transformer parameters """ trafo = extendable_trafos[0] diff --git a/ding0/flexopt/reinforce_measures_dena.py b/ding0/flexopt/reinforce_measures_dena.py index cf9a982f..bb969530 100644 --- a/ding0/flexopt/reinforce_measures_dena.py +++ b/ding0/flexopt/reinforce_measures_dena.py @@ -36,6 +36,7 @@ def parallel_branch(grid, node_target): def split_ring(grid): """ Reinforce MV grid by splitting a critical ring into two new rings according to dena + Parameters ---------- grid : MVGridDing0 @@ -77,4 +78,4 @@ def new_substation(grid): ------- type #TODO: Description of return. Change type in the previous line accordingly - """ \ No newline at end of file + """ diff --git a/ding0/grid/lv_grid/build_grid.py b/ding0/grid/lv_grid/build_grid.py index 7a245e29..7007ea4b 100644 --- a/ding0/grid/lv_grid/build_grid.py +++ b/ding0/grid/lv_grid/build_grid.py @@ -25,7 +25,7 @@ def select_transformers(grid, s_max=None): - """ Selects MV-LV transformers for the MV-LV substation. + """Selects LV transformer according to peak load of LV grid district. The transformers are chosen according to max. of load case and feedin-case considering load factors and power factor. @@ -40,7 +40,7 @@ def select_transformers(grid, s_max=None): Parameters ---------- - grid: ding0.core.network.LVGridDing0 + grid: LVGridDing0 LV grid data Arguments @@ -70,10 +70,17 @@ def select_transformers(grid, s_max=None): Returns ------- - transformer: DataFrame + :pandas:`pandas.DataFrame` Parameters of chosen Transformer - transformer_cnt: int + :obj:`int` Count of transformers + + Notes + ----- + The LV transformer with the next higher available nominal apparent power is + chosen. Therefore, a max. allowed transformer loading of 100% is implicitly + assumed. If the peak load exceeds the max. power of a single available + transformer, use multiple trafos. """ load_factor_lv_trans_lc_normal = cfg_ding0.get('assumptions', @@ -142,12 +149,11 @@ def select_transformers(grid, s_max=None): def transformer(grid): - """ - Choose transformer and add to grid's station + """ Choose transformer and add to grid's station Parameters ---------- - grid: ding0.core.network.LVGridDing0 + grid: LVGridDing0 LV grid data """ @@ -169,8 +175,7 @@ def transformer(grid): def select_grid_model_ria(lvgd, sector): - """ - Select a typified grid for retail/industrial and agricultural + """Select a typified grid for retail/industrial and agricultural Parameters ---------- @@ -182,7 +187,7 @@ def select_grid_model_ria(lvgd, sector): Returns ------- - grid_model : dict + :obj:`dict` Parameters that describe branch lines of a sector """ @@ -271,16 +276,17 @@ def select_grid_model_ria(lvgd, sector): def grid_model_params_ria(lvgd): - """ - Determine grid model parameters for LV grids of sectors + """Determine grid model parameters for LV grids of sectors retail/industrial and agricultural - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + Parameters + ---------- + lvgd : LVGridDistrictDing0 Low-voltage grid district object Returns ------- - model_params_ria : dict + :obj:`dict` Structural description of (parts of) LV grid topology """ @@ -306,8 +312,7 @@ def grid_model_params_ria(lvgd): def build_lv_graph_ria(lvgd, grid_model_params): - """ - Build graph for LV grid of sectors retail/industrial and agricultural + """Build graph for LV grid of sectors retail/industrial and agricultural Based on structural description of LV grid topology for sectors retail/industrial and agricultural (RIA) branches for these sectors are @@ -333,20 +338,31 @@ def build_lv_graph_ria(lvgd, grid_model_params): Parameters ---------- - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + lvgd : LVGridDistrictDing0 Low-voltage grid district object grid_model_params : dict - Dict of structural information of sectoral LV grid branch + Dict of structural information of sectoral LV grid branchwith particular + structure, e.g.:: + + grid_model_params = { + 'agricultural': { + 'max_loads_per_branch': 2 + 'single_peak_load': 140, + 'full_branches': 2, + 'remaining_loads': 1, + 'load_distance': 800/3, + 'load_distance_remaining': 400 + } + } Notes ----- We assume a distance from the load to the branch it is connected to of - 30 m. This assumption is defined in the config files + 30 m. This assumption is defined in the config files. """ def lv_graph_attach_branch(): - """ - Attach a single branch including its equipment (cable dist, loads + """Attach a single branch including its equipment (cable dist, loads and line segments) to graph of `lv_grid` """ @@ -506,13 +522,12 @@ def lv_graph_attach_branch(): def build_ret_ind_agr_branches(lvgd): - """ - Determine topology of LV grid for retail/industrial and agricultural sector + """Determine topology of LV grid for retail/industrial and agricultural sector and create representative graph of the grid Parameters ---------- - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + lvgd : LVGridDistrictDing0 Low-voltage grid district object """ @@ -524,19 +539,18 @@ def build_ret_ind_agr_branches(lvgd): def select_grid_model_residential(lvgd): - """ - Selects typified model grid based on population + """Selects typified model grid based on population Parameters ---------- - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + lvgd : LVGridDistrictDing0 Low-voltage grid district object Returns ------- - selected_strings_df: DataFrame + :pandas:`pandas.DataFrame` Selected string of typified model grid - transformer: Dataframe + :pandas:`pandas.DataFrame` Parameters of chosen Transformer Notes @@ -582,14 +596,13 @@ def select_grid_model_residential(lvgd): def build_lv_graph_residential(lvgd, selected_string_df): - """ - Builds nxGraph based on the LV grid model + """Builds nxGraph based on the LV grid model - Parameter - --------- - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + Parameters + ---------- + lvgd : LVGridDistrictDing0 Low-voltage grid district object - selected_string_df: Dataframe + selected_string_df: :pandas:`pandas.DataFrame` Table of strings of the selected grid model Notes @@ -598,11 +611,9 @@ def build_lv_graph_residential(lvgd, selected_string_df): are explained here * `count house branch`: number of houses connected to a string - * `distance house branch`: distance on a string between two house - branches + * `distance house branch`: distance on a string between two house branches * `string length`: total length of a string - * `length house branch A|B`: cable from string to connection point of a - house + * `length house branch A|B`: cable from string to connection point of a house A|B in general brings some variation in to the typified model grid and refer to different length of house branches and different cable types @@ -738,13 +749,12 @@ def build_lv_graph_residential(lvgd, selected_string_df): def build_residential_branches(lvgd): - """ - Based on population and identified peak load data, the according grid + """Based on population and identified peak load data, the according grid topology for residential sector is determined and attached to the grid graph Parameters ---------- - lvgd : ding0.core.structure.regions.LVGridDistrictDing0 + lvgd : LVGridDistrictDing0 Low-voltage grid district object """ @@ -778,4 +788,4 @@ def build_residential_branches(lvgd): logger.info( '{} has got no residential load. ' 'No grid is created.'.format( - repr(lvgd))) \ No newline at end of file + repr(lvgd))) diff --git a/ding0/grid/lv_grid/lv_connect.py b/ding0/grid/lv_grid/lv_connect.py index 211fe649..2cb720c0 100644 --- a/ding0/grid/lv_grid/lv_connect.py +++ b/ding0/grid/lv_grid/lv_connect.py @@ -25,15 +25,22 @@ def lv_connect_generators(lv_grid_district, graph, debug=False): - """ Connect LV generators to LV grid - - Args: - lv_grid_district: LVGridDistrictDing0 object for which the connection process has to be done - graph: NetworkX graph object with nodes - debug: If True, information is printed during process - Returns: - graph: NetworkX graph object with nodes and newly created branches + """ Connect LV generators to LV grid + + Args + ---- + lv_grid_district: LVGridDistrictDing0 + LVGridDistrictDing0 object for which the connection process has to be done + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + debug: bool, defaults to False + If True, information is printed during process + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches """ cable_lf = cfg_ding0.get('assumptions', @@ -136,4 +143,4 @@ def lv_connect_generators(lv_grid_district, graph, debug=False): graph.add_edge(generator, lv_conn_target, branch=branch) - return graph \ No newline at end of file + return graph diff --git a/ding0/grid/mv_grid/models/models.py b/ding0/grid/mv_grid/models/models.py index 74252a19..123b61d5 100644 --- a/ding0/grid/mv_grid/models/models.py +++ b/ding0/grid/mv_grid/models/models.py @@ -29,10 +29,14 @@ class Route(object): - """ - CVRP route, consists of consecutive nodes - ----------------------------------------- - bla + # TODO: check docstring + """CVRP route, consists of consecutive nodes + + Parameters + ---------- + cvrp_problem : type + Descr + """ def __init__(self, cvrp_problem): @@ -50,9 +54,15 @@ def __init__(self, cvrp_problem): def clone(self): """Returns a deep copy of self - Clones: - allocation - nodes + Function clones: + + * allocation + * nodes + + Returns + ------- + type + Deep copy of self """ new_route = self.__class__(self._problem) @@ -64,16 +74,34 @@ def clone(self): return new_route def demand(self): - """Returns the current route demand""" + """Returns the current route demand + + Returns + ------- + type + Current route demand. + """ return self._demand def nodes(self): - """Returns a generator for iterating over nodes""" + """Returns a generator for iterating over nodes + + Yields + ------ + type + Generator for iterating over nodes + """ for node in self._nodes: yield node def length(self): - """Returns the total route length (cost)""" + """Returns the route length (cost) + + Returns + ------- + int + Route length (cost). + """ cost = 0 depot = self._problem.depot() @@ -100,7 +128,21 @@ def length_from_nodelist(self, nodelist): return cost def can_allocate(self, nodes, pos=None): - """Returns True if this route can allocate nodes in `nodes` list""" + # TODO: check docstring + """Returns True if this route can allocate nodes in `nodes` list + + Parameters + ---------- + nodes : type + Desc + pos : type, defaults to None + Desc + + Returns + ------- + bool + True if this route can allocate nodes in `nodes` list + """ # clone route and nodes new_route = self.clone() @@ -116,7 +158,17 @@ def can_allocate(self, nodes, pos=None): return False def allocate(self, nodes, append=True): - """Allocates all nodes from `nodes` list in this route""" + # TODO: check docstring + """Allocates all nodes from `nodes` list in this route + + Parameters + ---------- + nodes : type + Desc + append : bool, defaults to True + Desc + + """ nodes_demand = 0 for node in [node for node in nodes]: @@ -133,7 +185,14 @@ def allocate(self, nodes, append=True): self._demand = self._demand + nodes_demand def deallocate(self, nodes): - """Deallocates all nodes from `nodes` list from this route""" + # TODO: check docstring + """Deallocates all nodes from `nodes` list from this route + + Parameters + ---------- + nodes : type + Desc + """ nodes_demand = 0 for node in nodes: @@ -147,7 +206,17 @@ def deallocate(self, nodes): raise Exception('Trying to deallocate more than previously allocated') def insert(self, nodes, pos): - """Inserts all nodes from `nodes` list into this route at position `pos`""" + # TODO: check docstring + """Inserts all nodes from `nodes` list into this route at position `pos` + + Parameters + ---------- + nodes : type + Desc + pos : type + Desc + + """ node_list = [] nodes_demand = 0 @@ -162,17 +231,49 @@ def insert(self, nodes, pos): self._demand += nodes_demand def is_interior(self, node): - """Returns True if node is interior to the route, i.e., not adjascent to depot""" + # TODO: check docstring + """Returns True if node is interior to the route, i.e., not adjascent to depot + + Parameters + ---------- + nodes : type + Desc + + Returns + ------- + bool + True if node is interior to the route + + """ return self._nodes.index(node) != 0 and self._nodes.index(node) != len(self._nodes) - 1 def last(self, node): - """Returns True if node is the last node in the route""" + # TODO: check docstring + """Returns True if node is the last node in the route + + Parameters + ---------- + nodes : type + Desc + + Returns + ------- + bool + True if node is the last node in the route + """ return self._nodes.index(node) == len(self._nodes) - 1 def calc_circuit_breaker_position(self, debug=False): """ Calculates the optimal position of a circuit breaker on route. - - Returns: + + Parameters + ---------- + debug: bool, defaults to False + If True, prints process information. + + Returns + ------- + int position of circuit breaker on route (index of last node on 1st half-ring preceding the circuit breaker) Notes @@ -188,6 +289,10 @@ def calc_circuit_breaker_position(self, debug=False): References ---------- + + See Also + -------- + ding0.grid.mv_grid.tools.set_circuit_breakers """ # TODO: add references (Tao) @@ -222,29 +327,28 @@ def calc_circuit_breaker_position(self, debug=False): def tech_constraints_satisfied(self): """ Check route validity according to technical constraints (voltage and current rating) - Constraints: - current rating of cable/line - voltage stability at all nodes + It considers constraints as + + * current rating of cable/line + * voltage stability at all nodes - Notes: + Notes + ----- The validation is done for every tested MV grid configuration during CVRP algorithm. The current rating is - checked using load factors from [1]_. Due to the high amount of steps the voltage rating cannot be checked + checked using load factors from [#]_. Due to the high amount of steps the voltage rating cannot be checked using load flow calculation. Therefore we use a simple method which determines the voltage change between - two consecutive nodes according to [2]_. - Furthermore it is checked: - * if new route has got more nodes than allowed (typ. 2*10 according to [3]_) - * if total lengths of half-rings exceed max. allowed distance of max_half_ring_length - (typ. 30km according to [4]_). We choose 28km as default value to take the max branch stub length - (cf. load_area_sat_string_length_threshold) of 2km into account. - - References: + two consecutive nodes according to [#]_. + Furthermore it is checked if new route has got more nodes than allowed (typ. 2*10 according to [#]_). + + References + ---------- - .. [1] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der + .. [#] Deutsche Energie-Agentur GmbH (dena), "dena-Verteilnetzstudie. Ausbau- und Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030.", 2012 - .. [2] M. Sakulin, W. Hipp, "Netzaspekte von dezentralen Erzeugungseinheiten, + .. [#] M. Sakulin, W. Hipp, "Netzaspekte von dezentralen Erzeugungseinheiten, Studie im Auftrag der E-Control GmbH", TU Graz, 2004 - .. [3] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 - .. [4] FGH e.V.: "Technischer Bericht 302: Ein Werkzeug zur Optimierung der Störungsbeseitigung + .. [#] Klaus Heuck et al., "Elektrische Energieversorgung", Vieweg+Teubner, Wiesbaden, 2007 + .. [#] FGH e.V.: "Technischer Bericht 302: Ein Werkzeug zur Optimierung der Störungsbeseitigung für Planung und Betrieb von Mittelspannungsnetzen", Tech. rep., 2008 """ @@ -283,7 +387,7 @@ def tech_constraints_satisfied(self): position = self.calc_circuit_breaker_position() # step 2: calc required values for checking current & voltage - # -> get nodes of half-rings + # get nodes of half-rings nodes_hring1 = [self._problem._depot] + self._nodes[0:position] nodes_hring2 = list(reversed(self._nodes[position:len(self._nodes)] + [self._problem._depot])) # get all nodes of full ring for both directions @@ -376,10 +480,15 @@ def __repr__(self): class Node(object): - """ - CVRP node (MV transformer/customer) - ----------------------------------- - bla + # TODO: check docstring + """CVRP node (MV transformer/customer) + + Parameters + ---------- + name: + Node name + demand: + Node demand """ def __init__(self, name, demand): @@ -396,11 +505,18 @@ def __init__(self, name, demand): self._allocation = None def clone(self): + # TODO: check docstring """Returns a deep copy of self - - Clones: - allocation - nodes + + Function clones: + + * allocation + * nodes + + Returns + ------- + type + Deep copy of self """ new_node = self.__class__(self._name, self._demand) @@ -408,15 +524,36 @@ def clone(self): return new_node def name(self): - """Returns node name""" + # TODO: check docstring + """Returns node name + + Returns + ------- + str + Node's name + """ return self._name def demand(self): - """Returns the node demand""" + # TODO: check docstring + """Returns the node demand + + Returns + ------- + float + Node's demand + """ return self._demand def route_allocation(self): - """Returns the route which node is allocated""" + # TODO: check docstring + """Returns the route which node is allocated + + Returns + ------- + type + Node's route + """ return self._allocation def __str__(self): @@ -436,11 +573,15 @@ def __hash__(self): class Graph(object): - """Class for modelling a CVRP problem data""" - """ - CVRP graph + # TODO: check docstring + """Class for modelling a CVRP problem data + + Parameters ---------- - bla + data: type + TSPLIB parsed data + + """ def __init__(self, data): @@ -478,23 +619,60 @@ def __init__(self, data): raise Exception('Depot not found') def nodes(self): - """Returns a generator for iterating over nodes""" + # TODO: check docstring + """Returns a generator for iterating over nodes. + + Yields + ------ + type + Generator for iterating over nodes. + + """ for i in sorted(self._nodes): yield self._nodes[i] def edges(self): - """Returns a generator for iterating over edges""" + # TODO: check docstring + """Returns a generator for iterating over edges + + Yields + ------ + type + Generator for iterating over edges. + + """ for i in sorted(self._matrix.keys(), key=lambda x:x.name()): for j in sorted(self._matrix[i].keys(), key=lambda x:x.name()): if i != j: yield (i, j) def depot(self): - """Returns the depot node""" + # TODO: check docstring + """Returns the depot node. + + Returns + ------- + type + Depot node + """ return self._depot def distance(self, i, j): - """Returns the distance between node i and node j""" + # TODO: check docstring + """Returns the distance between node i and node j + + Parameters + ---------- + i : type + Descr + j : type + Desc + + Returns + ------- + float + Distance between node i and node j. + """ a, b = i, j diff --git a/ding0/grid/mv_grid/mv_connect.py b/ding0/grid/mv_grid/mv_connect.py index 241b7b73..b057a325 100644 --- a/ding0/grid/mv_grid/mv_connect.py +++ b/ding0/grid/mv_grid/mv_connect.py @@ -36,23 +36,40 @@ def find_nearest_conn_objects(node_shp, branches, proj, conn_dist_weight, debug, branches_only=False): - """ Searches all `branches` for the nearest possible connection object per branch (picks out 1 object out of 3 - possible objects: 2 branch-adjacent stations and 1 potentially created cable distributor on the line - (perpendicular projection)). The resulting stack (list) is sorted ascending by distance from node. - - Args: - node_shp: Shapely Point object of node - branches: BranchDing0 objects of MV region - proj: pyproj projection object: nodes' CRS to equidistant CRS (e.g. WGS84 -> ETRS) - conn_dist_weight: length weighting to prefer stations instead of direct line connection, - see mv_connect_satellites() for details. - debug: If True, information is printed during process - branches_only: If True, only branch objects are considered as connection objects - - Returns: - conn_objects_min_stack: List of connection objects (each object is represented by dict with Ding0 object, - shapely object and distance to node. - + """Searches all `branches` for the nearest possible connection object per branch. + + Picks out 1 object out of 3 possible objects: + + * 2 branch-adjacent stations and + * 1 potentially created cable distributor on the line (perpendicular projection)). + + The resulting stack (list) is sorted ascending by distance from node. + + Args + ---- + node_shp: :shapely:`Shapely Point object` + Shapely Point object of node + branches: BranchDing0 + BranchDing0 objects of MV region + proj: :pyproj:`pyproj Proj object< >` + nodes' CRS to equidistant CRS (e.g. WGS84 -> ETRS) + conn_dist_weight: float + length weighting to prefer stations instead of direct line connection. + debug: bool + If True, information is printed during process + branches_only: bool, defaults to False + If True, only branch objects are considered as connection objects + + Returns + ------- + :any:`list` + List of connection objects. + Each object is represented by dict with Ding0 object, + shapely object, and distance to node. + + See Also + -------- + mv_connect_satellites : for details on `conn_dist_weight` param """ # threshold which is used to determine if 2 objects are on the same position (see below for details on usage) @@ -153,19 +170,32 @@ def find_connection_point(node, node_shp, graph, proj, conn_objects_min_stack, c """ Goes through the possible target connection objects in `conn_objects_min_stack` (from nearest to most far object) and tries to connect `node` to one of them. - Args: - node: origin node - Ding0 object (e.g. LVLoadAreaCentreDing0) - node_shp: Shapely Point object of node - graph: NetworkX graph object with nodes - proj: pyproj projection object: equidistant CRS to conformal CRS (e.g. ETRS -> WGS84) - conn_objects_min_stack: List of connection objects (each object is represented by dict with Ding0 object, - shapely object and distance to node), sorted ascending by distance. - conn_dist_ring_mod: Max. distance when nodes are included into route instead of creating a new line, - see mv_connect() for details. - debug: If True, information is printed during process - - Returns: - nothing + Function searches from nearest to most far object. + + Args + ---- + node: LVLoadAreaCentreDing0, i.e. + Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0) + node_shp: :shapely:`Shapely Point object` + Shapely Point object of node + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + proj: :pyproj:`pyproj Proj object< >` + equidistant CRS to conformal CRS (e.g. ETRS -> WGS84) + conn_objects_min_stack: list + List of connection objects. + + Each object is represented by dict with Ding0 object, shapely object, + and distance to node, sorted ascending by distance. + conn_dist_ring_mod: type + Max. distance when nodes are included into route instead of creating a + new line. + debug: bool + If True, information is printed during process + + See Also + -------- + ding0.grid.mv_grid.mv_connect : for details on the `conn_dist_ring_mod` parameter. """ node_connected = False @@ -309,22 +339,39 @@ def find_connection_point(node, node_shp, graph, proj, conn_objects_min_stack, c def connect_node(node, node_shp, mv_grid, target_obj, proj, graph, conn_dist_ring_mod, debug): - """ Connects `node` to `target_obj` - - Args: - node: origin node - Ding0 object (e.g. LVLoadAreaCentreDing0) - node_shp: Shapely Point object of origin node - target_obj: object that node shall be connected to - proj: pyproj projection object: equidistant CRS to conformal CRS (e.g. ETRS -> WGS84) - graph: NetworkX graph object with nodes and newly created branches - conn_dist_ring_mod: Max. distance when nodes are included into route instead of creating a new line, - see mv_connect() for details. - debug: If True, information is printed during process - - Returns: - target_obj_result: object that node was connected to (instance of LVLoadAreaCentreDing0 or - MVCableDistributorDing0). If node is included into line instead of creating a new line (see arg - `conn_dist_ring_mod`), `target_obj_result` is None. + """ Connects `node` to `target_obj`. + + Args + ---- + node: LVLoadAreaCentreDing0, i.e. + Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0) + node_shp: :shapely:`Shapely Point object` + Shapely Point object of origin node + target_obj: type + object that node shall be connected to + proj: :pyproj:`pyproj Proj object< >` + equidistant CRS to conformal CRS (e.g. ETRS -> WGS84) + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches + conn_dist_ring_mod: float + Max. distance when nodes are included into route instead of creating a + new line. + debug: bool + If True, information is printed during process. + + Returns + ------- + :obj:`LVLoadAreaCentreDing0` + object that node was connected to. + + (instance of :obj:`LVLoadAreaCentreDing0` or :obj:`MVCableDistributorDing0`. + + If node is included into line instead of creating a new line (see arg + `conn_dist_ring_mod`), `target_obj_result` is None. + + See Also + -------- + ding0.grid.mv_grid.mv_connect : for details on the `conn_dist_ring_mod` parameter. """ target_obj_result = None @@ -496,14 +543,17 @@ def connect_node(node, node_shp, mv_grid, target_obj, proj, graph, conn_dist_rin def disconnect_node(node, target_obj_result, graph, debug): """ Disconnects `node` from `target_obj` - Args: - node: node - Ding0 object (e.g. LVLoadAreaCentreDing0) - target_obj_result: - graph: NetworkX graph object with nodes and newly created branches - debug: If True, information is printed during process + Args + ---- + node: LVLoadAreaCentreDing0, i.e. + Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0) + target_obj_result: LVLoadAreaCentreDing0, i.e. + Origin node - Ding0 graph object (e.g. LVLoadAreaCentreDing0) + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches + debug: bool + If True, information is printed during process - Returns: - nothing """ # backup kind and type of branch @@ -532,14 +582,16 @@ def disconnect_node(node, target_obj_result, graph, debug): def parametrize_lines(mv_grid): """ Set unparametrized branches to default branch type - Args: - mv_grid: MVGridDing0 object - - Returns: - nothing - - Notes: - During the connection process of satellites, new branches are created - these have to be parametrized. + + Args + ---- + mv_grid: MVGridDing0 + MV grid instance + + Notes + ----- + During the connection process of satellites, new branches are created - + these have to be parametrized. """ for branch in mv_grid.graph_edges(): @@ -552,16 +604,39 @@ def parametrize_lines(mv_grid): def mv_connect_satellites(mv_grid, graph, mode='normal', debug=False): """ Connect satellites (small Load Areas) to MV grid - Args: - mv_grid: MVGridDing0 object - graph: NetworkX graph object with nodes - mode: 'normal' (step 1, do connection considering restrictions like max. string length, max peak load per - string) or - 'isolated' (step 2, connect to closest line/station on a MV ring that have not been connected in step 1) - debug: If True, information is printed during process - - Returns: - graph: NetworkX graph object with nodes and newly created branches + Args + ---- + mv_grid: MVGridDing0 + MV grid instance + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + mode: str, defaults to 'normal' + Specify mode how satellite `LVLoadAreaCentreDing0` are connected to the + grid. Mode normal (default) considers for restrictions like max. + string length, max peak load per string. + The mode 'isolated' disregards any connection restrictions and connects + the node `LVLoadAreaCentreDing0` to the next connection point. + + debug: bool, defaults to False + If True, information is printed during process + + Notes + ----- + conn_dist_weight: The satellites can be connected to line (new terminal is + created) or to one station where the line ends, depending on the distance + from satellite to the objects. This threshold is a length weighting to + prefer stations instead of direct line connection to respect grid planning + principles. + + Example: The distance from satellite to line is 1km, to station1 1.2km, to + station2 2km. With conn_dist_threshold=0.75, the 'virtual' distance to + station1 would be 1.2km * 0.75 = 0.9km, so this conn. point would be + preferred. + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches """ # conn_dist_weight: The satellites can be connected to line (new terminal is created) or to one station where the @@ -650,13 +725,19 @@ def mv_connect_satellites(mv_grid, graph, mode='normal', debug=False): def mv_connect_stations(mv_grid_district, graph, debug=False): """ Connect LV stations to MV grid - Args: - mv_grid_district: MVGridDistrictDing0 object for which the connection process has to be done - graph: NetworkX graph object with nodes - debug: If True, information is printed during process - - Returns: - graph: NetworkX graph object with nodes and newly created branches + Args + ---- + mv_grid_district: MVGridDistrictDing0 + MVGridDistrictDing0 object for which the connection process has to be done + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + debug: bool, defaults to False + If True, information is printed during process + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches """ # WGS84 (conformal) to ETRS (equidistant) projection @@ -818,15 +899,22 @@ def mv_connect_stations(mv_grid_district, graph, debug=False): def mv_connect_generators(mv_grid_district, graph, debug=False): - """ Connect MV generators to MV grid - - Args: - mv_grid_district: MVGridDistrictDing0 object for which the connection process has to be done - graph: NetworkX graph object with nodes - debug: If True, information is printed during process - - Returns: - graph: NetworkX graph object with nodes and newly created branches + """Connect MV generators to MV grid + + Args + ---- + mv_grid_district: MVGridDistrictDing0 + MVGridDistrictDing0 object for which the connection process has to be + done + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + debug: bool, defaults to False + If True, information is printed during process. + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and newly created branches """ generator_buffer_radius = cfg_ding0.get('mv_connect', 'generator_buffer_radius') diff --git a/ding0/grid/mv_grid/mv_routing.py b/ding0/grid/mv_grid/mv_routing.py index 21f49bb9..381818ee 100644 --- a/ding0/grid/mv_grid/mv_routing.py +++ b/ding0/grid/mv_grid/mv_routing.py @@ -33,11 +33,20 @@ def ding0_graph_to_routing_specs(graph): """ Build data dictionary from graph nodes for routing (translation) - Args: - graph: NetworkX graph object with nodes - - Returns: - specs: Data dictionary for routing, See class `Graph()` in routing's model definition for keys + Args + ---- + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + + Returns + ------- + :obj:`dict` + Data dictionary for routing. + + See Also + -------- + ding0.grid.mv_grid.models.models.Graph : for keys of return dict + """ # get power factor for loads @@ -93,12 +102,17 @@ def ding0_graph_to_routing_specs(graph): def routing_solution_to_ding0_graph(graph, solution): """ Insert `solution` from routing into `graph` - Args: - graph: NetworkX graph object with nodes - solution: Instance of `BaseSolution` or child class (e.g. `LocalSearchSolution`) (=solution from routing) - - Returns: - graph: NetworkX graph object with nodes and edges + Args + ---- + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + solution: BaseSolution + Instance of `BaseSolution` or child class (e.g. `LocalSearchSolution`) (=solution from routing) + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and edges """ # TODO: Bisherige Herangehensweise (diese Funktion): Branches werden nach Routing erstellt um die Funktionsfähigkeit # TODO: des Routing-Tools auch für die TestCases zu erhalten. Es wird ggf. notwendig, diese direkt im Routing vorzunehmen. @@ -220,15 +234,28 @@ def routing_solution_to_ding0_graph(graph, solution): def solve(graph, debug=False, anim=None): - """ Do MV routing for given nodes in `graph`. Translate data from node objects to appropriate format before. - - Args: - graph: NetworkX graph object with nodes - debug: If True, information is printed while routing - anim: AnimationDing0 object (refer to class 'AnimationDing0()' for a more detailed description) - - Returns: - graph: NetworkX graph object with nodes and edges + # TODO: check docstring + """ Do MV routing for given nodes in `graph`. + + Translate data from node objects to appropriate format before. + + Args + ---- + graph: :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes + debug: bool, defaults to False + If True, information is printed while routing + anim: AnimationDing0 + AnimationDing0 object + + Returns + ------- + :networkx:`NetworkX Graph Obj< >` + NetworkX graph object with nodes and edges + + See Also + -------- + ding0.tools.animation.AnimationDing0 : for a more detailed description on anim parameter. """ # TODO: Implement debug mode (pass to solver) to get more information while routing (print routes, draw network, ..) diff --git a/ding0/grid/mv_grid/solvers/base.py b/ding0/grid/mv_grid/solvers/base.py index 09b36ea8..62ff9bcc 100644 --- a/ding0/grid/mv_grid/solvers/base.py +++ b/ding0/grid/mv_grid/solvers/base.py @@ -24,23 +24,44 @@ class BaseSolution(object): - """Base abstract class for a CVRP solution""" + """Base abstract class for a CVRP solution + + Parameters + ---------- + cvrp_problem : type + Desc Graph instance? + """ def __init__(self, cvrp_problem): """Initialize class - - Parameters: - cvrp_problem: Graph instance """ self._problem = cvrp_problem self._allocated = 0 def get_pair(self, pair): + """get pair description + + Parameters + ---------- + pair : :any:`list` of nodes + Descr + + Returns + ------- + type + Descr + """ i, j = pair return (self._nodes[i.name()], self._nodes[j.name()]) def is_complete(self): - """Returns True if this is a complete solution, i.e, all nodes are allocated""" + """Returns True if this is a complete solution, i.e, all nodes are allocated + + Returns + ------- + bool + True if all nodes are llocated. + """ return all( [node.route_allocation() is not None for node in list(self._nodes.values()) if node != self._problem.depot()] ) @@ -48,10 +69,16 @@ def is_complete(self): def clone(self): """Returns a deep copy of self - Clones: - routes - allocation - nodes + Function clones: + + * route + * allocation + * nodes + + Returns + ------- + type + Deep copy of self """ new_solution = self.__class__(self._problem, len(self._routes)) @@ -67,12 +94,24 @@ def clone(self): return new_solution def routes(self): - """Returns a generator for iterating over solution routes""" + """Returns a generator for iterating over solution routes + + Yields + ------ + type + Generator for iterating over solution routes. + """ for r in self._routes: yield r def length(self): - """Returns the solution length (or cost)""" + """Returns the solution length (or cost) + + Returns + ------- + float + Solution length (or cost). + """ length = 0 for r in self._routes: length = length + r.length() @@ -80,24 +119,56 @@ def length(self): return length def can_process(self, pairs): + # TODO: check docstring """Returns True if this solution can process `pairs` - Parameters: - pairs: List of pairs + Parameters + ---------- + pairs: :any:`list` of pairs + List of pairs + + Returns + ------- + bool + True if this solution can process `pairs` + + Todo + ---- + Not yet implemented """ raise NotImplementedError() def process(self, node_or_pair): + # TODO: check docstring """Processes a node or a pair of nodes into the current solution MUST CREATE A NEW INSTANCE, NOT CHANGE ANY INSTANCE ATTRIBUTES - - Returns a new instance (deep copy) of self object + + Parameters + ---------- + node_or_pair: type + Desc + + Returns + ------- + type + A new instance (deep copy) of self object + + Todo + ---- + Not yet implemented """ raise NotImplementedError() def draw_network(self, anim): - """draws solution's graph using networkx""" + """Draws solution's graph using networkx + + Parameters + ---------- + AnimationDing0 + AnimationDing0 object + + """ g = nx.Graph() ntemp = [] @@ -140,13 +211,21 @@ class BaseSolver(object): def solve(self, data, vehicles, timeout): """Must solves the CVRP problem - Parameters: - data: Graph instance - vehicles: Vehicles number - timeout: max processing time in seconds - Must return BEFORE timeout Must returns a solution (BaseSolution class derived) + + Parameters + ---------- + data: type + Graph instance + vehicles: int + Vehicles number + timeout: int + max processing time in seconds + + Todo + ---- + Not yet implemented """ raise NotImplementedError() diff --git a/ding0/grid/mv_grid/solvers/local_search.py b/ding0/grid/mv_grid/solvers/local_search.py index b8f3d0df..ac73e1ba 100644 --- a/ding0/grid/mv_grid/solvers/local_search.py +++ b/ding0/grid/mv_grid/solvers/local_search.py @@ -33,7 +33,15 @@ class LocalSearchSolution(BaseSolution): - """Solution class for Local Search metaheuristic""" + """Solution class for Local Search metaheuristic + + Parameters + ---------- + cvrp_problem : type + Descr + solution : BaseSolution + Descr + """ def __init__(self, cvrp_problem, solution): super(LocalSearchSolution, self).__init__(cvrp_problem) @@ -44,10 +52,16 @@ def __init__(self, cvrp_problem, solution): def clone(self): """Returns a deep copy of self - Clones: - routes - allocation - nodes + Function clones: + + * route + * allocation + * nodes + + Returns + ------- + LocalSearchSolution + Deep copy of self """ new_solution = self.__class__(self._problem, self._vehicles) @@ -68,64 +82,84 @@ def clone(self): class LocalSearchSolver(BaseSolver): """ Improve initial savings solution using local search - - Graph operators: - Or-Opt (intra-route) - Relocate (inter-route) - Exchange (inter-route) - - ToDo: - ----- - * Cross (inter-route) - to remove crossing edges between two routes - References - ---------- - .. [1] W. Wenger, "Multikriterielle Tourenplanung", Dissertation, 2009 - .. [2] M. Kämpf, "Probleme der Tourenbildung", Chemnitzer Informatik-Berichte, 2006 - .. [3] O. Bräysy, M. Gendreau, "Vehicle Routing Problem with Time Windows, - Part I: Route Construction and Local Search Algorithms", - Transportation Science, vol. 39, Issue 1, pp. 104-118, 2005 - .. [4] C. Boomgaarden, "Dynamische Tourenplanung und -steuerung", - Dissertation, 2007 + The implementation of the local searach algorithm founds on the following + publications [#]_, [#]_, [#]_, [#]_ + + Graph operators:: + + Or-Opt (intra-route) + Relocate (inter-route) + Exchange (inter-route) + + Todo + ---- + * Cross (inter-route) - to remove crossing edges between two routes + + References + ---------- + .. [#] W. Wenger, "Multikriterielle Tourenplanung", Dissertation, 2009 + .. [#] M. Kämpf, "Probleme der Tourenbildung", Chemnitzer Informatik-Berichte, 2006 + .. [#] O. Bräysy, M. Gendreau, "Vehicle Routing Problem with Time Windows, + Part I: Route Construction and Local Search Algorithms", + Transportation Science, vol. 39, Issue 1, pp. 104-118, 2005 + .. [#] C. Boomgaarden, "Dynamische Tourenplanung und -steuerung", + Dissertation, 2007 """ # TODO: Cross (inter-route), see above def operator_oropt(self, graph, solution, op_diff_round_digits, anim=None): - """applies Or-Opt intra-route operator to solution + # 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. - Returns a solution (LocalSearchSolution class)) - - Args: - op_diff_round_digits: 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) - - 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. + 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 + * 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 @@ -192,24 +226,40 @@ def operator_relocate(self, graph, solution, op_diff_round_digits, anim): position with max. saving and procedure starts over again with newly created graph as input. Stops when no improvement is found. - Returns a solution (LocalSearchSolution class)) - - Args: - op_diff_round_digits: 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) + 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 + ----- (Inner) Loop variables: - i: node that is checked for possible moves (position in the route `tour`, not node name) - j: node that precedes the insert position in target route (position in the route `target_tour`, not node name) + + * i: node that is checked for possible moves (position in the route `tour`, not node name) + * j: node that precedes the insert position in target route (position in the route `target_tour`, not node name) - ToDo: - * Remove ugly nested loops, convert to more efficient matrix operations + Todo + ---- + * Remove ugly nested loops, convert to more efficient matrix operations """ # shorter var names for loop dm = graph._matrix @@ -287,25 +337,41 @@ def operator_exchange(self, graph, solution, op_diff_round_digits, anim): position with max. saving and procedure starts over again with newly created graph as input. Stops when no improvement is found. - Returns a solution (LocalSearchSolution class)) - - Args: - op_diff_round_digits: 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) + 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 + ----- (Inner) Loop variables: - i: node that is checked for possible moves (position in the route `tour`, not node name) - j: node that precedes the insert position in target route (position in the route `target_tour`, not node name) + + * i: node that is checked for possible moves (position in the route `tour`, not node name) + * j: node that precedes the insert position in target route (position in the route `target_tour`, not node name) - ToDo: - * allow moves of a 2-node chain - * Remove ugly nested loops, convert to more efficient matrix operations + Todo + ---- + * allow moves of a 2-node chain + * Remove ugly nested loops, convert to more efficient matrix operations """ # shorter var names for loop @@ -400,29 +466,40 @@ def operator_exchange(self, graph, solution, op_diff_round_digits, anim): return solution 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. - - Returns a solution (LocalSearchSolution class)) - - Args: - op_diff_round_digits: 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) - - - ToDo: - * allow moves of a 2-node chain - * Remove ugly nested loops, convert to more efficient matrix operations + + 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 @@ -430,7 +507,25 @@ def operator_cross(self, graph, solution, op_diff_round_digits): dn = graph._nodes def benchmark_operator_order(self, graph, solution, op_diff_round_digits): - """performs all possible permutations of route improvement and prints graph length""" + """performs all possible permutations of route improvement and prints graph length + + 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) + """ operators = {self.operator_exchange: 'exchange', self.operator_relocate: 'relocate', @@ -450,14 +545,24 @@ def benchmark_operator_order(self, graph, solution, op_diff_round_digits): def solve(self, graph, savings_solution, timeout, debug=False, anim=None): """Improve initial savings solution using local search - Parameters: - graph: Graph instance - savings_solution: initial solution of CVRP problem (instance of `SavingsSolution` class) - timeout: max processing time in seconds - debug: If True, information is printed while routing - anim: AnimationDing0 object (refer to class 'AnimationDing0()' for a more detailed description) + 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) - Returns a solution (LocalSearchSolution class)) """ # TODO: If necessary, use timeout to set max processing time of local search diff --git a/ding0/grid/mv_grid/solvers/savings.py b/ding0/grid/mv_grid/solvers/savings.py index 2b124369..f5f653e6 100644 --- a/ding0/grid/mv_grid/solvers/savings.py +++ b/ding0/grid/mv_grid/solvers/savings.py @@ -41,10 +41,16 @@ def __init__(self, cvrp_problem): def clone(self): """Returns a deep copy of self - Clones: - routes - allocation - nodes + Function clones: + + * routes + * allocation + * nodes + + Returns + ------- + SavingsSolution + A clone (deepcopy) of the instance itself """ new_solution = self.__class__(self._problem) @@ -64,7 +70,15 @@ def clone(self): def is_complete(self): """Returns True if this is a complete solution, i.e, all nodes are allocated + + Todo + ---- TO BE REVIEWED + + Returns + ------- + bool + True if this is a complete solution. """ allocated = all( [node.route_allocation() is not None for node in list(self._nodes.values()) if node.name() != self._problem.depot().name()] @@ -75,11 +89,22 @@ def is_complete(self): return allocated and valid_routes def process(self, pair): + # TODO: check docstring """Processes a pair of nodes into the current solution MUST CREATE A NEW INSTANCE, NOT CHANGE ANY INSTANCE ATTRIBUTES Returns a new instance (deep copy) of self object + + Args + ---- + pair : type + description + + Returns + ------- + type + Description (Copy of self?) """ a, b = pair @@ -117,8 +142,15 @@ def process(self, pair): def can_process(self, pairs): """Returns True if this solution can process `pairs` - Parameters: - pairs: List of pairs + Parameters + ---------- + pairs: :any:`list` of pairs of Route + List of pairs + + Returns + ------- + bool + True if this solution can process `pairs`. """ i, j = pairs @@ -141,6 +173,16 @@ def compute_savings_list(self, graph): A saving list is a matrix containing the saving amount S between i and j S is calculated by S = d(0,i) + d(0,j) - d(i,j) (CLARKE; WRIGHT, 1964) + + Args + ---- + graph: :networkx:`NetworkX Graph Obj< >` + A NetworkX graaph is used. + + Returns + ------- + :any:`list` of `Node` + List of nodes sorted by its savings """ savings_list = {} @@ -164,14 +206,22 @@ def compute_savings_list(self, graph): def solve(self, graph, timeout, debug=False, anim=None): """Solves the CVRP problem using Clarke and Wright Savings methods - Parameters: - graph: Graph instance - timeout: max processing time in seconds - debug: If True, information is printed while routing - anim: AnimationDing0 object (refer to class 'AnimationDing0()' for a more detailed description) - - Returns a solution (SavingsSolution class)) + Parameters + ---------- + graph: :networkx:`NetworkX Graph Obj< >` + A NetworkX graaph is used. + timeout: int + max processing time in seconds + debug: bool, defaults to False + If True, information is printed while routing + anim: AnimationDing0 + + Returns + ------- + SavingsSolution + A solution """ + savings_list = self.compute_savings_list(graph) solution = SavingsSolution(graph) diff --git a/ding0/grid/mv_grid/tests/run_test_case.py b/ding0/grid/mv_grid/tests/run_test_case.py index 36de4fa2..5019c815 100644 --- a/ding0/grid/mv_grid/tests/run_test_case.py +++ b/ding0/grid/mv_grid/tests/run_test_case.py @@ -29,6 +29,9 @@ def main(): + """ + Description of Test Case + """ plt.close('all') graph = data_input.read_file('./testcases/Augerat/A-n32-k5.vrp') diff --git a/ding0/grid/mv_grid/tools.py b/ding0/grid/mv_grid/tools.py index e811134d..4dce5f9d 100644 --- a/ding0/grid/mv_grid/tools.py +++ b/ding0/grid/mv_grid/tools.py @@ -25,29 +25,26 @@ def set_circuit_breakers(mv_grid, mode='load', debug=False): """ Calculates the optimal position of a circuit breaker on all routes of mv_grid, adds and connects them to graph. - Args: - mv_grid: MVGridDing0 object - mode: String - determines the key parameter for relocation - - 'load' (default): Only loads are used for determination of circuit breaker position. - - 'loadgen': Both loads and generator capacities are used for determination of - circuit breaker position. If a ring is dominated by loads (peak load - > peak capacity of generators), only loads are used for determining - the location of circuit breaker. If generators are prevailing - (peak load < peak capacity of generators), only generator capacities - are considered for relocation. - - debug: If True, information is printed during process + + Args + ---- + mv_grid: MVGridDing0 + Description#TODO + debug: bool, defaults to False + If True, information is printed during process + Notes ----- According to planning principles of MV grids, a MV ring is run as two strings (half-rings) separated by a - circuit breaker which is open at normal operation [1]_, [2]_. + circuit breaker which is open at normal operation [#]_, [#]_. Assuming a ring (route which is connected to the root node at either sides), the optimal position of a circuit breaker is defined as the position (virtual cable) between two nodes where the conveyed current is minimal on the route. Instead of the peak current, the peak load is used here (assuming a constant voltage). + + If a ring is dominated by loads (peak load > peak capacity of generators), only loads are used for determining + the location of circuit breaker. If generators are prevailing (peak load < peak capacity of generators), + only generator capacities are considered for relocation. The core of this function (calculation of the optimal circuit breaker position) is the same as in ding0.grid.mv_grid.models.Route.calc_circuit_breaker_position but here it is @@ -59,8 +56,8 @@ def set_circuit_breakers(mv_grid, mode='load', debug=False): References ---------- - .. [1] X. Tao, "Automatisierte Grundsatzplanung von Mittelspannungsnetzen", Dissertation, 2006 - .. [2] FGH e.V.: "Technischer Bericht 302: Ein Werkzeug zur Optimierung der Störungsbeseitigung + .. [#] X. Tao, "Automatisierte Grundsatzplanung von Mittelspannungsnetzen", Dissertation, 2006 + .. [#] FGH e.V.: "Technischer Bericht 302: Ein Werkzeug zur Optimierung der Störungsbeseitigung für Planung und Betrieb von Mittelspannungsnetzen", Tech. rep., 2008 """ diff --git a/ding0/grid/mv_grid/util/data_input.py b/ding0/grid/mv_grid/util/data_input.py index fbc17103..a59d0528 100644 --- a/ding0/grid/mv_grid/util/data_input.py +++ b/ding0/grid/mv_grid/util/data_input.py @@ -27,7 +27,18 @@ class ParseException(Exception): - """Exception raised when something unexpected occurs in a TSPLIB file parsing""" + """Exception raised when something unexpected occurs in a TSPLIB file parsing + + Attributes + ---------- + value: type + Description + + Args + ---- + value: type + Description + """ def __init__(self, value): self.value = value @@ -36,22 +47,48 @@ def __str__(self): def strip(line): - """Removes any \r or \n from line and remove trailing whitespaces""" + """Removes any `\\\\r` or `\\\\n` from line and remove trailing whitespaces + + Parameters + ---------- + line: str + + + Returns + ------- + str + the stripped line. + + """ return line.replace('\r\n', '').strip() # remove new lines and trailing whitespaces def sanitize(filename): """Returns a sanitized file name with absolut path - Example: ~/input.txt -> /home/ /home/` Available cable types including it's electrical parameters Returns ------- - cable_type : pandas.DataFrame + :pandas:`pandas.DataFrame` Parameters of cable type """ diff --git a/ding0/tools/animation.py b/ding0/tools/animation.py index df745cf8..33373850 100644 --- a/ding0/tools/animation.py +++ b/ding0/tools/animation.py @@ -20,10 +20,18 @@ class AnimationDing0: - """ Class for visual animation of routing process (basically a central place to store information about output file - and count of saved images). Use argument 'animation=True' of method 'NetworkDing0.mv_routing()' to enable image - export. Subsequently, FFMPEG can be used to convert images to animation, e.g. - ffmpeg -r 10 -i mv-routing_ani_%04d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p mv-routing_ani.mp4 + """ Class for visual animation of routing process. + + (basically a central place to store information about output file and count of saved images). + Use argument 'animation=True' of method 'NetworkDing0.mv_routing()' to enable image export. + + Subsequently, FFMPEG can be used to convert images to animation, e.g. + + ffmpeg -r 10 -i mv-routing_ani_%04d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p mv-routing_ani.mp4 + + See Also + -------- + ding0.core.NetworkDing0.mv_routing() : """ def __init__(self, **kwargs): diff --git a/ding0/tools/config.py b/ding0/tools/config.py index 60454824..9b774d29 100644 --- a/ding0/tools/config.py +++ b/ding0/tools/config.py @@ -10,24 +10,25 @@ Based on code by oemof development team This module provides a highlevel layer for reading and writing config files. -There must be a file called "config.ini" in the root-folder of the project. -The file has to be of the following structure to be imported correctly. -# this is a comment \n -# the filestructure is like: \n - \n -[netCDF] \n -RootFolder = c://netCDF \n -FilePrefix = cd2_ \n - \n -[mySQL] \n -host = localhost \n -user = guest \n -password = root \n -database = znes \n - \n -[SectionName] \n -OptionName = value \n -Option2 = value2 \n +The config file has to be of the following structure to be imported correctly. + +:: + + [netCDF] \n + RootFolder = c://netCDF \n + FilePrefix = cd2_ \n + \n + [mySQL] \n + host = localhost \n + user = guest \n + password = root \n + database = znes \n + \n + [SectionName] \n + OptionName = value \n + Option2 = value2 \n + +Based on code by oemof development team """ __copyright__ = "Reiner Lemoine Institut gGmbH" @@ -53,6 +54,13 @@ _loaded = False def load_config(filename): + """ Read config file specified by `filename` + + Parameters + ---------- + filename : str + Description of filename + """ package_path = ding0.__path__[0] FILE = path.join(package_path, 'config', filename) @@ -64,15 +72,25 @@ def load_config(filename): logger.exception("configfile not found.") def get(section, key): - """ - returns the value of a given key of a given section of the main + """Returns the value of a given key of a given section of the main config file. - :param section: the section. - :type section: str. - :param key: the key. - :type key: str. - :returns: the value which will be casted to float, int or boolean. - if no cast is successfull, the raw string will be returned. + + Parameters + ---------- + section : str + the section. + key : str + the key + + Returns + ------- + :any:`float` + the value which will be casted to float, int or boolean. + if no cast is successful, the raw string will be returned. + + See Also + -------- + set : """ if not _loaded: pass @@ -89,15 +107,22 @@ def get(section, key): def set(section, key, value): - """ - sets a value to a [section] key - pair. + """Sets a value to a [section] key - pair. + if the section doesn't exist yet, it will be created. - :param section: the section. - :type section: str. - :param key: the key. - :type key: str. - :param value: the value. - :type value: float, int, str. + + Parameters + ---------- + section: str + the section. + key: str + the key. + value: float, int, str + the value. + + See Also + -------- + get : """ if not _loaded: diff --git a/ding0/tools/debug.py b/ding0/tools/debug.py index 2c61a62a..1f34bcc3 100644 --- a/ding0/tools/debug.py +++ b/ding0/tools/debug.py @@ -13,8 +13,6 @@ __author__ = "nesnoj, gplssm" -# This file provides some useful functions for debugging DING0 - import ding0 import os.path as path import networkx as nx diff --git a/ding0/tools/geo.py b/ding0/tools/geo.py index 8014438f..8f3ad91d 100644 --- a/ding0/tools/geo.py +++ b/ding0/tools/geo.py @@ -28,7 +28,30 @@ def calc_geo_branches_in_polygon(mv_grid, polygon, mode, proj): - # TODO: DOCSTRING + """ Calculate geographical branches in polygon. + + For a given `mv_grid` all branches (edges in the graph of the grid) are + tested if they are in the given `polygon`. You can choose different modes + and projections for this operation. + + Parameters + ---------- + mv_grid : MVGridDing0 + MV Grid object. Edges contained in `mv_grid.graph_edges()` are taken + for the test. + polygon : :shapely:`Shapely Point object` + Polygon that contains edges. + mode : str + Choose between 'intersects' or 'contains'. + proj : int + EPSG code to specify projection + + Returns + ------- + :any:`list` of :any:`BranchDing0` objects + List of branches + + """ branches = [] polygon_shp = transform(proj, polygon) @@ -51,18 +74,29 @@ def calc_geo_branches_in_polygon(mv_grid, polygon, mode, proj): def calc_geo_branches_in_buffer(node, mv_grid, radius, radius_inc, proj): - """ Determines branches in nodes' associated graph that are at least partly within buffer of `radius` from `node`. - If there are no nodes, the buffer is successively extended by `radius_inc` until nodes are found. - - Args: - node: origin node (e.g. LVStationDing0 object) with associated shapely object (attribute `geo_data`) in any CRS - (e.g. WGS84) - radius: buffer radius in m - radius_inc: radius increment in m - proj: pyproj projection object: nodes' CRS to equidistant CRS (e.g. WGS84 -> ETRS) - - Returns: - list of branches (NetworkX branch objects) + """ Determines branches in nodes' associated graph that are at least partly + within buffer of `radius` from `node`. + + If there are no nodes, the buffer is successively extended by `radius_inc` + until nodes are found. + + Parameters + ---------- + node : LVStationDing0, GeneratorDing0, or CableDistributorDing0 + origin node (e.g. LVStationDing0 object) with associated shapely object + (attribute `geo_data`) in any CRS (e.g. WGS84) + radius : float + buffer radius in m + radius_inc : float + radius increment in m + proj : int + pyproj projection object: nodes' CRS to equidistant CRS + (e.g. WGS84 -> ETRS) + + Returns + ------- + :any:`list` of :networkx:`NetworkX Graph Obj< >` + List of branches (NetworkX branch objects) """ @@ -82,13 +116,19 @@ def calc_geo_branches_in_buffer(node, mv_grid, radius, radius_inc, proj): def calc_geo_dist_vincenty(node_source, node_target): - """ Calculates the geodesic distance between `node_source` and `node_target` incorporating the detour factor in - config_calc.cfg. - Args: - node_source: source node (Ding0 object), member of _graph - node_target: target node (Ding0 object), member of _graph - - Returns: + """ Calculates the geodesic distance between `node_source` and `node_target` + incorporating the detour factor specified in :file:`ding0/ding0/config/config_calc.cfg`. + + Parameters + ---------- + node_source: LVStationDing0, GeneratorDing0, or CableDistributorDing0 + source node, member of GridDing0._graph + node_target: LVStationDing0, GeneratorDing0, or CableDistributorDing0 + target node, member of GridDing0._graph + + Returns + ------- + :any:`float` Distance in m """ @@ -112,28 +152,36 @@ def calc_geo_dist_vincenty(node_source, node_target): def calc_geo_dist_matrix_vincenty(nodes_pos): - """ Calculates the geodesic distance between all nodes in `nodes_pos` incorporating the detour factor in - config_calc.cfg. For every two points/coord it uses geopy's vincenty function (formula devised by Thaddeus Vincenty, - with an accurate ellipsoidal model of the earth). As default ellipsoidal model of the earth WGS-84 is used. - For more options see - https://geopy.readthedocs.org/en/1.10.0/index.html?highlight=vincenty#geopy.distance.vincenty - - Args: - nodes_pos: dictionary of nodes with positions, - Format: {'node_1': (x_1, y_1), - ..., - 'node_n': (x_n, y_n) - } - - Returns: - dictionary with distances between all nodes (in km), - Format: {'node_1': {'node_1': dist_11, ..., 'node_n': dist_1n}, - ..., - 'node_n': {'node_1': dist_n1, ..., 'node_n': dist_nn - } - - Notice: - x=longitude, y=latitude + """ Calculates the geodesic distance between all nodes in `nodes_pos` incorporating the detour factor in config_calc.cfg. + + For every two points/coord it uses geopy's vincenty function (formula devised by Thaddeus Vincenty, + with an accurate ellipsoidal model of the earth). As default ellipsoidal model of the earth WGS-84 is used. + For more options see + + https://geopy.readthedocs.org/en/1.10.0/index.html?highlight=vincenty#geopy.distance.vincenty + + Parameters + ---------- + nodes_pos: dict + dictionary of nodes with positions, with x=longitude, y=latitude, and the following format:: + + { + 'node_1': (x_1, y_1), + ..., + 'node_n': (x_n, y_n) + } + + Returns + ------- + :obj:`dict` + dictionary with distances between all nodes (in km), with the following format:: + + { + 'node_1': {'node_1': dist_11, ..., 'node_n': dist_1n}, + ..., + 'node_n': {'node_1': dist_n1, ..., 'node_n': dist_nn} + } + """ branch_detour_factor = cfg_ding0.get('assumptions', 'branch_detour_factor') @@ -155,14 +203,20 @@ def calc_geo_dist_matrix_vincenty(nodes_pos): def calc_geo_centre_point(node_source, node_target): - """ Calculates the geodesic distance between `node_source` and `node_target` incorporating the detour factor in - config_calc.cfg. - Args: - node_source: source node (Ding0 object), member of _graph - node_target: target node (Ding0 object), member of _graph - - Returns: - Distance in m + """ Calculates the geodesic distance between `node_source` and `node_target` + incorporating the detour factor specified in config_calc.cfg. + + Parameters + ---------- + node_source: LVStationDing0, GeneratorDing0, or CableDistributorDing0 + source node, member of GridDing0._graph + node_target: LVStationDing0, GeneratorDing0, or CableDistributorDing0 + target node, member of GridDing0._graph + + Returns + ------- + :any:`float` + Distance in m. """ proj_source = partial( diff --git a/ding0/tools/logger.py b/ding0/tools/logger.py index eda36f59..cd8acea7 100644 --- a/ding0/tools/logger.py +++ b/ding0/tools/logger.py @@ -21,8 +21,7 @@ def create_dir(dirpath): - """ - Create directory and report about it + """Create directory and report about it Parameters ---------- @@ -39,7 +38,7 @@ def create_dir(dirpath): def create_home_dir(ding0_path=None): """ - Check in ~/ exists, otherwise create it + Check if ~/.ding0 exists, otherwise create it Parameters ---------- @@ -59,7 +58,7 @@ def get_default_home_dir(): Returns ------- - homedir : str + :any:`str` Default home directory including its path """ ding0_dir = str(cfg_ding0.get('config', @@ -73,8 +72,10 @@ def setup_logger(log_dir=None, loglevel=logging.DEBUG): Parameters ---------- - log_dir : str + log_dir: str Directory to save log, default: ~/.ding0/logging/ + loglevel: + Level of logger. """ create_home_dir() diff --git a/ding0/tools/results.py b/ding0/tools/results.py index cdb0e32e..651fe483 100644 --- a/ding0/tools/results.py +++ b/ding0/tools/results.py @@ -93,27 +93,12 @@ def lv_grid_generators_bus_bar(nd): return lv_stats -#here original position of function mvgdstats def save_nd_to_pickle(nd, path='', filename=None): - """ - Use pickle to save the whole nd-object to disc - - Parameters - ---------- - nd : NetworkDing0 - Ding0 grid container object - path : str - Absolute or relative path where pickle should be saved. Default is '' - which means pickle is save to PWD - """ - - abs_path = os.path.abspath(path) + """Use pickle to save the whole nd-object to disc + The network instance is entirely pickled to a file. -def save_nd_to_pickle(nd, path='', filename=None): - """ - Use pickle to save the whole nd-object to disc Parameters ---------- nd : NetworkDing0 @@ -121,6 +106,7 @@ def save_nd_to_pickle(nd, path='', filename=None): path : str Absolute or relative path where pickle should be saved. Default is '' which means pickle is save to PWD + """ abs_path = os.path.abspath(path) diff --git a/ding0/tools/results_scigrid_2017.py b/ding0/tools/results_scigrid_2017.py deleted file mode 100644 index 12f00096..00000000 --- a/ding0/tools/results_scigrid_2017.py +++ /dev/null @@ -1,46 +0,0 @@ -"""This file is part of DING0, the DIstribution Network GeneratOr. -DING0 is a tool to generate synthetic medium and low voltage power -distribution grids based on open data. - -It is developed in the project open_eGo: https://openegoproject.wordpress.com - -DING0 lives at github: https://github.com/openego/ding0/ -The documentation is available on RTD: http://ding0.readthedocs.io""" - -__copyright__ = "Reiner Lemoine Institut gGmbH" -__license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" -__url__ = "https://github.com/openego/ding0/blob/master/LICENSE" -__author__ = "nesnoj, gplssm" - - -from ding0.tools import config as cfg_ding0 -from ding0.tools import results - -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') - -base_path = "/home/guido/rli_local/ding0_results/" -ding0 = results.ResultsDing0(base_path) - -# concat nd-pickles -# first_mvgd = 5 -# last_mvgd = 24 -# ding0.concat_nd_pickles(list(range(first_mvgd, last_mvgd + 1))) - -# concat csv files of larger ranges -# ranges = [tuple([5,15]), tuple([16,24])] -# ding0.concat_csv_stats_files(ranges) - -# create results figures and numbers based of concatenated csv file -concat_csv_file_range = [5, 24] -ding0.read_csv_results(concat_csv_file_range) - -# calculate stats -# global_stats = ding0.calculate_global_stats() -mvgd_stats = ding0.calculate_mvgd_stats() -print(mvgd_stats) -ding0.plot_cable_length() -# for key in list(global_stats.keys()): -# print(key, global_stats[key]) \ No newline at end of file diff --git a/ding0/tools/tools.py b/ding0/tools/tools.py index d4b5c9e2..9abffc9d 100644 --- a/ding0/tools/tools.py +++ b/ding0/tools/tools.py @@ -30,7 +30,7 @@ def merge_two_dicts(x, y): Returns ------- - z: dict + :obj:`dict` Merged dictionary keyed by top-level keys of both dicts ''' diff --git a/ding0/tools/write_openego_header.py b/ding0/tools/write_openego_header.py index 66fbb584..d721ef38 100755 --- a/ding0/tools/write_openego_header.py +++ b/ding0/tools/write_openego_header.py @@ -20,11 +20,11 @@ def line_prepender(filename, line): def openego_header(): - """ + """openego header in files Returns ------- - header : str + :any:`str` openego group py-file header """ diff --git a/doc/about.rst b/doc/about.rst index 74c5489d..f6f5c538 100644 --- a/doc/about.rst +++ b/doc/about.rst @@ -79,47 +79,41 @@ Branches of sector residential .. TODO: Editha #. LV-Branches - We are using the LV-Branches of Kerber from the grids. They should be assigned to the most plausible types of settlement areas. + + We are using the LV-Branches of Kerber from the grids. They should be assigned to the most plausible types of settlement areas. + #. Define the type of settlement area - To decide if a LV-grid district is most likely a rural, village or suburban settlement area we are using the population value combined with statistical data. Statisticly, there are 2.3 persons per appartment and 1.5 appartments per house. [see BBR Tabelle B12 http://www.ggr-planung.de/fileadmin/pdf-projekte/SiedEntw_und_InfrastrFolgekosten_Teil_2.pdf] [DEMIREL page 37-41, average has been coosen]. (This is not valid for urban areas.) With this we estimate the amount aus house connections (HC). + + To decide if a LV-grid district is most likely a rural, village or suburban settlement area we are using the population value combined with statistical data. Statisticly, there are 2.3 persons per appartment and 1.5 appartments per house. [see BBR Tabelle B12 http://www.ggr-planung.de/fileadmin/pdf-projekte/SiedEntw_und_InfrastrFolgekosten_Teil_2.pdf] [DEMIREL page 37-41, average has been coosen]. (This is not valid for urban areas.) With this we estimate the amount aus house connections (HC). + This value can also be found at the explenation of the database of the "Kerber"-grids and is assinged to the type of settlement area: -Rural: 622 HC at 43 MV/LV substations results in an average amount of 14.5 HC/substation -Village: 2807 HC at 51 MV/LV substations results in an average amount of 55 HC/substation -Suburban: 4856 HC at 38 MV/LV substations results in an average amount of 128 HC/substationTher -With the resulting trendline of this three point, [the Polynomial degree 2 [ 16.127*(x^2)-7.847*x+6.1848 ] whereas x is the type of of settlement area], we difine the border values for the typ of settlement area at: - * Rural <31 HC/substation - * Village <87 HC/substation - * Suburban >=87 HC/substation -#. Define LV-grid branches - within the "Kerber"-model-grids several grid branches are found: - * Rural: 5 branches (with l>=78m & l<=676m) - * Village: 7 branches (with l>=102m & l<=588m) - * Suburban: 15 branches (with l>=85 & l<=610m) - Moreover Scheffler evaluated exsiting LV-grids and provides statistics on the prevalence of LV-cable lenght divided in settelment area "type C: Detached house settlement with low densety" and "type D: Detached house settlement with higher densety": - -.. prevalence of LV-cable lenght: -================ ======================= ==================== -cable length prevalence in Typ C prevalence in Typ D -================ ======================= ==================== ->0 2% 1% ->100 17% 16% ->200 22% 31% ->300 9% 17% ->400 16% 23% ->500 16% 12% ->600 11% 0 ->700 5% 0 ->800 2% 0 -================ ======================= ==================== - - - -#. Assinging grid branches to the Substations - Strangzuweisung - Zu jeder ONS werden in Abhängigkeit von Netztyp und HA, NS-Stränge zugewiesen - Eine Verteilung des Aufkommens der Stränge anhand von der Gesamtstranglänge geschieht mit Hilfe der Scheffler Angaben (Abbildung Länge der Netzstrahlen für ausgewählte Siedlungstypen [44]) + + * Rural: 622 HC at 43 MV/LV substations results in an average amount of 14.5 HC/substation + * Village: 2807 HC at 51 MV/LV substations results in an average amount of 55 HC/substation + * Suburban: 4856 HC at 38 MV/LV substations results in an average amount of 128 HC/substationTher + + With the resulting trendline of this three point, [the Polynomial degree 2 [ 16.127*(x^2)-7.847*x+6.1848 ] whereas x is the type of of settlement area], we difine the border values for the typ of settlement area at: + + * Rural <31 HC/substation + * Village <87 HC/substation + * Suburban >=87 HC/substation + +#. Assinging grid branches to the Substations + + within the "Kerber"-model-grids several grid branches are found. + + * Rural: 5 branches (with l>=78m & l<=676m) + * Village: 7 branches (with l>=102m & l<=588m) + * Suburban: 15 branches (with l>=85 & l<=610m) + + +Strangzuweisung +Zu jeder ONS werden in Abhängigkeit von Netztyp und HA, NS-Stränge zugewiesen +Eine Verteilung des Aufkommens der Stränge anhand von der Gesamtstranglänge geschieht mit Hilfe der Scheffler Angaben (Abbildung Länge der Netzstrahlen für ausgewählte Siedlungstypen [44]) + #. Categorising grid branches form "Kerber" model grids - Hinzu kommen auf Basis von kerber interpolierte stränge um Lücken in der Vollständigkeit zu schließen + +Hinzu kommen auf Basis von kerber interpolierte stränge um Lücken in der Vollständigkeit zu schließen Branches of sector retail/industrial and agricultural ----------------------------------------------------- @@ -136,6 +130,7 @@ The topology of each sectoral branch is affected largely by assumptions on parameters that are provided in the table below. .. _assumptions: + ========================================================= ===== Parameter Value ========================================================= ===== @@ -220,7 +215,7 @@ Following steps do apply during reinforcement of Ding0 LV grids in the substation #. Subsequently **over-voltage issues** are analyzed for all grid nodes #. For each node where voltage exceeds 3 % of nominal voltage in feed-in case or - 5 % of nominal voltage in load case, branch segments + 5 % of nominal voltage in load case, branch segments connecting the node with the substation are reinforce until no further issues remain. If a over-voltage issue cannot be solved by installing largest availabe cable (NAYY 4x1x300) this type of cable still remains as well as @@ -234,13 +229,14 @@ References ---------- .. [Amme2017] J. Amme, G. Pleßmann, J. Bühler, L. Hülk, E. Kötter, P. Schwaegerl: *The eGo grid model: An open-source and open-data based synthetic medium-voltage - grid model for distribution power supply systems*. - Journal of Physics: Conference Series 2017 (submitted) + grid model for distribution power supply systems*. Journal of Physics Conference + Series 977(1):012007, 2018, `doi:10.1088/1742-6596/977/1/012007 + `_ .. [Huelk2017] L. Hülk, L. Wienholt, I. Cussmann, U. Mueller, C. Matke and E. Kötter: *Allocation of annual electricity consumption and power generation capacities across multi voltage levels in a high spatial - resolution* International Journal of Sustainable Energy Planning and - Management 2017 (submitted) + resolution*. International Journal of Sustainable Energy Planning and Management + Vol. 13 2017 79–92, `doi:10.5278/ijsepm.2017.13.6 `_ .. [Kerber] G. Kerber: Aufnahmefähigkeit von Niederspannungsverteilnetzen für die Einspeisung aus Photovoltaikkleinanlagen, Dissertation, TU München, 2011 diff --git a/doc/api.rst b/doc/api.rst deleted file mode 100644 index d99d9270..00000000 --- a/doc/api.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. make doc-string generated documentation appear here - -.. toctree:: - :maxdepth: 7 - :titlesonly: - - ding0 API \ No newline at end of file diff --git a/doc/api/ding0.config.rst b/doc/api/ding0.config.rst index d50ec504..2dd0d7a0 100644 --- a/doc/api/ding0.config.rst +++ b/doc/api/ding0.config.rst @@ -4,8 +4,8 @@ ding0.config package Submodules ---------- -ding0.config.config_db_interfaces module ----------------------------------------- +ding0.config.config\_db\_interfaces module +------------------------------------------ .. automodule:: ding0.config.config_db_interfaces :members: diff --git a/doc/api/ding0.core.network.rst b/doc/api/ding0.core.network.rst index fc7fe49b..179eb696 100644 --- a/doc/api/ding0.core.network.rst +++ b/doc/api/ding0.core.network.rst @@ -4,8 +4,8 @@ ding0.core.network package Submodules ---------- -ding0.core.network.cable_distributors module --------------------------------------------- +ding0.core.network.cable\_distributors module +--------------------------------------------- .. automodule:: ding0.core.network.cable_distributors :members: diff --git a/doc/api/ding0.core.rst b/doc/api/ding0.core.rst index 9c0249f1..3e9c0855 100644 --- a/doc/api/ding0.core.rst +++ b/doc/api/ding0.core.rst @@ -13,8 +13,8 @@ Subpackages Submodules ---------- -ding0.core.upload_to_zenodo module ----------------------------------- +ding0.core.upload\_to\_zenodo module +------------------------------------ .. automodule:: ding0.core.upload_to_zenodo :members: diff --git a/doc/api/ding0.flexopt.rst b/doc/api/ding0.flexopt.rst index 6c1840e0..546576ab 100644 --- a/doc/api/ding0.flexopt.rst +++ b/doc/api/ding0.flexopt.rst @@ -4,32 +4,32 @@ ding0.flexopt package Submodules ---------- -ding0.flexopt.check_tech_constraints module -------------------------------------------- +ding0.flexopt.check\_tech\_constraints module +--------------------------------------------- .. automodule:: ding0.flexopt.check_tech_constraints :members: :undoc-members: :show-inheritance: -ding0.flexopt.reinforce_grid module ------------------------------------ +ding0.flexopt.reinforce\_grid module +------------------------------------ .. automodule:: ding0.flexopt.reinforce_grid :members: :undoc-members: :show-inheritance: -ding0.flexopt.reinforce_measures module ---------------------------------------- +ding0.flexopt.reinforce\_measures module +---------------------------------------- .. automodule:: ding0.flexopt.reinforce_measures :members: :undoc-members: :show-inheritance: -ding0.flexopt.reinforce_measures_dena module --------------------------------------------- +ding0.flexopt.reinforce\_measures\_dena module +---------------------------------------------- .. automodule:: ding0.flexopt.reinforce_measures_dena :members: diff --git a/doc/api/ding0.grid.lv_grid.rst b/doc/api/ding0.grid.lv_grid.rst index 46299443..e022be5c 100644 --- a/doc/api/ding0.grid.lv_grid.rst +++ b/doc/api/ding0.grid.lv_grid.rst @@ -1,27 +1,27 @@ -ding0.grid.lv_grid package -========================== +ding0.grid.lv\_grid package +=========================== Submodules ---------- -ding0.grid.lv_grid.build_grid module ------------------------------------- +ding0.grid.lv\_grid.build\_grid module +-------------------------------------- .. automodule:: ding0.grid.lv_grid.build_grid :members: :undoc-members: :show-inheritance: -ding0.grid.lv_grid.check module -------------------------------- +ding0.grid.lv\_grid.check module +-------------------------------- .. automodule:: ding0.grid.lv_grid.check :members: :undoc-members: :show-inheritance: -ding0.grid.lv_grid.lv_connect module ------------------------------------- +ding0.grid.lv\_grid.lv\_connect module +-------------------------------------- .. automodule:: ding0.grid.lv_grid.lv_connect :members: diff --git a/doc/api/ding0.grid.mv_grid.models.rst b/doc/api/ding0.grid.mv_grid.models.rst index 004a87c0..0ebbe40c 100644 --- a/doc/api/ding0.grid.mv_grid.models.rst +++ b/doc/api/ding0.grid.mv_grid.models.rst @@ -1,11 +1,11 @@ -ding0.grid.mv_grid.models package -================================= +ding0.grid.mv\_grid.models package +================================== Submodules ---------- -ding0.grid.mv_grid.models.models module ---------------------------------------- +ding0.grid.mv\_grid.models.models module +---------------------------------------- .. automodule:: ding0.grid.mv_grid.models.models :members: diff --git a/doc/api/ding0.grid.mv_grid.rst b/doc/api/ding0.grid.mv_grid.rst index cf4516d7..4923f183 100644 --- a/doc/api/ding0.grid.mv_grid.rst +++ b/doc/api/ding0.grid.mv_grid.rst @@ -1,5 +1,5 @@ -ding0.grid.mv_grid package -========================== +ding0.grid.mv\_grid package +=========================== Subpackages ----------- @@ -14,24 +14,24 @@ Subpackages Submodules ---------- -ding0.grid.mv_grid.mv_connect module ------------------------------------- +ding0.grid.mv\_grid.mv\_connect module +-------------------------------------- .. automodule:: ding0.grid.mv_grid.mv_connect :members: :undoc-members: :show-inheritance: -ding0.grid.mv_grid.mv_routing module ------------------------------------- +ding0.grid.mv\_grid.mv\_routing module +-------------------------------------- .. automodule:: ding0.grid.mv_grid.mv_routing :members: :undoc-members: :show-inheritance: -ding0.grid.mv_grid.tools module -------------------------------- +ding0.grid.mv\_grid.tools module +-------------------------------- .. automodule:: ding0.grid.mv_grid.tools :members: diff --git a/doc/api/ding0.grid.mv_grid.solvers.rst b/doc/api/ding0.grid.mv_grid.solvers.rst index 18c630a1..53ffc52f 100644 --- a/doc/api/ding0.grid.mv_grid.solvers.rst +++ b/doc/api/ding0.grid.mv_grid.solvers.rst @@ -1,27 +1,27 @@ -ding0.grid.mv_grid.solvers package -================================== +ding0.grid.mv\_grid.solvers package +=================================== Submodules ---------- -ding0.grid.mv_grid.solvers.base module --------------------------------------- +ding0.grid.mv\_grid.solvers.base module +--------------------------------------- .. automodule:: ding0.grid.mv_grid.solvers.base :members: :undoc-members: :show-inheritance: -ding0.grid.mv_grid.solvers.local_search module ----------------------------------------------- +ding0.grid.mv\_grid.solvers.local\_search module +------------------------------------------------ .. automodule:: ding0.grid.mv_grid.solvers.local_search :members: :undoc-members: :show-inheritance: -ding0.grid.mv_grid.solvers.savings module ------------------------------------------ +ding0.grid.mv\_grid.solvers.savings module +------------------------------------------ .. automodule:: ding0.grid.mv_grid.solvers.savings :members: diff --git a/doc/api/ding0.grid.mv_grid.tests.rst b/doc/api/ding0.grid.mv_grid.tests.rst index 97b2a231..5396dce5 100644 --- a/doc/api/ding0.grid.mv_grid.tests.rst +++ b/doc/api/ding0.grid.mv_grid.tests.rst @@ -1,11 +1,11 @@ -ding0.grid.mv_grid.tests package -================================ +ding0.grid.mv\_grid.tests package +================================= Submodules ---------- -ding0.grid.mv_grid.tests.run_test_case module ---------------------------------------------- +ding0.grid.mv\_grid.tests.run\_test\_case module +------------------------------------------------ .. automodule:: ding0.grid.mv_grid.tests.run_test_case :members: diff --git a/doc/api/ding0.grid.mv_grid.util.rst b/doc/api/ding0.grid.mv_grid.util.rst index 3771dc9b..fa7f6c0c 100644 --- a/doc/api/ding0.grid.mv_grid.util.rst +++ b/doc/api/ding0.grid.mv_grid.util.rst @@ -1,19 +1,19 @@ -ding0.grid.mv_grid.util package -=============================== +ding0.grid.mv\_grid.util package +================================ Submodules ---------- -ding0.grid.mv_grid.util.data_input module ------------------------------------------ +ding0.grid.mv\_grid.util.data\_input module +------------------------------------------- .. automodule:: ding0.grid.mv_grid.util.data_input :members: :undoc-members: :show-inheritance: -ding0.grid.mv_grid.util.util module ------------------------------------ +ding0.grid.mv\_grid.util.util module +------------------------------------ .. automodule:: ding0.grid.mv_grid.util.util :members: diff --git a/doc/api/ding0.tools.rst b/doc/api/ding0.tools.rst index 0006c548..8a46676f 100644 --- a/doc/api/ding0.tools.rst +++ b/doc/api/ding0.tools.rst @@ -20,14 +20,6 @@ ding0.tools.config module :undoc-members: :show-inheritance: -ding0.tools.db module ---------------------- - -.. automodule:: ding0.tools.db - :members: - :undoc-members: - :show-inheritance: - ding0.tools.debug module ------------------------ @@ -52,8 +44,8 @@ ding0.tools.logger module :undoc-members: :show-inheritance: -ding0.tools.pypsa_io module ---------------------------- +ding0.tools.pypsa\_io module +---------------------------- .. automodule:: ding0.tools.pypsa_io :members: @@ -68,30 +60,6 @@ ding0.tools.results module :undoc-members: :show-inheritance: -ding0.tools.results_scigrid_2017 module ---------------------------------------- - -.. automodule:: ding0.tools.results_scigrid_2017 - :members: - :undoc-members: - :show-inheritance: - -ding0.tools.test_logging module -------------------------------- - -.. automodule:: ding0.tools.test_logging - :members: - :undoc-members: - :show-inheritance: - -ding0.tools.test_logging2 module --------------------------------- - -.. automodule:: ding0.tools.test_logging2 - :members: - :undoc-members: - :show-inheritance: - ding0.tools.tests module ------------------------ @@ -108,8 +76,16 @@ ding0.tools.tools module :undoc-members: :show-inheritance: -ding0.tools.write_openego_header module ---------------------------------------- +ding0.tools.validation module +----------------------------- + +.. automodule:: ding0.tools.validation + :members: + :undoc-members: + :show-inheritance: + +ding0.tools.write\_openego\_header module +----------------------------------------- .. automodule:: ding0.tools.write_openego_header :members: diff --git a/doc/calculation.rst b/doc/calculation.rst index 50f6fb03..74a7ed33 100644 --- a/doc/calculation.rst +++ b/doc/calculation.rst @@ -15,15 +15,17 @@ Apparent power ############## * Given maximum thermal current `I_th_amx` (`I_L`) is given per conducter (of three -cables in a system)/per phase + cables in a system)/per phase. + * We assume to have delta connection. Thus, nominal voltage per conducted can be -applied to calculate apparent power `s_nom` and conductor current `I_L` has to -be transformed to `I_delta` respectively to `I` by + applied to calculate apparent power `s_nom` and conductor current `I_L` has to + be transformed to `I_delta` respectively to `I` by -.. math:: - I = I_{delta} = \sqrt{3} \cdot I_L + .. math:: + I = I_{delta} = \sqrt{3} \cdot I_L * Apparent `S` power is calculated to -.. math:: - S = U \cdot I = U \cdot I_{th,max} \ No newline at end of file + .. math:: + S = U \cdot I = U \cdot I_{th,max} + diff --git a/doc/conf.py b/doc/conf.py index 9ef6af25..d89f440f 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -55,7 +55,7 @@ 'sphinx.ext.viewcode', # 'sphinxcontrib.napoleon',#enable Napoleon interpreter of docstrings Sphinx v<=1.2 'sphinx.ext.napoleon', #enable Napoleon Sphinx v>1.3 -# 'sphinx_paramlinks',#to have links to the types of the parameters of the functions + 'sphinx.ext.extlinks', #enables external links with a key ] # Napoleon settings napoleon_google_docstring = True @@ -66,10 +66,25 @@ napoleon_use_admonition_for_examples = False napoleon_use_admonition_for_notes = False napoleon_use_admonition_for_references = False -napoleon_use_ivar = True +napoleon_use_ivar = False napoleon_use_param = True -napoleon_use_rtype = True -napoleon_use_keyword = True +napoleon_use_rtype = False +napoleon_use_keyword = False +# Dictionary of external links +extlinks = {'pandas':('http://pandas.pydata.org/pandas-docs/stable/api.html#%s', + 'pandas.'), + 'networkx':('https://networkx.readthedocs.io/en/stable/reference/classes.graph.html%s', + 'NetworkX Graph Obj'), + 'sqlalchemy':('http://docs.sqlalchemy.org/en/latest/%s', + 'SQLAlchemy object'), + 'shapely':('http://toblerity.org/shapely/manual.html#%s', + 'Shapely object'), + 'pypsa':('https://pypsa.org/doc/components.html#%s', + 'pypsa.'), + 'pyproj':('https://jswhit.github.io/pyproj/pyproj.Proj-class.html%s', + 'pyproj.'), + } + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -87,7 +102,7 @@ # General information about the project. project = u'ding0' -copyright = u'2015-2016, open_eGo-Team' +copyright = u'2015-2018, open_eGo-Team' author = u'open_eGo-Team' # The version info for the project you're documenting, acts as replacement for @@ -114,7 +129,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'whatsnew'] +exclude_patterns = ['_build', 'whatsnew', 'calculation.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -345,4 +360,12 @@ def __getattr__(cls, name): intersphinx_mapping = {'https://docs.python.org/': None} # Numbered figures -numfig = True \ No newline at end of file +numfig = True + +#Code to exclude certain text from de docs. +#See: http://www.sphinx-doc.org/en/stable/ext/autodoc.html +def setup(app): + from sphinx.ext.autodoc import cut_lines + app.connect('autodoc-process-docstring', cut_lines(8, what=['module'])) + return app + diff --git a/doc/development.rst b/doc/development.rst index 69253ff2..69aa337a 100644 --- a/doc/development.rst +++ b/doc/development.rst @@ -87,6 +87,7 @@ This suite will run three tests: and for difference between both files. * Compare the results of a fresh ding0 run over district [3545] and the data in -'ding0_tests_grids_1.pkl'. + 'ding0_tests_grids_1.pkl'. * Compare the results of two fresh runs of ding0 in district [3545]. + diff --git a/doc/index.rst b/doc/index.rst index 9f791000..1fc3c392 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -26,14 +26,11 @@ DIstribution Network GeneratOr -- A tool to generate synthetic medium and low vo getting_started usage_details about - .. calculation development whatsnew ding0 API - - Indices and tables ================== diff --git a/doc/make.bat b/doc/make.bat deleted file mode 100644 index 660e908c..00000000 --- a/doc/make.bat +++ /dev/null @@ -1,263 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -REM Check if sphinx-build is available and fallback to Python version if any -%SPHINXBUILD% 2> nul -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -:sphinx_ok - - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ding0.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ding0.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/doc/usage_details.rst b/doc/usage_details.rst index a3e03c26..2cbc4c43 100644 --- a/doc/usage_details.rst +++ b/doc/usage_details.rst @@ -8,11 +8,11 @@ Examples We provide two examples of how to use Ding0 along with two example for analysis of resulting data. The -:download:`first example <../examples/example_single_grid_district.py>` shows how Ding0 +:download:`first example <../ding0/examples/example_single_grid_district.py>` shows how Ding0 is applied to a single medium-voltage grid district. Grid topology for the medium- and low-voltage grid level is generated an export to the *OEDB* and save to file (.pkl). -The :download:`analysis script <../examples/example_analyze_single_grid_district.py>` +The :download:`analysis script <../ding0/examples/example_analyze_single_grid_district.py>` takes data generated the first example and produces exemplary output: key figures and plots. @@ -32,7 +32,7 @@ Run ding0 --------- Check out :meth:`~core.Network.run_ding0()` as high-level function which is also used the -:download:`example <../examples/example_single_grid_district.py>`. +:download:`example <../ding0/examples/example_single_grid_district.py>`. For larger calculation (parallelization) ---------------------------------------- diff --git a/doc/welcome.rst b/doc/welcome.rst index 0afcd1d0..c8df85c9 100644 --- a/doc/welcome.rst +++ b/doc/welcome.rst @@ -15,4 +15,6 @@ This software project is part of the research project The theoretical background is detailed in section :ref:`theoretical_background`. Install the software package as explained :ref:`installation`. Take up on the -:ref:`ding0-examples` to understand how to use the software. \ No newline at end of file +:ref:`ding0-examples` to understand how to use the software. + +A standardized presentation of ding0 can be found in the `factsheet on the OEP `_. diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index 10f3cd28..d2c442f4 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -8,6 +8,7 @@ See what's new as per release! :local: :backlinks: top +.. include:: whatsnew/v0-1-5.rst .. include:: whatsnew/v0-1-4.rst .. include:: whatsnew/v0-1-3.rst .. include:: whatsnew/v0-1-2.rst diff --git a/doc/whatsnew/v0-1-4.rst b/doc/whatsnew/v0-1-4.rst index 1755b1b7..cb0bcb41 100644 --- a/doc/whatsnew/v0-1-4.rst +++ b/doc/whatsnew/v0-1-4.rst @@ -1,5 +1,5 @@ -Release v0.1.4 (??, 2017) -++++++++++++++++++++++++++++++++++ +Release v0.1.4 (January 17, 2018) ++++++++++++++++++++++++++++++++++ This release provides some fixes, a largely extended export function for statistical information about the grid data and an update of input data. diff --git a/doc/whatsnew/v0-1-5.rst b/doc/whatsnew/v0-1-5.rst new file mode 100644 index 00000000..4b89d759 --- /dev/null +++ b/doc/whatsnew/v0-1-5.rst @@ -0,0 +1,11 @@ +Release v0.1.5 (April ??, 2018) +++++++++++++++++++++++++++++++++++ + +This release provides an update of API docs. + +* Update docs: API docs now build properly from a technical perspective + `#45 `_. + The content is still not complete +* Added new generator object GeneratorFluctuating that includes a + weather_cell_id + `#254 `_ diff --git a/setup.py b/setup.py index fe39b839..09a70ea5 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ setup(name='ding0', - version='v0.1.4', + version='v0.1.5-beta', author='Reiner Lemoine Institut, openego development group', author_email='jonathan.amme@rl-institut.de', description='DIstribution Network GeneratOr', @@ -33,10 +33,10 @@ 'sqlalchemy >= 1.0.11, <= 1.2.0', 'geoalchemy2 >= 0.2.6, <= 0.4.1', 'matplotlib >= 1.5.3, <= 1.5.3', - 'egoio==0.3.0', + 'egoio==0.3.1', 'shapely >= 1.5.12, <= 1.6.3', 'pypsa >= 0.11.0, <= 0.11.0', - 'seaborn', + 'seaborn', 'unittest2', 'scipy < 1.0' ], @@ -86,5 +86,6 @@ "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", "Topic :: Scientific/Engineering"], )