diff --git a/Snakefile b/Snakefile index cb50e3bf..b0dcc3b6 100644 --- a/Snakefile +++ b/Snakefile @@ -215,10 +215,22 @@ if 'hydro' in config['renewable'].keys(): resources: mem=5000 script: 'scripts/build_hydro_profile.py' +if config['lines'].get('dynamic_line_rating', True): + rule build_line_rating: + input: + base_network="networks/base.nc", + cutout="cutouts/" + config["renewable"]['onwind']['cutout'] + ".nc" + output: + output="networks/base_line_rating.nc" + log: "logs/build_line_rating.log" + benchmark: "benchmarks/build_line_rating" + threads: 1 + #resources: mem=3000 + script: "scripts/build_line_rating.py" rule add_electricity: input: - base_network='networks/base.nc', + base_network = rules.build_line_rating.output[0] if config['lines'].get('dynamic_line_rating', True) else rules.base_network.output[0], tech_costs=COSTS, regions="resources/regions_onshore.geojson", powerplants='resources/powerplants.csv', @@ -397,5 +409,4 @@ rule plot_p_nom_max: input: input_plot_p_nom_max output: "results/plots/elec_s{simpl}_cum_p_nom_max_{clusts}_{techs}_{country}.{ext}" log: "logs/plot_p_nom_max/elec_s{simpl}_{clusts}_{techs}_{country}_{ext}.log" - script: "scripts/plot_p_nom_max.py" - + script: "scripts/plot_p_nom_max.py" \ No newline at end of file diff --git a/scripts/_helpers.py b/scripts/_helpers.py index 30775ae5..f1e5e887 100644 --- a/scripts/_helpers.py +++ b/scripts/_helpers.py @@ -240,7 +240,7 @@ def mock_snakemake(rulename, **wildcards): if os.path.exists(p): snakefile = p break - workflow = sm.Workflow(snakefile) + workflow = sm.Workflow(snakefile, overwrite_configfiles=[]) workflow.include(snakefile) workflow.global_resources = {} rule = workflow.get_rule(rulename) diff --git a/scripts/build_line_rating.py b/scripts/build_line_rating.py new file mode 100644 index 00000000..7e42419a --- /dev/null +++ b/scripts/build_line_rating.py @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: : 2017-2020 The PyPSA-Eur Authors +# +# SPDX-License-Identifier: MIT + +# coding: utf-8 +""" +Adds dynamic line rating timeseries to the base network. + +Relevant Settings +----------------- + +.. code:: yaml + + lines_t: + s_max_pu + + +.. seealso:: + Documentation of the configuration file ``config.yaml` +Inputs +------ + +- ``data/cutouts``: +- ``networks/base.nc``: confer :ref:`base` + +Outputs +------- + +- ``networks/base_with_line_rating.nc`` + + +Description +----------- + +The rule :mod:`build_line_rating` calculates the line rating for transmission lines. +The line rating provides the maximal capacity of a transmission line considering the heat exchange with the environment. + +The folloing heat gains and losses are considered: + +- heat gain through resistive losses +- heat gain trough solar radiation +- heat loss through radiation of the trasnmission line +- heat loss through forced convection with wind +- heat loss through natural convection + + +With a heat balance considering the maximum temperature threshold of the tranmission line, +the maximal possible capacity factor "s_max_pu" for each transmission line at each time step is calculated. +""" + +import logging +from _helpers import configure_logging + +import pypsa +import pandas as pd +import numpy as np +import geopandas as gpd +from shapely.geometry import Point, LineString as Line +import atlite + + +def add_line_rating(n): + buses = n.lines[["bus0", "bus1"]].values + x = n.buses.x + y = n.buses.y + shapes = [Line([Point(x[b0], y[b0]), Point(x[b1], y[b1])]) for (b0, b1) in buses] + shapes = gpd.GeoSeries(shapes, index=n.lines.index) + cutout = atlite.Cutout(snakemake.input.cutout) + cutout.prepare(features=['temperature', "wnd100m", "height", "wnd_azimuth"]) + s = np.sqrt(3) * cutout.line_rating(shapes, n.lines.r/n.lines.length) * 1e3 # in MW + n.lines_t.s_max_pu=s.to_pandas().transpose()/n.lines.s_nom + n.lines_t.s_max_pu.replace(np.inf, 1.0, inplace=True) + + +if __name__ == "__main__": + if 'snakemake' not in globals(): + from _helpers import mock_snakemake + snakemake = mock_snakemake('build_line_rating', network='elec', simpl='', + clusters='5', ll='copt', opts='Co2L-BAU-CCL-24H') + configure_logging(snakemake) + + n = pypsa.Network(snakemake.input.base_network) + add_line_rating(n) + + n.export_to_netcdf(snakemake.output[0]) \ No newline at end of file diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 6619f2d7..a5a29e1b 100755 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -270,7 +270,7 @@ if __name__ == "__main__": if 'snakemake' not in globals(): from _helpers import mock_snakemake snakemake = mock_snakemake('solve_network', network='elec', simpl='', - clusters='5', ll='copt', opts='Co2L-BAU-CCL-24H') + clusters='6', ll='copt', opts='Co2L-24H') configure_logging(snakemake) tmpdir = snakemake.config['solving'].get('tmpdir') diff --git a/workflow.png b/workflow.png new file mode 100644 index 00000000..9c149766 Binary files /dev/null and b/workflow.png differ