Make directory for costs files configurable

Default to parallel directory for technology_data repository.
This commit is contained in:
Tom Brown 2020-07-30 08:27:33 +02:00
parent ece21bfdfa
commit b57a6c18f8
3 changed files with 83 additions and 89 deletions

68
Snakefile Executable file → Normal file
View File

@ -15,13 +15,13 @@ subworkflow pypsaeur:
workdir: "../pypsa-eur"
snakefile: "../pypsa-eur/Snakefile"
configfile: "../pypsa-eur/config.yaml"
rule all:
input:
input:
config['summary_dir'] + '/' + config['run'] + '/graphs/costs.pdf'
rule solve_all_elec_networks:
input:
expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}.nc",
@ -174,7 +174,7 @@ rule build_industrial_demand:
threads: 1
resources: mem_mb=1000
script: 'scripts/build_industrial_demand.py'
rule prepare_sector_network:
input:
@ -185,7 +185,7 @@ rule prepare_sector_network:
biomass_potentials='data/biomass_potentials.csv',
timezone_mappings='data/timezone_mappings.csv',
heat_profile="data/heat_load_profile_BDEW.csv",
costs="data/costs/costs_{planning_horizons}.csv", #"data/costs.csv"
costs=config['costs_dir'] + "costs_{planning_horizons}.csv", #"data/costs.csv"
co2_budget="data/co2_budget.csv",
clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv",
industrial_demand="resources/industrial_demand_{network}_s{simpl}_{clusters}.csv",
@ -265,7 +265,7 @@ rule make_summary:
resources: mem_mb=10000
script:
'scripts/make_summary.py'
rule plot_summary:
input:
@ -282,13 +282,13 @@ rule plot_summary:
'scripts/plot_summary.py'
if config["foresight"] == "overnight":
rule solve_network:
input:
network=config['results_dir'] + config['run'] + "/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc",
costs="data/costs/costs_{planning_horizons}.csv",
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
shadow: "shallow"
log:
solver="logs/" + config['run'] + "/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log",
@ -297,51 +297,51 @@ if config["foresight"] == "overnight":
benchmark: "benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}"
threads: 4
resources: mem_mb=config['solving']['mem']
# group: "solve" # with group, threads is ignored https://bitbucket.org/snakemake/snakemake/issues/971/group-job-description-does-not-contain
# group: "solve" # with group, threads is ignored https://bitbucket.org/snakemake/snakemake/issues/971/group-job-description-does-not-contain
script: "scripts/solve_network.py"
if config["foresight"] == "myopic":
if config["foresight"] == "myopic":
rule add_existing_baseyear:
input:
network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
costs="data/costs/costs_{}.csv".format(config['scenario']['planning_horizons'][0]),
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
costs=config['costs_dir'] + "costs_{}.csv".format(config['scenario']['planning_horizons'][0]),
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc"
output: config['results_dir'] + config['run'] + '/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc'
output: config['results_dir'] + config['run'] + '/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc'
wildcard_constraints:
planning_horizons=config['scenario']['planning_horizons'][0] #only applies to baseyear
threads: 1
resources: mem_mb=2000
resources: mem_mb=2000
script: "scripts/add_existing_baseyear.py"
def process_input(wildcards):
i = config["scenario"]["planning_horizons"].index(wildcards.planning_horizons)
return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_" + config["scenario"]["planning_horizons"][i-1] + ".nc"
return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_" + config["scenario"]["planning_horizons"][i-1] + ".nc"
rule add_brownfield:
input:
network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
network_p=process_input, #solved network at previous time step
costs="data/costs/costs_{planning_horizons}.csv",
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc"
output: config['results_dir'] + config['run'] + "/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
output: config['results_dir'] + config['run'] + "/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
threads: 4
resources: mem_mb=2000
resources: mem_mb=2000
script: "scripts/add_brownfield.py"
ruleorder: add_existing_baseyear > add_brownfield
ruleorder: add_existing_baseyear > add_brownfield
rule solve_network_myopic:
input:
network=config['results_dir'] + config['run'] + "/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc",
costs="data/costs/costs_{planning_horizons}.csv",
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
shadow: "shallow"
log:
solver="logs/" + config['run'] + "/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log",
@ -351,7 +351,3 @@ if config["foresight"] == "myopic":
threads: 4
resources: mem_mb=config['solving']['mem']
script: "scripts/solve_network.py"

7
config.default.yaml Executable file → Normal file
View File

@ -2,6 +2,7 @@ logging_level: INFO
results_dir: 'results/'
summary_dir: results
costs_dir: '../technology_data/outputs/'
run: 'your-run-name' # use this to keep track of runs with different settings
foresight: 'myopic' #options are overnight, myopic, perfect
@ -21,8 +22,8 @@ scenario:
# 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
planning_horizons : ['2020', '2030', '2040', '2050'] #timesteps for myopic and perfect
co2_budget_name: ['go']
planning_horizons : ['2020', '2030', '2040', '2050'] #timesteps for myopic and perfect
co2_budget_name: ['go']
# snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec
snapshots:
@ -49,7 +50,7 @@ biomass:
existing_capacities:
grouping_years: ['1980', '1985', '1990', '1995', '2000','2005','2010','2015', '2019']
threshold_capacity: 10
sector:
'central' : True
'central_fraction' : 0.6

View File

@ -41,16 +41,16 @@ override_component_attrs["Generator"].loc["build_year"] = ["integer","year",np.n
override_component_attrs["Generator"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
override_component_attrs["Store"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
def add_brownfield(n, n_p, year):
print("adding brownfield")
#first, remove generators, links and stores that track CO2 or global EU values
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list() if 'ror' in index])
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list() if 'ror' in index])
n_p.mremove("Generator", ['EU fossil gas', 'fossil oil'] )
n_p.mremove("Store", ['co2 atmosphere', 'co2 stored', 'EU gas Store'] )
n_p.mremove("Link", ['co2 vent'] )
if "H" in opts:
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'water tanks charger' in index])
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'water tanks discharger' in index])
@ -64,31 +64,31 @@ def add_brownfield(n, n_p, year):
n_p.mremove("Store", [index for index in n_p.stores.index.to_list() if 'battery storage' in index])
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'BEV charger' in index])
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'V2G' in index])
previous_timestep=snakemake.config['scenario']['planning_horizons'][snakemake.config['scenario']['planning_horizons'].index(year)-1]
previous_timesteps=snakemake.config['scenario']['planning_horizons'][0:snakemake.config['scenario']['planning_horizons'].index(year)]
grouping_years=snakemake.config['existing_capacities']['grouping_years']
### GENERATORS ###
# generators whose build_year + lifetime < year are removed
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
if (n_p.generators.loc[index, 'build_year']+n_p.generators.loc[index, 'lifetime'] < int(year))])
# remove generators if their optimized nominal capacity is lower than a threshold
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
if (n_p.generators.loc[index, 'p_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
# generators whose capacity was optimized in the previous year are renamed and build year is added
n_p.generators.index=np.where(n_p.generators.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
n_p.generators.index + '-' + previous_timestep,
n_p.generators.index + '-' + previous_timestep,
n_p.generators.index)
n_p.generators.loc[[index for index in n_p.generators.index.to_list()
if previous_timestep in index], 'build_year']=int(previous_timestep)
#add generators from previous step
n.madd("Generator",
#add generators from previous step
n.madd("Generator",
n_p.generators.index,
bus=n_p.generators.bus,
carrier=n_p.generators.carrier,
@ -99,24 +99,24 @@ def add_brownfield(n, n_p, year):
p_max_pu=n_p.generators_t.p_max_pu,
build_year=n_p.generators.build_year,
lifetime=n_p.generators.lifetime)
### STORES ###
# stores whose installationYear + lifetime < year are removed
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
if (n_p.stores.loc[index, 'build_year']+n_p.stores.loc[index, 'lifetime'] < int(year))])
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
if (n_p.stores.loc[index, 'build_year']+n_p.stores.loc[index, 'lifetime'] < int(year))])
# remove stores if their optimized nominal capacity is lower than a threshold
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
if (n_p.stores.loc[index, 'e_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
# stores whose capacity was optimized in the previous year are renamed and the build year is added
n_p.stores.index=np.where(n_p.stores.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
n_p.stores.index + '-' + previous_timestep,
n_p.stores.index + '-' + previous_timestep,
n_p.stores.index)
n_p.stores.loc[[index for index in n_p.stores.index.to_list()
if previous_timestep in index], 'build_year']=int(previous_timestep)
#add stores from previous steps
n.madd("Store",
n.madd("Store",
n_p.stores.index,
bus=n_p.stores.bus,
carrier=n_p.stores.carrier,
@ -125,27 +125,27 @@ def add_brownfield(n, n_p, year):
capital_cost=n_p.stores.capital_cost,
build_year=n_p.stores.build_year,
lifetime=n_p.stores.lifetime)
### LINKS ###
# TODO: add_chp_constraint() in solve_network needs to be adjusted
### LINKS ###
# TODO: add_chp_constraint() in solve_network needs to be adjusted
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'CHP' in index])
# links whose installationYear + lifetime < year are removed
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
if (n_p.links.loc[index, 'build_year']+n_p.links.loc[index, 'lifetime'] < int(year))])
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
if (n_p.links.loc[index, 'build_year']+n_p.links.loc[index, 'lifetime'] < int(year))])
# delete links if their optimized nominal capacity is lower than a threshold
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
if (n_p.links.loc[index, 'p_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
# links whose capacity was optimized in the previous year are renamed and the build year is added
n_p.links.index=np.where(n_p.links.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
n_p.links.index + '-' + previous_timestep,
n_p.links.index + '-' + previous_timestep,
n_p.links.index)
n_p.links.loc[[index for index in n_p.links.index.to_list()
if previous_timestep in index], 'build_year']=int(previous_timestep)
#add links from previous steps
n.madd("Link",
n.madd("Link",
n_p.links.index,
bus0=n_p.links.bus0,
bus1=n_p.links.bus1,
@ -158,23 +158,23 @@ def add_brownfield(n, n_p, year):
efficiency2=n_p.links.efficiency2,
build_year=n_p.links.build_year,
lifetime=n_p.links.lifetime)
if __name__ == "__main__":
# Detect running outside of snakemake and mock snakemake for testing
if 'snakemake' not in globals():
from vresutils.snakemake import MockSnakemake
snakemake = MockSnakemake(
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1',
co2_budget_name='go',
planning_horizons='2030'),
input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
network_p='pypsa-eur-sec/results/test/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_2020.nc',
input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
network_p='pypsa-eur-sec/results/test/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_2020.nc',
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
cop_air_total="pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc",
cop_soil_total="pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc"),
output=['pypsa-eur-sec/results/test/prenetworks_brownfied/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc']
cop_soil_total="pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc"),
output=['pypsa-eur-sec/results/test/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc']
)
import yaml
with open('config.yaml') as f:
@ -185,28 +185,25 @@ if __name__ == "__main__":
options = snakemake.config["sector"]
opts = snakemake.wildcards.sector_opts.split('-')
year=snakemake.wildcards.planning_horizons
n = pypsa.Network(snakemake.input.network,
override_component_attrs=override_component_attrs)
n_p = pypsa.Network(snakemake.input.network_p,
override_component_attrs=override_component_attrs)
#%%
add_brownfield(n, n_p, year)
Nyears = n.snapshot_weightings.sum()/8760.
costs = prepare_costs(snakemake.input.costs,
snakemake.config['costs']['USD2013_to_EUR2013'],
snakemake.config['costs']['discountrate'],
Nyears)
baseyear = snakemake.config['scenario']["planning_horizons"][0]
n.export_to_netcdf(snakemake.output[0])