Merge branch 'master' into retro

This commit is contained in:
Tom Brown 2020-11-30 17:07:43 +01:00
commit 974155bd46
15 changed files with 279 additions and 575 deletions

View File

@ -25,17 +25,12 @@ rule all:
rule solve_all_networks:
input:
expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc",
expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc",
**config['scenario'])
rule test_script:
input:
expand("resources/heat_demand_urban_elec_s_{clusters}.nc",
**config['scenario'])
rule prepare_sector_networks:
input:
expand(config['results_dir'] + config['run'] + "/prenetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc",
expand(config['results_dir'] + config['run'] + "/prenetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc",
**config['scenario'])
@ -313,10 +308,10 @@ rule prepare_sector_network:
heat_profile="data/heat_load_profile_BDEW.csv",
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
h2_cavern = "data/hydrogen_salt_cavern_potentials.csv",
co2_budget="data/co2_budget.csv",
profile_offwind_ac=pypsaeur("resources/profile_offwind-ac.nc"),
profile_offwind_dc=pypsaeur("resources/profile_offwind-dc.nc"),
clustermaps=pypsaeur('resources/clustermaps_{network}_s{simpl}_{clusters}.h5'),
busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"),
busmap=pypsaeur("resources/busmap_{network}_s{simpl}_{clusters}.csv"),
clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv",
simplified_pop_layout="resources/pop_layout_{network}_s{simpl}.csv",
industrial_demand="resources/industrial_energy_demand_{network}_s{simpl}_{clusters}.csv",
@ -340,20 +335,20 @@ rule prepare_sector_network:
solar_thermal_rural="resources/solar_thermal_rural_{network}_s{simpl}_{clusters}.nc",
retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv",
floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv"
output: config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc'
output: config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc'
threads: 1
resources: mem_mb=2000
benchmark: config['results_dir'] + config['run'] + "/benchmarks/prepare_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}"
benchmark: config['results_dir'] + config['run'] + "/benchmarks/prepare_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}"
script: "scripts/prepare_sector_network.py"
rule plot_network:
input:
network=config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
network=config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc"
output:
map=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{co2_budget_name}_{planning_horizons}.pdf",
today=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}-today.pdf"
map=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{planning_horizons}.pdf",
today=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}-today.pdf"
threads: 2
resources: mem_mb=10000
script: "scripts/plot_network.py"
@ -370,10 +365,10 @@ rule copy_config:
rule make_summary:
input:
networks=expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc",
networks=expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc",
**config['scenario']),
costs=config['costs_dir'] + "costs_{}.csv".format(config['scenario']['planning_horizons'][0]),
plots=expand(config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{co2_budget_name}_{planning_horizons}.pdf",
plots=expand(config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{planning_horizons}.pdf",
**config['scenario'])
#heat_demand_name='data/heating/daily_heat_demand.h5'
output:
@ -416,16 +411,16 @@ 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",
network=config['results_dir'] + config['run'] + "/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc",
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
config=config['summary_dir'] + '/' + config['run'] + '/configs/config.yaml'
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc"
shadow: "shallow"
log:
solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log",
python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_python.log",
memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_memory.log"
benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}"
solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_solver.log",
python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_python.log",
memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_memory.log"
benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{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
@ -436,14 +431,15 @@ 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',
network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc',
powerplants=pypsaeur('resources/powerplants.csv'),
clustermaps=pypsaeur('resources/clustermaps_{network}_s{simpl}_{clusters}.h5'),
busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"),
busmap=pypsaeur("resources/busmap_{network}_s{simpl}_{clusters}.csv"),
clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv",
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}_{planning_horizons}.nc'
wildcard_constraints:
planning_horizons=config['scenario']['planning_horizons'][0] #only applies to baseyear
threads: 1
@ -452,36 +448,36 @@ if config["foresight"] == "myopic":
def process_input(wildcards):
i = config["scenario"]["planning_horizons"].index(int(wildcards.planning_horizons))
return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_" + str(config["scenario"]["planning_horizons"][i-1]) + ".nc"
return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_" + str(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=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc',
network_p=process_input, #solved network at previous time step
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}_{planning_horizons}.nc"
threads: 4
resources: mem_mb=2000
resources: mem_mb=10000
script: "scripts/add_brownfield.py"
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",
network=config['results_dir'] + config['run'] + "/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc",
costs=config['costs_dir'] + "costs_{planning_horizons}.csv",
config=config['summary_dir'] + '/' + config['run'] + '/configs/config.yaml'
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc"
output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc"
shadow: "shallow"
log:
solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log",
python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_python.log",
memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_memory.log"
benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}"
solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_solver.log",
python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_python.log",
memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_memory.log"
benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}"
threads: 4
resources: mem_mb=config['solving']['mem']
script: "scripts/solve_network.py"

View File

@ -6,8 +6,8 @@ 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: 'overnight' #options are overnight, myopic, perfect (perfect is not yet implemented)
foresight: 'overnight' # options are overnight, myopic, perfect (perfect is not yet implemented)
# if you use myopic or perfect foresight, set the investment years in "planning_horizons" below
scenario:
sectors: [E] # ignore this legacy setting
@ -24,8 +24,19 @@ 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 : [2030] #investment years for myopic and perfect; or costs year for overnight
co2_budget_name: ['go'] #gives shape of CO2 budgets over planning horizon
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
# CO2 budget as a fraction of 1990 emissions
# this is over-ridden if CO2Lx is set in sector_opts
co2_budget:
2020: 0.7011648746
2025: 0.5241935484
2030: 0.2970430108
2035: 0.1500896057
2040: 0.0712365591
2045: 0.0322580645
2050: 0
# snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec
snapshots:
@ -62,8 +73,8 @@ existing_capacities:
sector:
'central' : True
'central_fraction' : 0.6
'dsm_restriction_value' : 0.75 #Set to 0 for no restriction on BEV DSM
'dsm_restriction_time' : 7 #Time at which SOC of BEV has to be dsm_restriction_value
'bev_dsm_restriction_value' : 0.75 #Set to 0 for no restriction on BEV DSM
'bev_dsm_restriction_time' : 7 #Time at which SOC of BEV has to be dsm_restriction_value
'transport_heating_deadband_upper' : 20.
'transport_heating_deadband_lower' : 15.
'ICE_lower_degree_factor' : 0.375 #in per cent increase in fuel consumption per degree above deadband
@ -71,10 +82,22 @@ sector:
'EV_lower_degree_factor' : 0.98
'EV_upper_degree_factor' : 0.63
'district_heating_loss' : 0.15
'bev' : True #turns on EV battery
'bev_dsm' : True #turns on EV battery
'bev_availability' : 0.5 #How many cars do smart charging
'v2g' : True #allows feed-in to grid from EV battery
'transport_fuel_cell_share' : 0. #0 means all EVs, 1 means all FCs
#what is not EV or FCEV is fossil-fuelled
'land_transport_fuel_cell_share': # 1 means all FCEVs
2020: 0
2030: 0.05
2040: 0.1
2050: 0.15
'land_transport_electric_share': # 1 means all EVs
2020: 0
2030: 0.25
2040: 0.6
2050: 0.85
'transport_fuel_cell_efficiency': 0.5
'transport_internal_combustion_efficiency': 0.3
'shipping_average_efficiency' : 0.4 #For conversion of fuel oil to propulsion in 2011
'time_dep_hp_cop' : True
'space_heating_fraction' : 1.0 #fraction of space heating active
@ -93,6 +116,7 @@ sector:
'boilers' : True
'oil_boilers': False
'chp' : True
'micro_chp' : False
'solar_thermal' : True
'solar_cf_correction': 0.788457 # = >>> 1/1.2683
'marginal_cost_storage' : 0. #1e-4
@ -112,7 +136,6 @@ sector:
'gas_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv
costs:
year: 2030
lifetime: 25 #default lifetime
# From a Lion Hirth paper, also reflects average of Noothout et al 2016
discountrate: 0.07
@ -171,7 +194,7 @@ solving:
industry:
'St_primary_fraction' : 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6
'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279
'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from 51kgH2/tSt in Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279
'elec_DRI' : 0.322 #electricity consumption in Direct Reduced Iron (DRI) shaft, MWh/tSt HYBRIT brochure https://ssabwebsitecdn.azureedge.net/-/media/hybrit/files/hybrit_brochure.pdf
'Al_primary_fraction' : 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4
'MWh_CH4_per_tNH3_SMR' : 10.8 # 2012's demand from https://ec.europa.eu/docsroom/documents/4165/attachments/1/translations/en/renditions/pdf
@ -180,6 +203,7 @@ industry:
'MWh_elec_per_tNH3_electrolysis' : 1.17 # from https://doi.org/10.1016/j.joule.2018.04.017 Table 13 (air separation and HB)
'NH3_process_emissions' : 24.5 # in MtCO2/a from SMR for H2 production for NH3 from UNFCCC for 2015 for EU28
'petrochemical_process_emissions' : 25.5 # in MtCO2/a for petrochemical and other from UNFCCC for 2015 for EU28
'HVC_primary_fraction' : 1.0 #fraction of current non-ammonia basic chemicals produced via primary route
plotting:
map:
@ -286,6 +310,7 @@ plotting:
"Fischer-Tropsch" : "#44DD33"
"kerosene for aviation": "#44BB11"
"naphtha for industry" : "#44FF55"
"land transport fossil" : "#44DD33"
"water tanks" : "#BBBBBB"
"hot water storage" : "#BBBBBB"
"hot water charging" : "#BBBBBB"
@ -297,7 +322,6 @@ plotting:
"Ambient" : "k"
"Electric load" : "b"
"Heat load" : "r"
"Transport load" : "grey"
"heat" : "darkred"
"rural heat" : "#880000"
"central heat" : "#b22222"
@ -312,15 +336,16 @@ plotting:
"building retrofitting" : "purple"
"BEV charger" : "grey"
"V2G" : "grey"
"transport" : "grey"
"land transport EV" : "grey"
"electricity" : "k"
"gas for industry" : "#333333"
"solid biomass for industry" : "#555555"
"industry electricity" : "#222222"
"industry new electricity" : "#222222"
"process emissions to stored" : "#444444"
"process emissions to atmosphere" : "#888888"
"process emissions" : "#222222"
"transport fuel cell" : "#AAAAAA"
"land transport fuel cell" : "#AAAAAA"
"biogas" : "#800000"
"solid biomass" : "#DAA520"
"today" : "#D2691E"

View File

@ -1,346 +0,0 @@
version: 0.3.0
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 (perfect is not yet implemented)
scenario:
sectors: [E] # ignore this legacy setting
simpl: [''] # only relevant for PyPSA-Eur
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
opts: [''] # only relevant for PyPSA-Eur
sector_opts: [Co2L0-3H-H-B-solar3-dist1] # this is where the main scenario settings are
# 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%);
# 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
# single letters are sectors: T for land transport, H for building heating,
# 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] #investment years for myopic and perfect; or costs year for overnight
co2_budget_name: ['go'] #gives shape of CO2 budgets over planning horizon
# snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec
snapshots:
# arguments to pd.date_range
start: "2013-01-01"
end: "2014-01-01"
closed: 'left' # end is not inclusive
atlite:
cutout_dir: '../pypsa-eur/cutouts'
cutout_name: "europe-2013-era5"
# this information is NOT used but needed as an argument for
# pypsa-eur/scripts/add_electricity.py/load_costs in make_summary.py
electricity:
max_hours:
battery: 6
H2: 168
biomass:
year: 2030
scenario: "Med"
classes:
solid biomass: ['Primary agricultural residues', 'Forestry energy residue', 'Secondary forestry residues', 'Secondary Forestry residues sawdust', 'Forestry residues from landscape care biomass', 'Municipal waste']
not included: ['Bioethanol sugar beet biomass', 'Rapeseeds for biodiesel', 'sunflower and soya for Biodiesel', 'Starchy crops biomass', 'Grassy crops biomass', 'Willow biomass', 'Poplar biomass potential', 'Roundwood fuelwood', 'Roundwood Chips & Pellets']
biogas: ['Manure biomass potential', 'Sludge biomass']
# only relevant for foresight = myopic or perfect
existing_capacities:
grouping_years: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019]
threshold_capacity: 10
conventional_carriers: ['lignite', 'coal', 'oil', 'uranium']
sector:
'central' : True
'central_fraction' : 0.6
'dsm_restriction_value' : 0.75 #Set to 0 for no restriction on BEV DSM
'dsm_restriction_time' : 7 #Time at which SOC of BEV has to be dsm_restriction_value
'transport_heating_deadband_upper' : 20.
'transport_heating_deadband_lower' : 15.
'ICE_lower_degree_factor' : 0.375 #in per cent increase in fuel consumption per degree above deadband
'ICE_upper_degree_factor' : 1.6
'EV_lower_degree_factor' : 0.98
'EV_upper_degree_factor' : 0.63
'district_heating_loss' : 0.15
'bev' : True #turns on EV battery
'bev_availability' : 0.5 #How many cars do smart charging
'v2g' : True #allows feed-in to grid from EV battery
'transport_fuel_cell_share' : 0. #0 means all EVs, 1 means all FCs
'shipping_average_efficiency' : 0.4 #For conversion of fuel oil to propulsion in 2011
'time_dep_hp_cop' : True
'space_heating_fraction' : 1.0 #fraction of space heating active
'retrofitting' :
'retro_exogen': True # space heat demand savings exogenously
'dE': [0.0, 0.1, 0.2, 0.5] # reduction of space heat demand per year (applied before losses in DH)
'retro_endogen': False # co-optimise space heat savings
'cost_factor' : 1.0
'interest_rate': 0.04 # for investment in building components
'annualise_cost': True # annualise the investment costs
'tax_weighting': False # weight costs depending on taxes in countries
'construction_index': True # weight costs depending on labour/material costs per ct
'l_strength': ["0.076", "0.197"] # additional insulation thickness[m], determines number of retro steps(=generators per bus) and maximum possible savings
'tes' : True
'tes_tau' : 3.
'boilers' : True
'oil_boilers': False
'chp' : True
'solar_thermal' : True
'solar_cf_correction': 0.788457 # = >>> 1/1.2683
'marginal_cost_storage' : 0. #1e-4
'methanation' : True
'helmeth' : True
'dac' : True
'co2_vent' : True
'SMR' : True
'ccs_fraction' : 0.9
'hydrogen_underground_storage' : True
'use_fischer_tropsch_waste_heat' : True
'use_fuel_cell_waste_heat' : True
'electricity_distribution_grid' : False
'electricity_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv
'electricity_grid_connection' : True # only applies to onshore wind and utility PV
'gas_distribution_grid' : True
'gas_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv
costs:
year: 2030
lifetime: 25 #default lifetime
# From a Lion Hirth paper, also reflects average of Noothout et al 2016
discountrate: 0.07
# [EUR/USD] ECB: https://www.ecb.europa.eu/stats/exchange/eurofxref/html/eurofxref-graph-usd.en.html # noqa: E501
USD2013_to_EUR2013: 0.7532
# Marginal and capital costs can be overwritten
# capital_cost:
# Wind: Bla
marginal_cost: #
solar: 0.01
onwind: 0.015
offwind: 0.015
hydro: 0.
H2: 0.
battery: 0.
emission_prices: # only used with the option Ep (emission prices)
co2: 0.
lines:
length_factor: 1.25 #to estimate offwind connection costs
solving:
#tmpdir: "path/to/tmp"
options:
formulation: kirchhoff
clip_p_max_pu: 1.e-2
load_shedding: false
noisy_costs: true
min_iterations: 1
max_iterations: 1
# nhours: 1
solver:
name: gurobi
threads: 4
method: 2 # barrier
crossover: 0
BarConvTol: 1.e-5
Seed: 123
AggFill: 0
PreDual: 0
GURO_PAR_BARDENSETHRESH: 200
#FeasibilityTol: 1.e-6
#name: cplex
#threads: 4
#lpmethod: 4 # barrier
#solutiontype: 2 # non basic solution, ie no crossover
#barrier_convergetol: 1.e-5
#feasopt_tolerance: 1.e-6
mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2
industry:
'St_primary_fraction' : 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6
'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279
'elec_DRI' : 0.322 #electricity consumption in Direct Reduced Iron (DRI) shaft, MWh/tSt HYBRIT brochure https://ssabwebsitecdn.azureedge.net/-/media/hybrit/files/hybrit_brochure.pdf
'Al_primary_fraction' : 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4
'MWh_CH4_per_tNH3_SMR' : 10.8 # 2012's demand from https://ec.europa.eu/docsroom/documents/4165/attachments/1/translations/en/renditions/pdf
'MWh_elec_per_tNH3_SMR' : 0.7 # same source, assuming 94-6% split methane-elec of total energy demand 11.5 MWh/tNH3
'MWh_H2_per_tNH3_electrolysis' : 6.5 # from https://doi.org/10.1016/j.joule.2018.04.017, around 0.197 tH2/tHN3 (>3/17 since some H2 lost and used for energy)
'MWh_elec_per_tNH3_electrolysis' : 1.17 # from https://doi.org/10.1016/j.joule.2018.04.017 Table 13 (air separation and HB)
'NH3_process_emissions' : 24.5 # in MtCO2/a from SMR for H2 production for NH3 from UNFCCC for 2015 for EU28
'petrochemical_process_emissions' : 25.5 # in MtCO2/a for petrochemical and other from UNFCCC for 2015 for EU28
plotting:
map:
figsize: [7, 7]
boundaries: [-10.2, 29, 35, 72]
p_nom:
bus_size_factor: 5.e+4
linewidth_factor: 3.e+3 # 1.e+3 #3.e+3
costs_max: 1200
costs_threshold: 1
energy_max: 20000.
energy_min: -15000.
energy_threshold: 50.
vre_techs: ["onwind", "offwind-ac", "offwind-dc", "solar", "ror"]
renewable_storage_techs: ["PHS","hydro"]
conv_techs: ["OCGT", "CCGT", "Nuclear", "Coal"]
storage_techs: ["hydro+PHS", "battery", "H2"]
# store_techs: ["Li ion", "water tanks"]
load_carriers: ["AC load"] #, "heat load", "Li ion load"]
AC_carriers: ["AC line", "AC transformer"]
link_carriers: ["DC line", "Converter AC-DC"]
heat_links: ["heat pump", "resistive heater", "CHP heat", "CHP electric",
"gas boiler", "central heat pump", "central resistive heater", "central CHP heat",
"central CHP electric", "central gas boiler"]
heat_generators: ["gas boiler", "central gas boiler", "solar thermal collector", "central solar thermal collector"]
tech_colors:
"onwind" : "b"
"onshore wind" : "b"
'offwind' : "c"
'offshore wind' : "c"
'offwind-ac' : "c"
'offshore wind (AC)' : "c"
'offwind-dc' : "#009999"
'offshore wind (DC)' : "#009999"
'wave' : "#004444"
"hydro" : "#3B5323"
"hydro reservoir" : "#3B5323"
"ror" : "#78AB46"
"run of river" : "#78AB46"
'hydroelectricity' : '#006400'
'solar' : "y"
'solar PV' : "y"
'solar thermal' : 'coral'
'solar rooftop' : '#e6b800'
"OCGT" : "wheat"
"OCGT marginal" : "sandybrown"
"OCGT-heat" : "orange"
"gas boiler" : "orange"
"gas boilers" : "orange"
"gas boiler marginal" : "orange"
"gas-to-power/heat" : "orange"
"gas" : "brown"
"natural gas" : "brown"
"SMR" : "#4F4F2F"
"oil" : "#B5A642"
"oil boiler" : "#B5A677"
"lines" : "k"
"transmission lines" : "k"
"H2" : "m"
"hydrogen storage" : "m"
"battery" : "slategray"
"battery storage" : "slategray"
"home battery" : "#614700"
"home battery storage" : "#614700"
"Nuclear" : "r"
"Nuclear marginal" : "r"
"nuclear" : "r"
"uranium" : "r"
"Coal" : "k"
"coal" : "k"
"Coal marginal" : "k"
"Lignite" : "grey"
"lignite" : "grey"
"Lignite marginal" : "grey"
"CCGT" : "orange"
"CCGT marginal" : "orange"
"heat pumps" : "#76EE00"
"heat pump" : "#76EE00"
"air heat pump" : "#76EE00"
"ground heat pump" : "#40AA00"
"power-to-heat" : "#40AA00"
"resistive heater" : "pink"
"Sabatier" : "#FF1493"
"methanation" : "#FF1493"
"power-to-gas" : "#FF1493"
"power-to-liquid" : "#FFAAE9"
"helmeth" : "#7D0552"
"helmeth" : "#7D0552"
"DAC" : "#E74C3C"
"co2 stored" : "#123456"
"CO2 sequestration" : "#123456"
"CCS" : "k"
"co2" : "#123456"
"co2 vent" : "#654321"
"solid biomass for industry co2 from atmosphere" : "#654321"
"solid biomass for industry co2 to stored": "#654321"
"gas for industry co2 to atmosphere": "#654321"
"gas for industry co2 to stored": "#654321"
"Fischer-Tropsch" : "#44DD33"
"kerosene for aviation": "#44BB11"
"naphtha for industry" : "#44FF55"
"water tanks" : "#BBBBBB"
"hot water storage" : "#BBBBBB"
"hot water charging" : "#BBBBBB"
"hot water discharging" : "#999999"
"CHP" : "r"
"CHP heat" : "r"
"CHP electric" : "r"
"PHS" : "g"
"Ambient" : "k"
"Electric load" : "b"
"Heat load" : "r"
"Transport load" : "grey"
"heat" : "darkred"
"rural heat" : "#880000"
"central heat" : "#b22222"
"decentral heat" : "#800000"
"low-temperature heat for industry" : "#991111"
"process heat" : "#FF3333"
"heat demand" : "darkred"
"electric demand" : "k"
"Li ion" : "grey"
"district heating" : "#CC4E5C"
"retrofitting" : "purple"
"building retrofitting" : "purple"
"BEV charger" : "grey"
"V2G" : "grey"
"transport" : "grey"
"electricity" : "k"
"gas for industry" : "#333333"
"solid biomass for industry" : "#555555"
"industry new electricity" : "#222222"
"process emissions to stored" : "#444444"
"process emissions to atmosphere" : "#888888"
"process emissions" : "#222222"
"transport fuel cell" : "#AAAAAA"
"biogas" : "#800000"
"solid biomass" : "#DAA520"
"today" : "#D2691E"
"shipping" : "#6495ED"
"electricity distribution grid" : "#333333"
nice_names:
# OCGT: "Gas"
# OCGT marginal: "Gas (marginal)"
offwind: "offshore wind"
onwind: "onshore wind"
battery: "Battery storage"
lines: "Transmission lines"
AC line: "AC lines"
AC-AC: "DC lines"
ror: "Run of river"
nice_names_n:
offwind: "offshore\nwind"
onwind: "onshore\nwind"
# OCGT: "Gas"
H2: "Hydrogen\nstorage"
# OCGT marginal: "Gas (marginal)"
lines: "transmission\nlines"
ror: "run of river"

View File

@ -1,8 +0,0 @@
,go,wait
2020,0.7011648746,0.7011648746
2025,0.5241935484,0.6285842294
2030,0.2970430108,0.3503584229
2035,0.1500896057,0.0725806452
2040,0.0712365591,0
2045,0.0322580645,0
2050,0,0
1 go wait
2 2020 0.7011648746 0.7011648746
3 2025 0.5241935484 0.6285842294
4 2030 0.2970430108 0.3503584229
5 2035 0.1500896057 0.0725806452
6 2040 0.0712365591 0
7 2045 0.0322580645 0
8 2050 0 0

View File

@ -78,27 +78,26 @@ For example:
Electricity network: nodal.
Electricity demand: nodal, distributed in each country based on
population and GDP.
population, GDP and location of industrial facilities.
Building heating demand: nodal, distributed in each country based on
population.
Industry demand: nodal, distributed in each country based on
population (will be corrected to real locations of industry, see
github issue).
locations of industry from `HotMaps database <https://gitlab.com/hotmaps/industrial_sites/industrial_sites_Industrial_Database>`_.
Hydrogen network: nodal.
Methane network: copper-plated for Europe, since future demand is so
Methane network: single node for Europe, since future demand is so
low and no bottlenecks are expected.
Solid biomass: copper-plated until transport costs can be
Solid biomass: single node for Europe, until transport costs can be
incorporated.
CO2: copper-plated (but a transport and storage cost is added for
sequestered CO2).
CO2: single node for Europe, but a transport and storage cost is added for
sequestered CO2.
Liquid hydrocarbons: copper-plated since transport costs are low.
Liquid hydrocarbons: single node for Europe, since transport costs are low.

View File

@ -17,12 +17,14 @@ See also other `outstanding issues <https://github.com/PyPSA/pypsa-eur-sec/issue
Configuration
=================
PyPSA-Eur-Sec has several configuration options which are collected in a config.yaml file located in the root directory. For myopic optimization, users should copy the provided myopic configuration ``config.myopic.yaml`` and make their own modifications and assumptions in the user-specific configuration file (``config.yaml``).
PyPSA-Eur-Sec has several configuration options which are collected in a config.yaml file located in the root directory. For myopic optimization, users should copy the provided default configuration ``config.default.yaml`` and make their own modifications and assumptions in the user-specific configuration file (``config.yaml``).
The following options included in the config.yaml file are relevant for the myopic code.
To activate the myopic option select ``foresight: 'myopic'`` in ``config.yaml``.
To set the investment years which are sequentially simulated for the myopic investment planning, select for example ``planning_horizons : [2020, 2030, 2040, 2050]`` in ``config.yaml``.
**existing capacities**

View File

@ -7,3 +7,5 @@ Overnight (greenfield) scenarios
The default is to calculate a rebuilding of the energy system to meet demand, a so-called overnight or greenfield approach.
For this, use ``foresight : 'overnight'`` in ``config.yaml``, like the example in ``config.default.yaml``.
In this case, the ``planning_horizons : [2030]`` scenario parameter can be set to use the year from which cost and other technology assumptions are set (forecasts for 2030 in this case).

View File

@ -170,10 +170,8 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas
df_agg.Fueltype = df_agg.Fueltype.map(rename_fuel)
#assign clustered bus
busmap_s = pd.read_hdf(snakemake.input.clustermaps,
key="/busmap_s")
busmap = pd.read_hdf(snakemake.input.clustermaps,
key="/busmap")
busmap_s = pd.read_csv(snakemake.input.busmap_s, index_col=0).squeeze()
busmap = pd.read_csv(snakemake.input.busmap, index_col=0).squeeze()
clustermaps = busmap_s.map(busmap)
clustermaps.index = clustermaps.index.astype(int)
@ -416,7 +414,8 @@ if __name__ == "__main__":
planning_horizons='2020'),
input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
powerplants='pypsa-eur/resources/powerplants.csv',
clustermaps='pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5',
busmap_s='pypsa-eur/resources/busmap_{network}_s{simpl}.csv',
busmap='pypsa-eur/resources/busmap_{network}_s{simpl}_{clusters}.csv',
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"),
@ -443,7 +442,8 @@ if __name__ == "__main__":
costs = prepare_costs(snakemake.input.costs,
snakemake.config['costs']['USD2013_to_EUR2013'],
snakemake.config['costs']['discountrate'],
Nyears)
Nyears,
snakemake.config['costs']['lifetime'])
grouping_years=snakemake.config['existing_capacities']['grouping_years']
add_power_capacities_installed_before_baseyear(n, grouping_years, costs, baseyear)

View File

@ -378,12 +378,12 @@ def build_energy_totals():
clean_df.loc[missing,"total aviation passenger"] = clean_df.loc[missing,["total domestic aviation passenger","total international aviation passenger"]].sum(axis=1)
clean_df.loc[missing,"total aviation freight"] = clean_df.loc[missing,["total domestic aviation freight","total international aviation freight"]].sum(axis=1)
if "BA" in clean_df.index:
#fix missing data for BA (services and road energy data)
missing = (clean_df.loc["BA"] == 0.)
#fix missing data for BA (services and road energy data)
missing = (clean_df.loc["BA"] == 0.)
#add back in proportional to RS with ratio of total residential demand
clean_df.loc["BA",missing] = clean_df.loc["BA","total residential"]/clean_df.loc["RS","total residential"]*clean_df.loc["RS",missing]
#add back in proportional to RS with ratio of total residential demand
clean_df.loc["BA",missing] = clean_df.loc["BA","total residential"]/clean_df.loc["RS","total residential"]*clean_df.loc["RS",missing]
clean_df.to_csv(snakemake.output.energy_name)

View File

@ -22,6 +22,8 @@ fraction_primary_stays_primary = snakemake.config["industry"]["Al_primary_fracti
industrial_production["Aluminium - primary production"] = fraction_primary_stays_primary*industrial_production["Aluminium - primary production"]
industrial_production["Aluminium - secondary production"] = total_aluminium - industrial_production["Aluminium - primary production"]
industrial_production["Basic chemicals (without ammonia)"] *= snakemake.config["industry"]['HVC_primary_fraction']
industrial_production.to_csv(snakemake.output.industrial_production_per_country_tomorrow,
float_format='%.2f')

View File

@ -186,14 +186,6 @@ def calculate_costs(n,label,costs):
costs.loc[marginal_costs_grouped.index,label] = marginal_costs_grouped
#add back in costs of links if there is a line volume limit
if label[1] != "opt":
costs.loc[("links-added","capital","transmission lines"),label] = ((costs_db.at['HVDC overhead', 'fixed']*n.links.length + costs_db.at['HVDC inverter pair', 'fixed'])*n.links.p_nom_opt)[n.links.carrier == "DC"].sum()
costs.loc[("lines-added","capital","transmission lines"),label] = costs_db.at["HVAC overhead", "fixed"]*(n.lines.length*n.lines.s_nom_opt).sum()
else:
costs.loc[("links-added","capital","transmission lines"),label] = (costs_db.at['HVDC inverter pair', 'fixed']*n.links.p_nom_opt)[n.links.carrier == "DC"].sum()
#add back in all hydro
#costs.loc[("storage_units","capital","hydro"),label] = (0.01)*2e6*n.storage_units.loc[n.storage_units.group=="hydro","p_nom"].sum()
#costs.loc[("storage_units","capital","PHS"),label] = (0.01)*2e6*n.storage_units.loc[n.storage_units.group=="PHS","p_nom"].sum()
@ -530,7 +522,7 @@ outputs = ["nodal_costs",
def make_summaries(networks_dict):
columns = pd.MultiIndex.from_tuples(networks_dict.keys(),names=["cluster","lv","opt", "co2_budget_name","planning_horizon"])
columns = pd.MultiIndex.from_tuples(networks_dict.keys(),names=["cluster","lv","opt","planning_horizon"])
df = {}
@ -579,21 +571,19 @@ if __name__ == "__main__":
for item in outputs:
snakemake.output[item] = snakemake.config['summary_dir'] + '/{name}/csvs/{item}.csv'.format(name=snakemake.config['run'],item=item)
networks_dict = {(cluster,lv,opt+sector_opt, co2_budget_name, planning_horizon) :
snakemake.config['results_dir'] + snakemake.config['run'] + '/postnetworks/elec_s{simpl}_{cluster}_lv{lv}_{opt}_{sector_opt}_{co2_budget_name}_{planning_horizon}.nc'\
networks_dict = {(cluster, lv, opt+sector_opt, planning_horizon) :
snakemake.config['results_dir'] + snakemake.config['run'] + '/postnetworks/elec_s{simpl}_{cluster}_lv{lv}_{opt}_{sector_opt}_{planning_horizon}.nc'\
.format(simpl=simpl,
cluster=cluster,
opt=opt,
lv=lv,
sector_opt=sector_opt,
co2_budget_name=co2_budget_name,
planning_horizon=planning_horizon)\
for simpl in snakemake.config['scenario']['simpl'] \
for cluster in snakemake.config['scenario']['clusters'] \
for opt in snakemake.config['scenario']['opts'] \
for sector_opt in snakemake.config['scenario']['sector_opts'] \
for lv in snakemake.config['scenario']['lv'] \
for co2_budget_name in snakemake.config['scenario']['co2_budget_name'] \
for planning_horizon in snakemake.config['scenario']['planning_horizons']}
print(networks_dict)
@ -602,7 +592,8 @@ if __name__ == "__main__":
costs_db = prepare_costs(snakemake.input.costs,
snakemake.config['costs']['USD2013_to_EUR2013'],
snakemake.config['costs']['discountrate'],
Nyears)
Nyears,
snakemake.config['costs']['lifetime'])
df = make_summaries(networks_dict)

View File

@ -324,7 +324,7 @@ def plot_map_without(network):
fig.set_size_inches(7, 6)
# PDF has minimum width, so set these to zero
line_lower_threshold = 0.
line_lower_threshold = 200.
line_upper_threshold = 1e4
linewidth_factor = 2e3
ac_color = "gray"
@ -343,19 +343,19 @@ def plot_map_without(network):
line_widths = n.lines.s_nom_min
link_widths = n.links.p_nom_min
line_widths[line_widths < line_upper_threshold] = 0.
link_widths[link_widths < line_upper_threshold] = 0.
line_widths[line_widths < line_lower_threshold] = 0.
link_widths[link_widths < line_lower_threshold] = 0.
line_widths[line_widths > line_upper_threshold] = line_upper_threshold
link_widths[link_widths > line_upper_threshold] = line_upper_threshold
n.plot(bus_sizes=10,
bus_colors="k",
n.plot(bus_colors="k",
line_colors=ac_color,
link_colors=dc_color,
line_widths=line_widths / linewidth_factor,
link_widths=link_widths / linewidth_factor,
ax=ax, boundaries=(-10, 30, 34, 70))
ax=ax, boundaries=(-10, 30, 34, 70),
color_geomap={'ocean': 'lightblue', 'land': "palegoldenrod"})
handles = []
labels = []

View File

@ -256,7 +256,8 @@ if __name__ == "__main__":
snakemake.input["balances"] = snakemake.config['summary_dir'] + '/test/csvs/supply_energy.csv'
snakemake.output["balances"] = snakemake.config['summary_dir'] + '/test/graphs/balances-energy.csv'
n_header = 5
n_header = 4
plot_costs()
plot_energy()

View File

@ -68,11 +68,13 @@ def update_wind_solar_costs(n,costs):
#assign clustered bus
#map initial network -> simplified network
busmap_s = pd.read_hdf(snakemake.input.clustermaps,
key="/busmap_s")
busmap_s = pd.read_csv(snakemake.input.busmap_s, index_col=0).squeeze()
busmap_s.index = busmap_s.index.astype(str)
busmap_s = busmap_s.astype(str)
#map simplified network -> clustered network
busmap = pd.read_hdf(snakemake.input.clustermaps,
key="/busmap")
busmap = pd.read_csv(snakemake.input.busmap, index_col=0).squeeze()
busmap.index = busmap.index.astype(str)
busmap = busmap.astype(str)
#map initial network -> clustered network
clustermaps = busmap_s.map(busmap)
@ -526,7 +528,7 @@ def prepare_data(network):
dsm_week = np.zeros((24*7,))
dsm_week[(np.arange(0,7,1)*24+options['dsm_restriction_time'])] = options['dsm_restriction_value']
dsm_week[(np.arange(0,7,1)*24+options['bev_dsm_restriction_time'])] = options['bev_dsm_restriction_value']
dsm_profile = generate_periodic_profiles(dt_index=network.snapshots.tz_localize("UTC"),
nodes=pop_layout.index,
@ -546,7 +548,7 @@ def prepare_data(network):
def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears):
def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears, lifetime):
#set all asset costs and other parameters
costs = pd.read_csv(cost_file,index_col=list(range(2))).sort_index()
@ -564,7 +566,7 @@ def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears):
"efficiency" : 1,
"fuel" : 0,
"investment" : 0,
"lifetime" : 25
"lifetime" : lifetime
})
costs["fixed"] = [(annuity(v["lifetime"],v["discount rate"])+v["FOM"]/100.)*v["investment"]*Nyears for i,v in costs.iterrows()]
@ -969,78 +971,105 @@ def add_storage(network):
lifetime=costs.at['SMR','lifetime'])
def add_transport(network):
print("adding transport")
def add_land_transport(network):
print("adding land transport")
fuel_cell_share = get_parameter(options["land_transport_fuel_cell_share"])
electric_share = get_parameter(options["land_transport_electric_share"])
fossil_share = 1 - fuel_cell_share - electric_share
print("shares of FCEV, EV and ICEV are",
fuel_cell_share,
electric_share,
fossil_share)
if fossil_share < 0:
print("Error, more FCEV and EV share than 1.")
sys.exit()
nodes = pop_layout.index
network.add("Carrier","Li ion")
network.madd("Bus",
nodes,
location=nodes,
suffix=" EV battery",
carrier="Li ion")
if electric_share > 0:
network.madd("Load",
nodes,
suffix=" transport",
bus=nodes + " EV battery",
carrier="transport",
p_set=(1-options['transport_fuel_cell_share'])*(transport[nodes]+shift_df(transport[nodes],1)+shift_df(transport[nodes],2))/3.)
network.add("Carrier","Li ion")
p_nom = nodal_transport_data["number cars"]*0.011*(1-options['transport_fuel_cell_share']) #3-phase charger with 11 kW * x% of time grid-connected
network.madd("Link",
nodes,
suffix= " BEV charger",
bus0=nodes,
bus1=nodes + " EV battery",
p_nom=p_nom,
carrier="BEV charger",
p_max_pu=avail_profile[nodes],
efficiency=0.9, #[B]
#These were set non-zero to find LU infeasibility when availability = 0.25
#p_nom_extendable=True,
#p_nom_min=p_nom,
#capital_cost=1e6, #i.e. so high it only gets built where necessary
)
if options["v2g"]:
network.madd("Link",
network.madd("Bus",
nodes,
suffix=" V2G",
bus1=nodes,
bus0=nodes + " EV battery",
p_nom=p_nom,
carrier="V2G",
p_max_pu=avail_profile[nodes],
efficiency=0.9) #[B]
if options["bev"]:
network.madd("Store",
nodes,
suffix=" battery storage",
bus=nodes + " EV battery",
carrier="battery storage",
e_cyclic=True,
e_nom=nodal_transport_data["number cars"]*0.05*options["bev_availability"]*(1-options['transport_fuel_cell_share']), #50 kWh battery http://www.zeit.de/mobilitaet/2014-10/auto-fahrzeug-bestand
e_max_pu=1,
e_min_pu=dsm_profile[nodes])
if options['transport_fuel_cell_share'] != 0:
location=nodes,
suffix=" EV battery",
carrier="Li ion")
network.madd("Load",
nodes,
suffix=" transport fuel cell",
bus=nodes + " H2",
carrier="transport fuel cell",
p_set=options['transport_fuel_cell_share']/costs.at["fuel cell","efficiency"]*transport[nodes])
suffix=" land transport EV",
bus=nodes + " EV battery",
carrier="land transport EV",
p_set=electric_share*(transport[nodes]+shift_df(transport[nodes],1)+shift_df(transport[nodes],2))/3.)
p_nom = nodal_transport_data["number cars"]*0.011*electric_share #3-phase charger with 11 kW * x% of time grid-connected
network.madd("Link",
nodes,
suffix= " BEV charger",
bus0=nodes,
bus1=nodes + " EV battery",
p_nom=p_nom,
carrier="BEV charger",
p_max_pu=avail_profile[nodes],
efficiency=0.9, #[B]
#These were set non-zero to find LU infeasibility when availability = 0.25
#p_nom_extendable=True,
#p_nom_min=p_nom,
#capital_cost=1e6, #i.e. so high it only gets built where necessary
)
if options["v2g"]:
network.madd("Link",
nodes,
suffix=" V2G",
bus1=nodes,
bus0=nodes + " EV battery",
p_nom=p_nom,
carrier="V2G",
p_max_pu=avail_profile[nodes],
efficiency=0.9) #[B]
if options["bev_dsm"]:
network.madd("Store",
nodes,
suffix=" battery storage",
bus=nodes + " EV battery",
carrier="battery storage",
e_cyclic=True,
e_nom=nodal_transport_data["number cars"]*0.05*options["bev_availability"]*electric_share, #50 kWh battery http://www.zeit.de/mobilitaet/2014-10/auto-fahrzeug-bestand
e_max_pu=1,
e_min_pu=dsm_profile[nodes])
if fuel_cell_share > 0:
network.madd("Load",
nodes,
suffix=" land transport fuel cell",
bus=nodes + " H2",
carrier="land transport fuel cell",
p_set=fuel_cell_share/options['transport_fuel_cell_efficiency']*transport[nodes])
if fossil_share > 0:
network.madd("Load",
nodes,
suffix=" land transport fossil",
bus="Fischer-Tropsch",
carrier="land transport fossil",
p_set=fossil_share/options['transport_internal_combustion_efficiency']*transport[nodes])
@ -1269,7 +1298,8 @@ def add_heat(network):
lifetime=costs.at['central gas CHP CCS','lifetime'])
else:
network.madd("Link",
if options["micro_chp"]:
network.madd("Link",
nodes[name] + " " + name + " micro gas CHP",
p_nom_extendable=True,
bus0="EU gas",
@ -1794,6 +1824,13 @@ def remove_h2_network(n):
carrier="H2 Store",
capital_cost=h2_capital_cost)
def get_parameter(item):
"""Check whether it depends on investment year"""
if type(item) is dict:
return item[investment_year]
else:
return item
if __name__ == "__main__":
@ -1803,48 +1840,45 @@ if __name__ == "__main__":
snakemake = MockSnakemake(
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
opts='', planning_horizons='2020',
co2_budget_name='go',
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1'),
input=dict(
network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc',
energy_totals_name='resources/energy_totals.csv',
co2_totals_name='resources/co2_totals.csv',
transport_name='resources/transport_data.csv',
biomass_potentials='resources/biomass_potentials.csv',
biomass_transport='data/biomass/biomass_transport_costs.csv',
timezone_mappings='data/timezone_mappings.csv',
heat_profile="data/heat_load_profile_BDEW.csv",
costs="../technology-data/outputs/costs_{planning_horizons}.csv",
h2_cavern = "data/hydrogen_salt_cavern_potentials.csv",
co2_budget="data/co2_budget.csv",
profile_offwind_ac="../pypsa-eur/resources/profile_offwind-ac.nc",
profile_offwind_dc="../pypsa-eur/resources/profile_offwind-dc.nc",
clustermaps='../pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5',
clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv",
simplified_pop_layout="resources/pop_layout_{network}_s{simpl}.csv",
industrial_demand="resources/industrial_energy_demand_{network}_s{simpl}_{clusters}.csv",
heat_demand_urban="resources/heat_demand_urban_{network}_s{simpl}_{clusters}.nc",
heat_demand_rural="resources/heat_demand_rural_{network}_s{simpl}_{clusters}.nc",
heat_demand_total="resources/heat_demand_total_{network}_s{simpl}_{clusters}.nc",
temp_soil_total="resources/temp_soil_total_{network}_s{simpl}_{clusters}.nc",
temp_soil_rural="resources/temp_soil_rural_{network}_s{simpl}_{clusters}.nc",
temp_soil_urban="resources/temp_soil_urban_{network}_s{simpl}_{clusters}.nc",
temp_air_total="resources/temp_air_total_{network}_s{simpl}_{clusters}.nc",
temp_air_rural="resources/temp_air_rural_{network}_s{simpl}_{clusters}.nc",
temp_air_urban="resources/temp_air_urban_{network}_s{simpl}_{clusters}.nc",
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
cop_soil_rural="resources/cop_soil_rural_{network}_s{simpl}_{clusters}.nc",
cop_soil_urban="resources/cop_soil_urban_{network}_s{simpl}_{clusters}.nc",
cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc",
cop_air_rural="resources/cop_air_rural_{network}_s{simpl}_{clusters}.nc",
cop_air_urban="resources/cop_air_urban_{network}_s{simpl}_{clusters}.nc",
solar_thermal_total="resources/solar_thermal_total_{network}_s{simpl}_{clusters}.nc",
solar_thermal_urban="resources/solar_thermal_urban_{network}_s{simpl}_{clusters}.nc",
traffic_data = "data/emobility/",
solar_thermal_rural="resources/solar_thermal_rural_{network}_s{simpl}_{clusters}.nc",
retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv",
floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv"
),
input=dict(network='../pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc',
energy_totals_name='resources/energy_totals.csv',
co2_totals_name='resources/co2_totals.csv',
transport_name='resources/transport_data.csv',
biomass_potentials='resources/biomass_potentials.csv',
biomass_transport='data/biomass/biomass_transport_costs.csv',
timezone_mappings='data/timezone_mappings.csv',
heat_profile="data/heat_load_profile_BDEW.csv",
costs="../technology-data/outputs/costs_{planning_horizons}.csv",
h2_cavern = "data/hydrogen_salt_cavern_potentials.csv",
profile_offwind_ac="../pypsa-eur/resources/profile_offwind-ac.nc",
profile_offwind_dc="../pypsa-eur/resources/profile_offwind-dc.nc",
clustermaps='../pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5',
clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv",
simplified_pop_layout="resources/pop_layout_{network}_s{simpl}.csv",
industrial_demand="resources/industrial_energy_demand_{network}_s{simpl}_{clusters}.csv",
heat_demand_urban="resources/heat_demand_urban_{network}_s{simpl}_{clusters}.nc",
heat_demand_rural="resources/heat_demand_rural_{network}_s{simpl}_{clusters}.nc",
heat_demand_total="resources/heat_demand_total_{network}_s{simpl}_{clusters}.nc",
temp_soil_total="resources/temp_soil_total_{network}_s{simpl}_{clusters}.nc",
temp_soil_rural="resources/temp_soil_rural_{network}_s{simpl}_{clusters}.nc",
temp_soil_urban="resources/temp_soil_urban_{network}_s{simpl}_{clusters}.nc",
temp_air_total="resources/temp_air_total_{network}_s{simpl}_{clusters}.nc",
temp_air_rural="resources/temp_air_rural_{network}_s{simpl}_{clusters}.nc",
temp_air_urban="resources/temp_air_urban_{network}_s{simpl}_{clusters}.nc",
cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc",
cop_soil_rural="resources/cop_soil_rural_{network}_s{simpl}_{clusters}.nc",
cop_soil_urban="resources/cop_soil_urban_{network}_s{simpl}_{clusters}.nc",
cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc",
cop_air_rural="resources/cop_air_rural_{network}_s{simpl}_{clusters}.nc",
cop_air_urban="resources/cop_air_urban_{network}_s{simpl}_{clusters}.nc",
solar_thermal_total="resources/solar_thermal_total_{network}_s{simpl}_{clusters}.nc",
solar_thermal_urban="resources/solar_thermal_urban_{network}_s{simpl}_{clusters}.nc",
traffic_data = "data/emobility/",
solar_thermal_rural="resources/solar_thermal_rural_{network}_s{simpl}_{clusters}.nc",
retro_cost_energy = "resources/retro_cost_{network}_s{simpl}_{clusters}.csv",
floor_area = "resources/floor_area_{network}_s{simpl}_{clusters}.csv"
),
output=['pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc']
)
import yaml
@ -1860,6 +1894,8 @@ if __name__ == "__main__":
opts = snakemake.wildcards.sector_opts.split('-')
investment_year=int(snakemake.wildcards.planning_horizons[-4:])
n = pypsa.Network(snakemake.input.network,
override_component_attrs=override_component_attrs)
@ -1876,7 +1912,8 @@ if __name__ == "__main__":
costs = prepare_costs(snakemake.input.costs,
snakemake.config['costs']['USD2013_to_EUR2013'],
snakemake.config['costs']['discountrate'],
Nyears)
Nyears,
snakemake.config['costs']['lifetime'])
remove_elec_base_techs(n)
@ -1916,7 +1953,7 @@ if __name__ == "__main__":
options["central"] = False
if "T" in opts:
add_transport(n)
add_land_transport(n)
if "H" in opts:
add_heat(n)
@ -1944,33 +1981,36 @@ if __name__ == "__main__":
else:
logger.info("No resampling")
#process CO2 limit
limit = get_parameter(snakemake.config["co2_budget"])
print("CO2 limit set to",limit)
if snakemake.config["foresight"] == 'myopic':
co2_limits=pd.read_csv(snakemake.input.co2_budget, index_col=0)
year=snakemake.wildcards.planning_horizons[-4:]
limit=co2_limits.loc[int(year),snakemake.config["scenario"]["co2_budget_name"]]
add_co2limit(n, Nyears, limit)
else:
for o in opts:
if "Co2L" in o:
limit = o[o.find("Co2L")+4:]
print(o,limit)
if limit == "":
limit = snakemake.config['co2_reduction']
else:
limit = float(limit.replace("p",".").replace("m","-"))
add_co2limit(n, Nyears, limit)
# add_emission_prices(n, exclude_co2=True)
for o in opts:
if "Co2L" in o:
limit = o[o.find("Co2L")+4:]
limit = float(limit.replace("p",".").replace("m","-"))
print("overriding CO2 limit with scenario limit",limit)
# if 'Ep' in opts:
# add_emission_prices(n)
print("adding CO2 budget limit as per unit of 1990 levels of",limit)
add_co2limit(n, Nyears, limit)
for o in opts:
for tech in ["solar","onwind","offwind"]:
if tech 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':
maxext = float(o[10:])*1e3
print("limiting new HVAC and HVDC extensions to",maxext,"MW")
n.lines['s_nom_max'] = n.lines['s_nom'] + maxext
hvdc = n.links.index[n.links.carrier == 'DC']
n.links.loc[hvdc,'p_nom_max'] = n.links.loc[hvdc,'p_nom'] + maxext
if snakemake.config["sector"]['electricity_distribution_grid']:
insert_electricity_distribution_grid(n)
if snakemake.config["sector"]['gas_distribution_grid']:

View File

@ -351,7 +351,7 @@ def solve_network(n, config=None, solver_log=None, opts=None):
# fn = os.path.basename(snakemake.output[0])
# n.export_to_netcdf('/home/vres/data/jonas/playground/pypsa-eur/' + fn)
status, termination_condition = run_lopf(n, fix_ext_lines=True)
status, termination_condition = run_lopf(n, allow_warning_status=True, fix_ext_lines=True)
# Drop zero lines from network
# zero_lines_i = n.lines.index[(n.lines.s_nom_opt == 0.) & n.lines.s_nom_extendable]