From b30f4a2fff71a420eba3b4682359d64627746d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20H=C3=B6rsch?= Date: Fri, 26 Oct 2018 21:32:04 +0200 Subject: [PATCH] Update technology costs for wind Calculate grid extension costs for offshore based on weighted average distance from weather cell to substation. --- Snakefile | 1 - data/costs.csv | 18 ++++++++++-------- scripts/add_electricity.py | 11 ++++++++++- scripts/build_bus_regions.py | 4 ++++ scripts/build_renewable_profiles.py | 16 +++++++++++++++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Snakefile b/Snakefile index 97e2aa0a..ccae9908 100644 --- a/Snakefile +++ b/Snakefile @@ -112,7 +112,6 @@ rule build_renewable_potentials: rule build_renewable_profiles: input: - base_network="networks/base.nc", potentials="resources/potentials_{technology}.nc", regions=lambda wildcards: ("resources/regions_onshore.geojson" if wildcards.technology in ('onwind', 'solar') diff --git a/data/costs.csv b/data/costs.csv index 5fdcea72..ee216d36 100644 --- a/data/costs.csv +++ b/data/costs.csv @@ -1,7 +1,7 @@ technology,year,parameter,value,unit,source solar-rooftop,2030,discount rate,0.04,per unit,standard for decentral -onwind,2030,lifetime,25,years,IEA2010 -offwind,2030,lifetime,25,years,IEA2010 +onwind,2030,lifetime,30,years,DEA https://ens.dk/en/our-services/projections-and-models/technology-data +offwind,2030,lifetime,30,years,DEA https://ens.dk/en/our-services/projections-and-models/technology-data solar,2030,lifetime,25,years,IEA2010 solar-rooftop,2030,lifetime,25,years,IEA2010 solar-utility,2030,lifetime,25,years,IEA2010 @@ -16,8 +16,10 @@ lignite,2030,lifetime,40,years,IEA2010 geothermal,2030,lifetime,40,years,IEA2010 biomass,2030,lifetime,30,years,ECF2010 in DIW DataDoc http://hdl.handle.net/10419/80348 oil,2030,lifetime,30,years,ECF2010 in DIW DataDoc http://hdl.handle.net/10419/80348 -onwind,2030,investment,1182,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 -offwind,2030,investment,2506,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 +onwind,2030,investment,910,EUR/kWel,DEA https://ens.dk/en/our-services/projections-and-models/technology-data +offwind,2030,investment,1640,EUR/kWel,DEA https://ens.dk/en/our-services/projections-and-models/technology-data +offwind-grid,2030,investment,255,EUR/kWel,Haertel 2017; assuming one onshore and one offshore node +offwind-grid-perlength,2030,investment,0.97,EUR/kWel/km,Haertel 2017 solar,2030,investment,600,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 biomass,2030,investment,2209,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 geothermal,2030,investment,3392,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 @@ -32,8 +34,8 @@ OCGT,2030,investment,400,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 nuclear,2030,investment,6000,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 CCGT,2030,investment,800,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 oil,2030,investment,400,EUR/kWel,DIW DataDoc http://hdl.handle.net/10419/80348 -onwind,2030,FOM,2.961083,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 -offwind,2030,FOM,3.192338,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 +onwind,2030,FOM,2.450549,%/year,DEA https://ens.dk/en/our-services/projections-and-models/technology-data +offwind,2030,FOM,2.304878,%/year,DEA https://ens.dk/en/our-services/projections-and-models/technology-data solar,2030,FOM,4.166667,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 solar-rooftop,2030,FOM,2,%/year,ETIP PV solar-utility,2030,FOM,3,%/year,ETIP PV @@ -47,8 +49,8 @@ hydro,2030,FOM,1,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 ror,2030,FOM,2,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 CCGT,2030,FOM,2.5,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 OCGT,2030,FOM,3.75,%/year,DIW DataDoc http://hdl.handle.net/10419/80348 -onwind,2030,VOM,0.015,EUR/MWhel,RES costs made up to fix curtailment order -offwind,2030,VOM,0.02,EUR/MWhel,RES costs made up to fix curtailment order +onwind,2030,VOM,2.3,EUR/MWhel,DEA https://ens.dk/en/our-services/projections-and-models/technology-data +offwind,2030,VOM,2.7,EUR/MWhel,DEA https://ens.dk/en/our-services/projections-and-models/technology-data solar,2030,VOM,0.01,EUR/MWhel,RES costs made up to fix curtailment order coal,2030,VOM,6,EUR/MWhel,DIW DataDoc http://hdl.handle.net/10419/80348 PC (Advanced/SuperC) lignite,2030,VOM,7,EUR/MWhel,DIW DataDoc http://hdl.handle.net/10419/80348 diff --git a/scripts/add_electricity.py b/scripts/add_electricity.py index 2a460db1..465f6414 100644 --- a/scripts/add_electricity.py +++ b/scripts/add_electricity.py @@ -161,6 +161,15 @@ def attach_wind_and_solar(n, costs): n.add("Carrier", name=tech) with xr.open_dataset(getattr(snakemake.input, 'profile_' + tech)) as ds: + capital_cost = costs.at[tech, 'capital_cost'] + if tech + "-grid" in costs.index: + if tech + "-grid-perlength" in costs.index: + grid_cost = costs.at[tech + "-grid", "capital_cost"] + costs.at[tech + "-grid-perlength", 'capital_cost'] * ds['average_distance'].to_pandas() + logger.info("Added connection cost of {:0.0f}-{:0.0f} Eur/MW/a to {}".format(grid_cost.min(), grid_cost.max(), tech)) + else: + grid_cost = costs.at[tech + "-grid", "capital_cost"] + logger.info("Added connection cost of {:0.0f} Eur/MW/a to {}".format(grid_cost, tech)) + capital_cost = capital_cost + grid_cost n.madd("Generator", ds.indexes['bus'], ' ' + tech, bus=ds.indexes['bus'], @@ -169,7 +178,7 @@ def attach_wind_and_solar(n, costs): p_nom_max=ds['p_nom_max'].to_pandas(), weight=ds['weight'].to_pandas(), marginal_cost=costs.at[tech, 'marginal_cost'], - capital_cost=costs.at[tech, 'capital_cost'], + capital_cost=capital_cost, efficiency=costs.at[tech, 'efficiency'], p_max_pu=ds['profile'].transpose('time', 'bus').to_pandas()) diff --git a/scripts/build_bus_regions.py b/scripts/build_bus_regions.py index 6ba67b50..7034df61 100644 --- a/scripts/build_bus_regions.py +++ b/scripts/build_bus_regions.py @@ -24,6 +24,8 @@ for country in countries: onshore_shape = country_shapes[country] onshore_locs = n.buses.loc[c_b & n.buses.substation_lv, ["x", "y"]] onshore_regions.append(gpd.GeoDataFrame({ + 'x': onshore_locs['x'], + 'y': onshore_locs['y'], 'geometry': voronoi_partition_pts(onshore_locs.values, onshore_shape), 'country': country }, index=onshore_locs.index)) @@ -32,6 +34,8 @@ for country in countries: offshore_shape = offshore_shapes[country] offshore_locs = n.buses.loc[c_b & n.buses.substation_off, ["x", "y"]] offshore_regions_c = gpd.GeoDataFrame({ + 'x': offshore_locs['x'], + 'y': offshore_locs['y'], 'geometry': voronoi_partition_pts(offshore_locs.values, offshore_shape), 'country': country }, index=offshore_locs.index) diff --git a/scripts/build_renewable_profiles.py b/scripts/build_renewable_profiles.py index 1fe6391e..b7e00cba 100644 --- a/scripts/build_renewable_profiles.py +++ b/scripts/build_renewable_profiles.py @@ -6,6 +6,8 @@ import numpy as np import xarray as xr import pandas as pd import geopandas as gpd +from pypsa.geo import haversine +from vresutils.array import spdiag import logging logger = logging.getLogger(__name__) @@ -47,9 +49,21 @@ p_nom_max = xr.DataArray([np.nanmin(relativepotentials[row.nonzero()[1]]) for row in indicatormatrix.tocsr()], [capacities.coords['bus']]) * capacities +# Determine weighted average distance to substation +matrix_weighted = indicatormatrix * spdiag(layout.stack(spatial=('y', 'x'))) +cell_coords = cutout.grid_coordinates() + +average_distance = [] +for i, bus in enumerate(regions.index): + row = matrix_weighted[i] + distances = haversine(regions.loc[bus, ['x', 'y']], cell_coords[row.indices])[0] + average_distance.append((distances * (row.data / row.data.sum())).sum()) +average_distance = xr.DataArray(average_distance, [regions.index.rename("bus")]) + ds = xr.merge([(correction_factor * profile).rename('profile'), capacities.rename('weight'), p_nom_max.rename('p_nom_max'), - layout.rename('potential')]) + layout.rename('potential'), + average_distance.rename('average_distance')]) (ds.sel(bus=ds['profile'].mean('time') > config.get('min_p_max_pu', 0.)) .to_netcdf(snakemake.output.profile))