Merge pull request #3 from PyPSA/master

update from master upstream
This commit is contained in:
martavp 2021-02-04 09:16:21 +01:00 committed by GitHub
commit 1b205b9e4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 267 additions and 235 deletions

View File

@ -26,7 +26,7 @@ the energy system and includes all greenhouse gas emitters except
waste management, agriculture, forestry and land use. waste management, agriculture, forestry and land use.
Please see the [documentation](https://pypsa-eur-sec.readthedocs.io/) Please see the [documentation](https://pypsa-eur-sec.readthedocs.io/)
for installation instructions and other useful information. for installation instructions and other useful information about the snakemake workflow.
This diagram gives an overview of the sectors and the links between This diagram gives an overview of the sectors and the links between
them: them:

View File

@ -15,19 +15,21 @@ scenario:
lv: [1.0,1.5] # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt" lv: [1.0,1.5] # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt"
clusters: [45,50] # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred clusters: [45,50] # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred
opts: [''] # only relevant for PyPSA-Eur opts: [''] # only relevant for PyPSA-Eur
sector_opts: [Co2L0-3H-T-H-B-I-solar3-dist1] # this is where the main scenario settings are sector_opts: [Co2L0-3H-T-H-B-I-solar+p3-dist1] # this is where the main scenario settings are
# to really understand the options here, look in scripts/prepare_sector_network.py # to really understand the options here, look in scripts/prepare_sector_network.py
# Co2Lx specifies the CO2 target in x% of the 1990 values; default will give default (5%); # Co2Lx specifies the CO2 target in x% of the 1990 values; default will give default (5%);
# Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions # Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions
# xH is the temporal resolution; 3H is 3-hourly, i.e. one snapshot every 3 hours # xH is the temporal resolution; 3H is 3-hourly, i.e. one snapshot every 3 hours
# single letters are sectors: T for land transport, H for building heating, # single letters are sectors: T for land transport, H for building heating,
# B for biomass supply, I for industry, shipping and aviation # B for biomass supply, I for industry, shipping and aviation
# solarx or onwindx changes the available installable potential by factor x
# dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv
# solar+c0.5 reduces the capital cost of solar to 50\% of reference value # solar+c0.5 reduces the capital cost of solar to 50\% of reference value
# for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative # solar+p3 multiplies the available installable potential by factor 3
# emissions throughout the transition path in the timeframe determined by the # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv
# for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative
# emissions throughout the transition path in the timeframe determined by the
# planning_horizons), be:beta decay; ex:exponential decay # planning_horizons), be:beta decay; ex:exponential decay
# cb40ex0 distributes a carbon budget of 40 GtCO2 following an exponential
# decay with initial growth rate 0
planning_horizons : [2030] # investment years for myopic and perfect; or costs year for overnight planning_horizons : [2030] # investment years for myopic and perfect; or costs year for overnight
# for example, set to [2020, 2030, 2040, 2050] for myopic foresight # for example, set to [2020, 2030, 2040, 2050] for myopic foresight
@ -69,6 +71,7 @@ pypsa_eur:
"Link": ["DC"] "Link": ["DC"]
"Generator": ["onwind", "offwind-ac", "offwind-dc", "solar", "ror"] "Generator": ["onwind", "offwind-ac", "offwind-dc", "solar", "ror"]
"StorageUnit": ["PHS","hydro"] "StorageUnit": ["PHS","hydro"]
"Store": []
biomass: biomass:
year: 2030 year: 2030
@ -99,7 +102,7 @@ sector:
'bev_dsm' : True #turns on EV battery 'bev_dsm' : True #turns on EV battery
'bev_availability' : 0.5 #How many cars do smart charging 'bev_availability' : 0.5 #How many cars do smart charging
'v2g' : True #allows feed-in to grid from EV battery 'v2g' : True #allows feed-in to grid from EV battery
#what is not EV or FCEV is fossil-fuelled #what is not EV or FCEV is oil-fuelled ICE
'land_transport_fuel_cell_share': # 1 means all FCEVs 'land_transport_fuel_cell_share': # 1 means all FCEVs
2020: 0 2020: 0
2030: 0.05 2030: 0.05
@ -331,7 +334,7 @@ plotting:
"Fischer-Tropsch" : "#44DD33" "Fischer-Tropsch" : "#44DD33"
"kerosene for aviation": "#44BB11" "kerosene for aviation": "#44BB11"
"naphtha for industry" : "#44FF55" "naphtha for industry" : "#44FF55"
"land transport fossil" : "#44DD33" "land transport oil" : "#44DD33"
"water tanks" : "#BBBBBB" "water tanks" : "#BBBBBB"
"hot water storage" : "#BBBBBB" "hot water storage" : "#BBBBBB"
"hot water charging" : "#BBBBBB" "hot water charging" : "#BBBBBB"
@ -366,6 +369,7 @@ plotting:
"process emissions to stored" : "#444444" "process emissions to stored" : "#444444"
"process emissions to atmosphere" : "#888888" "process emissions to atmosphere" : "#888888"
"process emissions" : "#222222" "process emissions" : "#222222"
"oil emissions" : "#666666"
"land transport fuel cell" : "#AAAAAA" "land transport fuel cell" : "#AAAAAA"
"biogas" : "#800000" "biogas" : "#800000"
"solid biomass" : "#DAA520" "solid biomass" : "#DAA520"

View File

@ -2,7 +2,7 @@ description,file/folder,licence,source
JRC IDEES database,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees JRC IDEES database,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees
urban/rural fraction,urban_percent.csv,unknown,unknown urban/rural fraction,urban_percent.csv,unknown,unknown
JRC biomass potentials,biomass/,unknown,https://doi.org/10.2790/39014 JRC biomass potentials,biomass/,unknown,https://doi.org/10.2790/39014
EEA emission statistics,eea/,unknown,https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-14 EEA emission statistics,eea/UNFCCC_v23.csv,EEA standard re-use policy,https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
Eurostat Energy Balances,eurostat-energy_balances-*/,Eurostat,https://ec.europa.eu/eurostat/web/energy/data/energy-balances Eurostat Energy Balances,eurostat-energy_balances-*/,Eurostat,https://ec.europa.eu/eurostat/web/energy/data/energy-balances
Swiss energy statistics from Swiss Federal Office of Energy,switzerland-sfoe/,unknown,http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169 Swiss energy statistics from Swiss Federal Office of Energy,switzerland-sfoe/,unknown,http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169
BASt emobility statistics,emobility/,unknown,http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-verkehrszaehlung/Stundenwerte.html?nn=626916 BASt emobility statistics,emobility/,unknown,http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-verkehrszaehlung/Stundenwerte.html?nn=626916

1 description file/folder licence source
2 JRC IDEES database jrc-idees-2015/ CC BY 4.0 https://ec.europa.eu/jrc/en/potencia/jrc-idees
3 urban/rural fraction urban_percent.csv unknown unknown
4 JRC biomass potentials biomass/ unknown https://doi.org/10.2790/39014
5 EEA emission statistics eea/ eea/UNFCCC_v23.csv unknown EEA standard re-use policy https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-14 https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
6 Eurostat Energy Balances eurostat-energy_balances-*/ Eurostat https://ec.europa.eu/eurostat/web/energy/data/energy-balances
7 Swiss energy statistics from Swiss Federal Office of Energy switzerland-sfoe/ unknown http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169
8 BASt emobility statistics emobility/ unknown http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-verkehrszaehlung/Stundenwerte.html?nn=626916

View File

@ -73,8 +73,8 @@ To download and extract the data bundle on the command line:
.. code:: bash .. code:: bash
projects/pypsa-eur-sec/data % wget "https://nworbmot.org/pypsa-eur-sec-data-bundle-201012.tar.gz" projects/pypsa-eur-sec/data % wget "https://nworbmot.org/pypsa-eur-sec-data-bundle-210125.tar.gz"
projects/pypsa-eur-sec/data % tar xvzf pypsa-eur-sec-data-bundle-201012.tar.gz projects/pypsa-eur-sec/data % tar xvzf pypsa-eur-sec-data-bundle-210125.tar.gz
The data licences and sources are given in the following table. The data licences and sources are given in the following table.

View File

@ -4,8 +4,13 @@ Release Notes
Future release Future release
=================== ===================
*For the myopic option, a carbon budget and a type of decay (exponential or beta) can be selected in the config file to distribute the budget across the planning_horizons.
*Added an option to alter the capital cost of carriers by a factor via ``carrier+factor`` in the ``{opts}`` wildcard. This can be useful for exploring uncertain cost parameters. Example: ``solar+0.5`` reduces the capital cost of solar to 50\% of original values. * For the myopic investment option, a carbon budget and a type of decay (exponential or beta) can be selected in the ``config.yaml`` file to distribute the budget across the ``planning_horizons``. For example, ``cb40ex0`` in the ``{sector_opts}`` wildcard will distribute a carbon budget of 40 GtCO2 following an exponential decay with initial growth rate 0.
* Added an option to alter the capital cost or maximum capacity of carriers by a factor via ``carrier+factor`` in the ``{sector_opts}`` wildcard. This can be useful for exploring uncertain cost parameters. Example: ``solar+c0.5`` reduces the ``capital_cost`` of solar to 50\% of original values. Similarly ``solar+p3`` multiplies the ``p_nom_max`` by 3.
* Rename the bus for European liquid hydrocarbons from ``Fischer-Tropsch`` to ``EU oil``, since it can be supplied not just with the Fischer-Tropsch process, but also with fossil oil.
* Bugfix: Fix reading in of ``pypsa-eur/resources/powerplants.csv`` to PyPSA-Eur Version 0.3.0 (use column attribute name ``DateIn`` instead of old ``YearDecommissioned``).
* Bugfix: Make sure that ``Store`` components (battery and H2) are also removed from PyPSA-Eur, so they can be added later by PyPSA-Eur-Sec.
PyPSA-Eur-Sec 0.4.0 (11th December 2020) PyPSA-Eur-Sec 0.4.0 (11th December 2020)
========================================= =========================================
@ -131,4 +136,4 @@ To make a new release of the data bundle, make an archive of the files in ``data
.. code:: bash .. code:: bash
data % tar pczf pypsa-eur-sec-data-bundle-date.tar.gz eea switzerland-sfoe biomass eurostat-energy_balances-* jrc-idees-2015 emobility urban_percent.csv timezone_mappings.csv heat_load_profile_DK_AdamJensen.csv WindWaveWEC_GLTB.xlsx myb1-2017-nitro.xls Industrial_Database.csv data % tar pczf pypsa-eur-sec-data-bundle-YYMMDD.tar.gz eea/UNFCCC_v23.csv switzerland-sfoe biomass eurostat-energy_balances-* jrc-idees-2015 emobility urban_percent.csv timezone_mappings.csv heat_load_profile_DK_AdamJensen.csv WindWaveWEC_GLTB.xlsx myb1-2017-nitro.xls Industrial_Database.csv

View File

@ -62,6 +62,9 @@ if __name__ == "__main__":
with open('config.yaml', encoding='utf8') as f: with open('config.yaml', encoding='utf8') as f:
snakemake.config = yaml.safe_load(f) snakemake.config = yaml.safe_load(f)
# This is a hack, to be replaced once snakemake is unicode-conform
if 'Secondary Forestry residues sawdust' in snakemake.config['biomass']['classes']['solid biomass']: if 'Secondary Forestry residues sawdust' in snakemake.config['biomass']['classes']['solid biomass']:
snakemake.config['biomass']['classes']['solid biomass'].remove('Secondary Forestry residues sawdust') snakemake.config['biomass']['classes']['solid biomass'].remove('Secondary Forestry residues sawdust')
snakemake.config['biomass']['classes']['solid biomass'].append('Secondary Forestry residues sawdust') snakemake.config['biomass']['classes']['solid biomass'].append('Secondary Forestry residues sawdust')

View File

@ -1,6 +1,6 @@
import numpy as np
import pandas as pd import pandas as pd
#allow plotting without Xwindows #allow plotting without Xwindows
@ -9,7 +9,7 @@ matplotlib.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from prepare_sector_network import co2_emissions_year
#consolidate and rename #consolidate and rename
def rename_techs(label): def rename_techs(label):
@ -237,7 +237,137 @@ def plot_balances():
fig.savefig(snakemake.output.balances[:-10] + k + ".pdf",transparent=True) fig.savefig(snakemake.output.balances[:-10] + k + ".pdf",transparent=True)
def historical_emissions(cts):
"""
read historical emissions to add them to the carbon budget plot
"""
#https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
#downloaded 201228 (modified by EEA last on 201221)
fn = "data/eea/UNFCCC_v23.csv"
df = pd.read_csv(fn, encoding="latin-1")
df.loc[df["Year"] == "1985-1987","Year"] = 1986
df["Year"] = df["Year"].astype(int)
df = df.set_index(['Year', 'Sector_name', 'Country_code', 'Pollutant_name']).sort_index()
e = pd.Series()
e["electricity"] = '1.A.1.a - Public Electricity and Heat Production'
e['residential non-elec'] = '1.A.4.b - Residential'
e['services non-elec'] = '1.A.4.a - Commercial/Institutional'
e['rail non-elec'] = "1.A.3.c - Railways"
e["road non-elec"] = '1.A.3.b - Road Transportation'
e["domestic navigation"] = "1.A.3.d - Domestic Navigation"
e['international navigation'] = '1.D.1.b - International Navigation'
e["domestic aviation"] = '1.A.3.a - Domestic Aviation'
e["international aviation"] = '1.D.1.a - International Aviation'
e['total energy'] = '1 - Energy'
e['industrial processes'] = '2 - Industrial Processes and Product Use'
e['agriculture'] = '3 - Agriculture'
e['LULUCF'] = '4 - Land Use, Land-Use Change and Forestry'
e['waste management'] = '5 - Waste management'
e['other'] = '6 - Other Sector'
e['indirect'] = 'ind_CO2 - Indirect CO2'
e["total wL"] = "Total (with LULUCF)"
e["total woL"] = "Total (without LULUCF)"
pol = ["CO2"] # ["All greenhouse gases - (CO2 equivalent)"]
cts
if "GB" in cts:
cts.remove("GB")
cts.append("UK")
year = np.arange(1990,2018).tolist()
idx = pd.IndexSlice
co2_totals = df.loc[idx[year,e.values,cts,pol],"emissions"].unstack("Year").rename(index=pd.Series(e.index,e.values))
co2_totals = (1/1e6)*co2_totals.groupby(level=0, axis=0).sum() #Gton CO2
co2_totals.loc['industrial non-elec'] = co2_totals.loc['total energy'] - co2_totals.loc[['electricity', 'services non-elec','residential non-elec', 'road non-elec',
'rail non-elec', 'domestic aviation', 'international aviation', 'domestic navigation',
'international navigation']].sum()
emissions = co2_totals.loc["electricity"]
if "T" in opts:
emissions += co2_totals.loc[[i+ " non-elec" for i in ["rail","road"]]].sum()
if "H" in opts:
emissions += co2_totals.loc[[i+ " non-elec" for i in ["residential","services"]]].sum()
if "I" in opts:
emissions += co2_totals.loc[["industrial non-elec","industrial processes",
"domestic aviation","international aviation",
"domestic navigation","international navigation"]].sum()
return emissions
def plot_carbon_budget_distribution():
"""
Plot historical carbon emissions in the EU and decarbonization path
"""
import matplotlib.gridspec as gridspec
import seaborn as sns; sns.set()
sns.set_style('ticks')
plt.style.use('seaborn-ticks')
plt.rcParams['xtick.direction'] = 'in'
plt.rcParams['ytick.direction'] = 'in'
plt.rcParams['xtick.labelsize'] = 20
plt.rcParams['ytick.labelsize'] = 20
plt.figure(figsize=(10, 7))
gs1 = gridspec.GridSpec(1, 1)
ax1 = plt.subplot(gs1[0,0])
ax1.set_ylabel('CO$_2$ emissions (Gt per year)',fontsize=22)
ax1.set_ylim([0,5])
ax1.set_xlim([1990,snakemake.config['scenario']['planning_horizons'][-1]+1])
path_cb = snakemake.config['results_dir'] + snakemake.config['run'] + '/csvs/'
countries=pd.read_csv(path_cb + 'countries.csv', index_col=1)
cts=countries.index.to_list()
e_1990 = co2_emissions_year(cts, opts, year=1990)
CO2_CAP=pd.read_csv(path_cb + 'carbon_budget_distribution.csv',
index_col=0)
ax1.plot(e_1990*CO2_CAP[o],linewidth=3,
color='dodgerblue', label=None)
emissions = historical_emissions(cts)
ax1.plot(emissions, color='black', linewidth=3, label=None)
#plot commited and uder-discussion targets
#(notice that historical emissions include all countries in the
# network, but targets refer to EU)
ax1.plot([2020],[0.8*emissions[1990]],
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black')
ax1.plot([2030],[0.45*emissions[1990]],
marker='*', markersize=12, markerfacecolor='white',
markeredgecolor='black')
ax1.plot([2030],[0.6*emissions[1990]],
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black')
ax1.plot([2050, 2050],[x*emissions[1990] for x in [0.2, 0.05]],
color='gray', linewidth=2, marker='_', alpha=0.5)
ax1.plot([2050],[0.01*emissions[1990]],
marker='*', markersize=12, markerfacecolor='white',
linewidth=0, markeredgecolor='black',
label='EU under-discussion target', zorder=10,
clip_on=False)
ax1.plot([2050],[0.125*emissions[1990]],'ro',
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black', label='EU commited target')
ax1.legend(fancybox=True, fontsize=18, loc=(0.01,0.01),
facecolor='white', frameon=True)
path_cb_plot = snakemake.config['results_dir'] + snakemake.config['run'] + '/graphs/'
plt.savefig(path_cb_plot+'carbon_budget_plot.pdf', dpi=300)
if __name__ == "__main__": if __name__ == "__main__":
# Detect running outside of snakemake and mock snakemake for testing # Detect running outside of snakemake and mock snakemake for testing
@ -249,13 +379,16 @@ if __name__ == "__main__":
snakemake.config = yaml.safe_load(f) snakemake.config = yaml.safe_load(f)
snakemake.input = Dict() snakemake.input = Dict()
snakemake.output = Dict() snakemake.output = Dict()
snakemake.wildcards = Dict()
#snakemake.wildcards['sector_opts']='3H-T-H-B-I-solar3-dist1-cb48be3'
for item in ["costs", "energy"]: for item in ["costs", "energy"]:
snakemake.input[item] = snakemake.config['summary_dir'] + '/{name}/csvs/{item}.csv'.format(name=snakemake.config['run'],item=item) snakemake.input[item] = snakemake.config['summary_dir'] + '/{name}/csvs/{item}.csv'.format(name=snakemake.config['run'],item=item)
snakemake.output[item] = snakemake.config['summary_dir'] + '/{name}/graphs/{item}.pdf'.format(name=snakemake.config['run'],item=item) snakemake.output[item] = snakemake.config['summary_dir'] + '/{name}/graphs/{item}.pdf'.format(name=snakemake.config['run'],item=item)
snakemake.input["balances"] = snakemake.config['summary_dir'] + '/test/csvs/supply_energy.csv' snakemake.input["balances"] = snakemake.config['summary_dir'] + '/{name}/csvs/supply_energy.csv'.format(name=snakemake.config['run'],item=item)
snakemake.output["balances"] = snakemake.config['summary_dir'] + '/test/graphs/balances-energy.csv' snakemake.output["balances"] = snakemake.config['summary_dir'] + '/{name}/graphs/balances-energy.csv'.format(name=snakemake.config['run'],item=item)
n_header = 4 n_header = 4
plot_costs() plot_costs()
@ -263,3 +396,9 @@ if __name__ == "__main__":
plot_energy() plot_energy()
plot_balances() plot_balances()
for sector_opts in snakemake.config['scenario']['sector_opts']:
opts=sector_opts.split('-')
for o in opts:
if "cb" in o:
plot_carbon_budget_distribution()

View File

@ -48,24 +48,24 @@ override_component_attrs["Store"].loc["build_year"] = ["integer","year",np.nan,"
override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"lifetime","Input (optional)"] override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"lifetime","Input (optional)"]
def co2_emissions_year(year):
def co2_emissions_year(cts, opts, year):
""" """
calculate co2 emissions in one specific year (e.g. 1990 or 2018). calculate co2 emissions in one specific year (e.g. 1990 or 2018).
""" """
eea_co2 = build_eea_co2(year) eea_co2 = build_eea_co2(year)
#TODO: read Eurostat data from year>2014, this only affects the estimation of #TODO: read Eurostat data from year>2014, this only affects the estimation of
# CO2 emissions for "BA","RS","AL","ME","MK" # CO2 emissions for "BA","RS","AL","ME","MK"
if year > 2014: if year > 2014:
eurostat_co2 = build_eurostat_co2(year=2014) eurostat_co2 = build_eurostat_co2(year=2014)
else: else:
eurostat_co2 = build_eurostat_co2(year) eurostat_co2 = build_eurostat_co2(year)
co2_totals=build_co2_totals(eea_co2, eurostat_co2, year) co2_totals=build_co2_totals(eea_co2, eurostat_co2, year)
pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout, index_col=0)
pop_layout["ct"] = pop_layout.index.str[:2]
cts = pop_layout.ct.value_counts().index
co2_emissions = co2_totals.loc[cts, "electricity"].sum() co2_emissions = co2_totals.loc[cts, "electricity"].sum()
@ -80,173 +80,57 @@ def co2_emissions_year(year):
co2_emissions *=0.001 #MtCO2 to GtCO2 co2_emissions *=0.001 #MtCO2 to GtCO2
return co2_emissions return co2_emissions
def historical_emissions():
"""
read historical emissions to add them to the carbon budget plot
"""
#https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
#downloaded 201228 (modified by EEA last on 201221)
fn = "data/eea/UNFCCC_v23.csv"
df = pd.read_csv(fn, encoding="latin-1")
df.loc[df["Year"] == "1985-1987","Year"] = 1986
df["Year"] = df["Year"].astype(int)
df = df.set_index(['Year', 'Sector_name', 'Country_code', 'Pollutant_name']).sort_index()
e = pd.Series()
e["electricity"] = '1.A.1.a - Public Electricity and Heat Production'
e['residential non-elec'] = '1.A.4.b - Residential'
e['services non-elec'] = '1.A.4.a - Commercial/Institutional'
e['rail non-elec'] = "1.A.3.c - Railways"
e["road non-elec"] = '1.A.3.b - Road Transportation'
e["domestic navigation"] = "1.A.3.d - Domestic Navigation"
e['international navigation'] = '1.D.1.b - International Navigation'
e["domestic aviation"] = '1.A.3.a - Domestic Aviation'
e["international aviation"] = '1.D.1.a - International Aviation'
e['total energy'] = '1 - Energy'
e['industrial processes'] = '2 - Industrial Processes and Product Use'
e['agriculture'] = '3 - Agriculture'
e['LULUCF'] = '4 - Land Use, Land-Use Change and Forestry'
e['waste management'] = '5 - Waste management'
e['other'] = '6 - Other Sector'
e['indirect'] = 'ind_CO2 - Indirect CO2'
e["total wL"] = "Total (with LULUCF)"
e["total woL"] = "Total (without LULUCF)"
pol = ["CO2"] # ["All greenhouse gases - (CO2 equivalent)"]
pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout, index_col=0)
pop_layout["ct"] = pop_layout.index.str[:2]
cts = pop_layout.ct.value_counts().index.to_list()
if "GB" in cts:
cts.remove("GB")
cts.append("UK")
year = np.arange(1990,2018).tolist()
idx = pd.IndexSlice
co2_totals = df.loc[idx[year,e.values,cts,pol],"emissions"].unstack("Year").rename(index=pd.Series(e.index,e.values))
co2_totals = (1/1e6)*co2_totals.groupby(level=0, axis=0).sum() #Gton CO2
co2_totals.loc['industrial non-elec'] = co2_totals.loc['total energy'] - co2_totals.loc[['electricity', 'services non-elec','residential non-elec', 'road non-elec',
'rail non-elec', 'domestic aviation', 'international aviation', 'domestic navigation',
'international navigation']].sum()
emissions = co2_totals.loc["electricity"]
if "T" in opts:
emissions += co2_totals.loc[[i+ " non-elec" for i in ["rail","road"]]].sum()
if "H" in opts:
emissions += co2_totals.loc[[i+ " non-elec" for i in ["residential","services"]]].sum()
if "I" in opts:
emissions += co2_totals.loc[["industrial non-elec","industrial processes",
"domestic aviation","international aviation",
"domestic navigation","international navigation"]].sum()
return emissions
def build_carbon_budget(o): def build_carbon_budget(o):
#distribute carbon budget following beta or exponential transition path #distribute carbon budget following beta or exponential transition path
if "be" in o: if "be" in o:
#beta decay #beta decay
carbon_budget = float(o[o.find("cb")+2:o.find("be")]) carbon_budget = float(o[o.find("cb")+2:o.find("be")])
be=float(o[o.find("be")+2:]) be=float(o[o.find("be")+2:])
if "ex" in o: if "ex" in o:
#exponential decay #exponential decay
carbon_budget = float(o[o.find("cb")+2:o.find("ex")]) carbon_budget = float(o[o.find("cb")+2:o.find("ex")])
r=float(o[o.find("ex")+2:]) r=float(o[o.find("ex")+2:])
e_1990 = co2_emissions_year(year=1990)
pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout, index_col=0)
pop_layout["ct"] = pop_layout.index.str[:2]
cts = pop_layout.ct.value_counts().index
e_1990 = co2_emissions_year(cts, opts, year=1990)
#emissions at the beginning of the path (last year available 2018) #emissions at the beginning of the path (last year available 2018)
e_0 = co2_emissions_year(year=2018) e_0 = co2_emissions_year(cts, opts, year=2018)
#emissions in 2019 and 2020 assumed equal to 2018 and substracted #emissions in 2019 and 2020 assumed equal to 2018 and substracted
carbon_budget -= 2*e_0 carbon_budget -= 2*e_0
planning_horizons = snakemake.config['scenario']['planning_horizons'] planning_horizons = snakemake.config['scenario']['planning_horizons']
CO2_CAP = pd.DataFrame(index = pd.Series(data=planning_horizons, CO2_CAP = pd.DataFrame(index = pd.Series(data=planning_horizons,
name='planning_horizon'), name='planning_horizon'),
columns=pd.Series(data=[], columns=pd.Series(data=[],
name='paths', name='paths',
dtype='float')) dtype='float'))
t_0 = planning_horizons[0] t_0 = planning_horizons[0]
if "be" in o: if "be" in o:
#beta decay #beta decay
t_f = t_0 + (2*carbon_budget/e_0).round(0) # final year in the path t_f = t_0 + (2*carbon_budget/e_0).round(0) # final year in the path
#emissions (relative to 1990) #emissions (relative to 1990)
CO2_CAP[o] = [(e_0/e_1990)*(1-beta.cdf((t-t_0)/(t_f-t_0), be, be)) for t in planning_horizons] CO2_CAP[o] = [(e_0/e_1990)*(1-beta.cdf((t-t_0)/(t_f-t_0), be, be)) for t in planning_horizons]
if "ex" in o: if "ex" in o:
#exponential decay without delay #exponential decay without delay
T=carbon_budget/e_0 T=carbon_budget/e_0
m=(1+np.sqrt(1+r*T))/T m=(1+np.sqrt(1+r*T))/T
CO2_CAP[o] = [(e_0/e_1990)*(1+(m+r)*(t-t_0))*np.exp(-m*(t-t_0)) for t in planning_horizons] CO2_CAP[o] = [(e_0/e_1990)*(1+(m+r)*(t-t_0))*np.exp(-m*(t-t_0)) for t in planning_horizons]
CO2_CAP.to_csv(path_cb + 'carbon_budget_distribution.csv', sep=',',
line_terminator='\n', float_format='%.3f')
"""
Plot historical carbon emissions in the EU and decarbonization path
"""
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns; sns.set()
sns.set_style('ticks')
plt.style.use('seaborn-ticks')
plt.rcParams['xtick.direction'] = 'in'
plt.rcParams['ytick.direction'] = 'in'
plt.rcParams['xtick.labelsize'] = 20
plt.rcParams['ytick.labelsize'] = 20
plt.figure(figsize=(10, 7))
gs1 = gridspec.GridSpec(1, 1)
ax1 = plt.subplot(gs1[0,0])
ax1.set_ylabel('CO$_2$ emissions (Gt per year)',fontsize=22)
ax1.set_ylim([0,5])
ax1.set_xlim([1990,planning_horizons[-1]+1])
ax1.plot(e_1990*CO2_CAP[o],linewidth=3,
color='dodgerblue', label=None)
emissions = historical_emissions()
ax1.plot(emissions, color='black', linewidth=3, label=None) CO2_CAP.to_csv(path_cb + 'carbon_budget_distribution.csv', sep=',',
line_terminator='\n', float_format='%.3f')
#plot commited and uder-discussion targets countries=pd.Series(data=cts)
#(notice that historical emissions include all countries in the countries.to_csv(path_cb + 'countries.csv', sep=',',
# network, but targets refer to EU) line_terminator='\n', float_format='%.3f')
ax1.plot([2020],[0.8*emissions[1990]],
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black')
ax1.plot([2030],[0.45*emissions[1990]],
marker='*', markersize=12, markerfacecolor='white',
markeredgecolor='black')
ax1.plot([2030],[0.6*emissions[1990]],
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black')
ax1.plot([2050, 2050],[x*emissions[1990] for x in [0.2, 0.05]],
color='gray', linewidth=2, marker='_', alpha=0.5)
ax1.plot([2050],[0.01*emissions[1990]],
marker='*', markersize=12, markerfacecolor='white',
linewidth=0, markeredgecolor='black',
label='EU under-discussion target', zorder=10,
clip_on=False)
ax1.plot([2050],[0.125*emissions[1990]],'ro',
marker='*', markersize=12, markerfacecolor='black',
markeredgecolor='black', label='EU commited target')
ax1.legend(fancybox=True, fontsize=18, loc=(0.01,0.01),
facecolor='white', frameon=True)
path_cb_plot = snakemake.config['results_dir'] + snakemake.config['run'] + '/graphs/'
if not os.path.exists(path_cb_plot):
os.makedirs(path_cb_plot)
print('carbon budget distribution saved to ' + path_cb_plot + 'carbon_budget_plot.pdf')
plt.savefig(path_cb_plot+'carbon_budget_plot.pdf', dpi=300)
def add_lifetime_wind_solar(n): def add_lifetime_wind_solar(n):
""" """
Add lifetime for solar and wind generators Add lifetime for solar and wind generators
@ -799,7 +683,7 @@ def add_generation(network):
capital_cost=0.) #could correct to e.g. 0.2 EUR/kWh * annuity and O&M capital_cost=0.) #could correct to e.g. 0.2 EUR/kWh * annuity and O&M
network.add("Generator", network.add("Generator",
"EU fossil " + carrier, "EU " + carrier,
bus="EU " + carrier, bus="EU " + carrier,
p_nom_extendable=True, p_nom_extendable=True,
carrier=carrier, carrier=carrier,
@ -1179,14 +1063,14 @@ def add_land_transport(network):
fuel_cell_share = get_parameter(options["land_transport_fuel_cell_share"]) fuel_cell_share = get_parameter(options["land_transport_fuel_cell_share"])
electric_share = get_parameter(options["land_transport_electric_share"]) electric_share = get_parameter(options["land_transport_electric_share"])
fossil_share = 1 - fuel_cell_share - electric_share ice_share = 1 - fuel_cell_share - electric_share
print("shares of FCEV, EV and ICEV are", print("shares of FCEV, EV and ICEV are",
fuel_cell_share, fuel_cell_share,
electric_share, electric_share,
fossil_share) ice_share)
if fossil_share < 0: if ice_share < 0:
print("Error, more FCEV and EV share than 1.") print("Error, more FCEV and EV share than 1.")
sys.exit() sys.exit()
@ -1264,14 +1148,14 @@ def add_land_transport(network):
p_set=fuel_cell_share/options['transport_fuel_cell_efficiency']*transport[nodes]) p_set=fuel_cell_share/options['transport_fuel_cell_efficiency']*transport[nodes])
if fossil_share > 0: if ice_share > 0:
network.madd("Load", network.madd("Load",
nodes, nodes,
suffix=" land transport fossil", suffix=" land transport oil",
bus="Fischer-Tropsch", bus="EU oil",
carrier="land transport fossil", carrier="land transport oil",
p_set=fossil_share/options['transport_internal_combustion_efficiency']*transport[nodes]) p_set=ice_share/options['transport_internal_combustion_efficiency']*transport[nodes])
@ -1463,7 +1347,7 @@ def add_heat(network):
capital_cost=costs.at['central gas CHP','fixed']*costs.at['central gas CHP','efficiency'] + costs.at['biomass CHP capture','fixed']*costs.at['gas','CO2 intensity'], capital_cost=costs.at['central gas CHP','fixed']*costs.at['central gas CHP','efficiency'] + costs.at['biomass CHP capture','fixed']*costs.at['gas','CO2 intensity'],
marginal_cost=costs.at['central gas CHP','VOM'], marginal_cost=costs.at['central gas CHP','VOM'],
efficiency=costs.at['central gas CHP','efficiency'] - costs.at['gas','CO2 intensity']*(costs.at['biomass CHP capture','electricity-input'] + costs.at['biomass CHP capture','compression-electricity-input']), efficiency=costs.at['central gas CHP','efficiency'] - costs.at['gas','CO2 intensity']*(costs.at['biomass CHP capture','electricity-input'] + costs.at['biomass CHP capture','compression-electricity-input']),
efficiency2=costs.at['central gas CHP','efficiency']/costs.at['central gas CHP','c_b'] + costs.at['gas','CO2 intensity']*(costs.at['biomass CHP capture','heat-output'] + costs.at['biomass CHP capture','compression-heat-output'] - costs.at['biomass CHP capture','heat-output']), efficiency2=costs.at['central gas CHP','efficiency']/costs.at['central gas CHP','c_b'] + costs.at['gas','CO2 intensity']*(costs.at['biomass CHP capture','heat-output'] + costs.at['biomass CHP capture','compression-heat-output'] - costs.at['biomass CHP capture','heat-input']),
efficiency3=costs.at['gas','CO2 intensity']*(1-costs.at['biomass CHP capture','capture_rate']), efficiency3=costs.at['gas','CO2 intensity']*(1-costs.at['biomass CHP capture','capture_rate']),
efficiency4=costs.at['gas','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'], efficiency4=costs.at['gas','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'],
lifetime=costs.at['central gas CHP','lifetime']) lifetime=costs.at['central gas CHP','lifetime'])
@ -1682,7 +1566,7 @@ def add_biomass(network):
capital_cost=costs.at['central solid biomass CHP','fixed']*costs.at['central solid biomass CHP','efficiency'] + costs.at['biomass CHP capture','fixed']*costs.at['solid biomass','CO2 intensity'], capital_cost=costs.at['central solid biomass CHP','fixed']*costs.at['central solid biomass CHP','efficiency'] + costs.at['biomass CHP capture','fixed']*costs.at['solid biomass','CO2 intensity'],
marginal_cost=costs.at['central solid biomass CHP','VOM'], marginal_cost=costs.at['central solid biomass CHP','VOM'],
efficiency=costs.at['central solid biomass CHP','efficiency'] - costs.at['solid biomass','CO2 intensity']*(costs.at['biomass CHP capture','electricity-input'] + costs.at['biomass CHP capture','compression-electricity-input']), efficiency=costs.at['central solid biomass CHP','efficiency'] - costs.at['solid biomass','CO2 intensity']*(costs.at['biomass CHP capture','electricity-input'] + costs.at['biomass CHP capture','compression-electricity-input']),
efficiency2=costs.at['central solid biomass CHP','efficiency-heat'] + costs.at['solid biomass','CO2 intensity']*(costs.at['biomass CHP capture','heat-output'] + costs.at['biomass CHP capture','compression-heat-output'] - costs.at['biomass CHP capture','heat-output']), efficiency2=costs.at['central solid biomass CHP','efficiency-heat'] + costs.at['solid biomass','CO2 intensity']*(costs.at['biomass CHP capture','heat-output'] + costs.at['biomass CHP capture','compression-heat-output'] - costs.at['biomass CHP capture','heat-input']),
efficiency3=-costs.at['solid biomass','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'], efficiency3=-costs.at['solid biomass','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'],
efficiency4=costs.at['solid biomass','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'], efficiency4=costs.at['solid biomass','CO2 intensity']*costs.at['biomass CHP capture','capture_rate'],
lifetime=costs.at['central solid biomass CHP','lifetime']) lifetime=costs.at['central solid biomass CHP','lifetime'])
@ -1787,27 +1671,30 @@ def add_industry(network):
carrier="H2 for shipping", carrier="H2 for shipping",
p_set = nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6*options['shipping_average_efficiency']/costs.at["fuel cell","efficiency"]/8760.) p_set = nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6*options['shipping_average_efficiency']/costs.at["fuel cell","efficiency"]/8760.)
network.madd("Bus", if "EU oil" not in network.buses.index:
["Fischer-Tropsch"], network.madd("Bus",
location="EU", ["EU oil"],
carrier="Fischer-Tropsch") location="EU",
carrier="oil")
#use madd to get carrier inserted #use madd to get carrier inserted
network.madd("Store", if "EU oil Store" not in network.stores.index:
["Fischer-Tropsch Store"], network.madd("Store",
bus="Fischer-Tropsch", ["EU oil Store"],
e_nom_extendable=True, bus="EU oil",
e_cyclic=True, e_nom_extendable=True,
carrier="Fischer-Tropsch", e_cyclic=True,
capital_cost=0.) #could correct to e.g. 0.001 EUR/kWh * annuity and O&M carrier="oil",
capital_cost=0.) #could correct to e.g. 0.001 EUR/kWh * annuity and O&M
network.add("Generator", if "EU oil" not in network.generators.index:
"fossil oil", network.add("Generator",
bus="Fischer-Tropsch", "EU oil",
p_nom_extendable=True, bus="EU oil",
carrier="oil", p_nom_extendable=True,
capital_cost=0., carrier="oil",
marginal_cost=costs.at["oil",'fuel']) capital_cost=0.,
marginal_cost=costs.at["oil",'fuel'])
if options["oil_boilers"]: if options["oil_boilers"]:
@ -1817,7 +1704,7 @@ def add_industry(network):
network.madd("Link", network.madd("Link",
nodes_heat[name] + " " + name + " oil boiler", nodes_heat[name] + " " + name + " oil boiler",
p_nom_extendable=True, p_nom_extendable=True,
bus0=["Fischer-Tropsch"] * len(nodes_heat[name]), bus0="EU oil",
bus1=nodes_heat[name] + " " + name + " heat", bus1=nodes_heat[name] + " " + name + " heat",
bus2="co2 atmosphere", bus2="co2 atmosphere",
carrier=name + " oil boiler", carrier=name + " oil boiler",
@ -1830,7 +1717,7 @@ def add_industry(network):
network.madd("Link", network.madd("Link",
nodes + " Fischer-Tropsch", nodes + " Fischer-Tropsch",
bus0=nodes + " H2", bus0=nodes + " H2",
bus1="Fischer-Tropsch", bus1="EU oil",
bus2="co2 stored", bus2="co2 stored",
carrier="Fischer-Tropsch", carrier="Fischer-Tropsch",
efficiency=costs.at["Fischer-Tropsch",'efficiency'], efficiency=costs.at["Fischer-Tropsch",'efficiency'],
@ -1841,13 +1728,13 @@ def add_industry(network):
network.madd("Load", network.madd("Load",
["naphtha for industry"], ["naphtha for industry"],
bus="Fischer-Tropsch", bus="EU oil",
carrier="naphtha for industry", carrier="naphtha for industry",
p_set = industrial_demand.loc[nodes,"naphtha"].sum()/8760.) p_set = industrial_demand.loc[nodes,"naphtha"].sum()/8760.)
network.madd("Load", network.madd("Load",
["kerosene for aviation"], ["kerosene for aviation"],
bus="Fischer-Tropsch", bus="EU oil",
carrier="kerosene for aviation", carrier="kerosene for aviation",
p_set = nodal_energy_totals.loc[nodes,["total international aviation","total domestic aviation"]].sum(axis=1).sum()*1e6/8760.) p_set = nodal_energy_totals.loc[nodes,["total international aviation","total domestic aviation"]].sum(axis=1).sum()*1e6/8760.)
@ -1857,9 +1744,9 @@ def add_industry(network):
co2 = network.loads.loc[["naphtha for industry","kerosene for aviation"],"p_set"].sum()*costs.at["oil",'CO2 intensity'] - industrial_demand.loc[nodes,"process emission from feedstock"].sum()/8760. co2 = network.loads.loc[["naphtha for industry","kerosene for aviation"],"p_set"].sum()*costs.at["oil",'CO2 intensity'] - industrial_demand.loc[nodes,"process emission from feedstock"].sum()/8760.
network.madd("Load", network.madd("Load",
["Fischer-Tropsch emissions"], ["oil emissions"],
bus="co2 atmosphere", bus="co2 atmosphere",
carrier="Fischer-Tropsch emissions", carrier="oil emissions",
p_set=-co2) p_set=-co2)
network.madd("Load", network.madd("Load",
@ -1935,13 +1822,6 @@ def add_waste_heat(network):
network.links.loc[urban_central + " H2 Fuel Cell","bus2"] = urban_central + " urban central heat" network.links.loc[urban_central + " H2 Fuel Cell","bus2"] = urban_central + " urban central heat"
network.links.loc[urban_central + " H2 Fuel Cell","efficiency2"] = 0.95 - network.links.loc[urban_central + " H2 Fuel Cell","efficiency"] network.links.loc[urban_central + " H2 Fuel Cell","efficiency2"] = 0.95 - network.links.loc[urban_central + " H2 Fuel Cell","efficiency"]
def restrict_technology_potential(n,tech,limit):
print("restricting potentials (p_nom_max) for {} to {} of technical potential".format(tech,limit))
gens = n.generators.index[n.generators.carrier.str.contains(tech)]
#beware if limit is 0 and p_nom_max is np.inf, 0*np.inf is nan
n.generators.loc[gens,"p_nom_max"] *=limit
def decentral(n): def decentral(n):
n.lines.drop(n.lines.index,inplace=True) n.lines.drop(n.lines.index,inplace=True)
n.links.drop(n.links.index[n.links.carrier.isin(["DC","B2B"])],inplace=True) n.links.drop(n.links.index[n.links.carrier.isin(["DC","B2B"])],inplace=True)
@ -1984,8 +1864,9 @@ if __name__ == "__main__":
from vresutils.snakemake import MockSnakemake from vresutils.snakemake import MockSnakemake
snakemake = MockSnakemake( snakemake = MockSnakemake(
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0', wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
opts='', planning_horizons='2050', opts='', planning_horizons='2020',
sector_opts='Co2L0-180H-T-H-B-I-solar3-dist1-solar+c0.5-Sabatier+c0.5'), sector_opts='120H-T-H-B-I-onwind+p3-dist1-cb48be3'),
input=dict( network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc', input=dict( network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc',
energy_totals_name='resources/energy_totals.csv', energy_totals_name='resources/energy_totals.csv',
co2_totals_name='resources/co2_totals.csv', co2_totals_name='resources/co2_totals.csv',
@ -2024,7 +1905,8 @@ if __name__ == "__main__":
retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv", retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv",
floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv" floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv"
), ),
output=['results/version-0/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc'] output=['results/version-cb48be3/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc']
) )
import yaml import yaml
with open('config.yaml', encoding='utf8') as f: with open('config.yaml', encoding='utf8') as f:
@ -2129,19 +2011,21 @@ if __name__ == "__main__":
print("CO2 limit set to",limit) print("CO2 limit set to",limit)
for o in opts: for o in opts:
if "cb" in o:
if "cb" in o:
path_cb = snakemake.config['results_dir'] + snakemake.config['run'] + '/csvs/' path_cb = snakemake.config['results_dir'] + snakemake.config['run'] + '/csvs/'
if not os.path.exists(path_cb): if not os.path.exists(path_cb):
os.makedirs(path_cb) os.makedirs(path_cb)
try: try:
CO2_CAP=pd.read_csv(path_cb + 'carbon_budget_distribution.csv', index_col=0) CO2_CAP=pd.read_csv(path_cb + 'carbon_budget_distribution.csv', index_col=0)
except: except:
build_carbon_budget(o) build_carbon_budget(o)
CO2_CAP=pd.read_csv(path_cb + 'carbon_budget_distribution.csv', index_col=0) CO2_CAP=pd.read_csv(path_cb + 'carbon_budget_distribution.csv', index_col=0)
limit=CO2_CAP.loc[investment_year] limit=CO2_CAP.loc[investment_year]
print("overriding CO2 limit with scenario limit",limit) print("overriding CO2 limit with scenario limit",limit)
for o in opts: for o in opts:
if "Co2L" in o: if "Co2L" in o:
limit = o[o.find("Co2L")+4:] limit = o[o.find("Co2L")+4:]
@ -2150,14 +2034,8 @@ if __name__ == "__main__":
print("adding CO2 budget limit as per unit of 1990 levels of",limit) print("adding CO2 budget limit as per unit of 1990 levels of",limit)
add_co2limit(n, Nyears, limit) add_co2limit(n, Nyears, limit)
for o in opts: for o in opts:
for tech in ["solar","onwind","offwind"]:
if tech in o and "+" not in o:
limit = o[o.find(tech)+len(tech):]
limit = float(limit.replace("p",".").replace("m","-"))
print("changing potential for",tech,"by factor",limit)
restrict_technology_potential(n,tech,limit)
if o[:10] == 'linemaxext': if o[:10] == 'linemaxext':
maxext = float(o[10:])*1e3 maxext = float(o[10:])*1e3
@ -2169,28 +2047,31 @@ if __name__ == "__main__":
if snakemake.config["sector"]['electricity_distribution_grid']: if snakemake.config["sector"]['electricity_distribution_grid']:
insert_electricity_distribution_grid(n) insert_electricity_distribution_grid(n)
for o in opts: for o in opts:
if "+" in o: if "+" in o:
oo = o.split("+") oo = o.split("+")
carrier_list=np.hstack((n.generators.carrier.unique(), n.links.carrier.unique(), carrier_list=np.hstack((n.generators.carrier.unique(), n.links.carrier.unique(),
n.stores.carrier.unique(), n.storage_units.carrier.unique())) n.stores.carrier.unique(), n.storage_units.carrier.unique()))
suptechs = map(lambda c: c.split("-", 2)[0], carrier_list) suptechs = map(lambda c: c.split("-", 2)[0], carrier_list)
if oo[0].startswith(tuple(suptechs)): if oo[0].startswith(tuple(suptechs)):
carrier = oo[0] carrier = oo[0]
# handles only p_nom_max as stores and lines have no potentials
attr_lookup = {"p": "p_nom_max", "c": "capital_cost"} attr_lookup = {"p": "p_nom_max", "c": "capital_cost"}
attr = attr_lookup[oo[1][0]] attr = attr_lookup[oo[1][0]]
factor = float(oo[1][1:]) factor = float(oo[1][1:])
#beware if factor is 0 and p_nom_max is np.inf, 0*np.inf is nan
if carrier == "AC": # lines do not have carrier if carrier == "AC": # lines do not have carrier
n.lines[attr] *= factor n.lines[attr] *= factor
else: else:
comps = {"Generator", "Link", "StorageUnit", "Store"} comps = {"Generator", "Link", "StorageUnit"} if attr=='p_nom_max' else {"Generator", "Link", "StorageUnit", "Store"}
for c in n.iterate_components(comps): for c in n.iterate_components(comps):
sel = c.df.carrier.str.contains(carrier) if carrier=='solar':
sel = c.df.carrier.str.contains(carrier) & ~c.df.carrier.str.contains("solar rooftop")
else:
sel = c.df.carrier.str.contains(carrier)
c.df.loc[sel,attr] *= factor c.df.loc[sel,attr] *= factor
print("changing", attr ,"for",carrier,"by factor",factor) print("changing", attr ,"for",carrier,"by factor",factor)
if snakemake.config["sector"]['gas_distribution_grid']: if snakemake.config["sector"]['gas_distribution_grid']:
insert_gas_distribution_costs(n) insert_gas_distribution_costs(n)
if snakemake.config["sector"]['electricity_grid_connection']: if snakemake.config["sector"]['electricity_grid_connection']: