Exogenous transition path for shipping, Steel, and Aluminum production (#136)
* Update .gitignore * Add fictitious load to account for non-transformed shipping emissions The share of shipping demand that is transformed is defined now for different years to be used with the myopic code. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. * Split colours for H2 in Industry and H2 in shipping when plotting balances. When plotting the balance for H2, the rename dictionary merges all the demands containing H2. This commit disables such merging and keeps different colours for H2 in shipping and H2 in industry. This is useful when one wants to look at the H2 balance and have an overview of where the H2 is consumed in the model. * Make transformation of Steel and Aluminum production depends on year Previously, the transformation of the Steel and Aluminum production was assumed to occur overnight. This commit enables the definition of a transformation path via the config.yaml file. This requires adding the {planning_horizon} to the input and output file name of the following rules: build_industrial_production_per_country_tomorrow build_industrial_production_per_node build_industry_energy_demand_per_node prepare_sector_network * small follow-up to merge * Add oil consumed in shipping as a load to EU oil bus * Update scripts/prepare_sector_network.py * add planning_horizons wildcard to benchmark paths * fixup: double fraction_primary for steel Co-authored-by: Fabian Neumann <fabian.neumann@outlook.de>
This commit is contained in:
parent
50dd4ce285
commit
fab31e6524
2
.gitignore
vendored
2
.gitignore
vendored
@ -28,7 +28,7 @@ gurobi.log
|
||||
/data/.nfs*
|
||||
/data/Industrial_Database.csv
|
||||
/data/retro/tabula-calculator-calcsetbuilding.csv
|
||||
|
||||
/data
|
||||
*.org
|
||||
|
||||
*.nc
|
||||
|
18
Snakefile
18
Snakefile
@ -220,10 +220,10 @@ rule build_industrial_production_per_country_tomorrow:
|
||||
input:
|
||||
industrial_production_per_country="resources/industrial_production_per_country.csv"
|
||||
output:
|
||||
industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow.csv"
|
||||
industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv"
|
||||
threads: 1
|
||||
resources: mem_mb=1000
|
||||
benchmark: "benchmarks/build_industrial_production_per_country_tomorrow"
|
||||
benchmark: "benchmarks/build_industrial_production_per_country_tomorrow_{planning_horizons}"
|
||||
script: 'scripts/build_industrial_production_per_country_tomorrow.py'
|
||||
|
||||
|
||||
@ -243,25 +243,25 @@ rule build_industrial_distribution_key:
|
||||
rule build_industrial_production_per_node:
|
||||
input:
|
||||
industrial_distribution_key="resources/industrial_distribution_key_elec_s{simpl}_{clusters}.csv",
|
||||
industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow.csv"
|
||||
industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv"
|
||||
output:
|
||||
industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}.csv"
|
||||
industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
||||
threads: 1
|
||||
resources: mem_mb=1000
|
||||
benchmark: "benchmarks/build_industrial_production_per_node/s{simpl}_{clusters}"
|
||||
benchmark: "benchmarks/build_industrial_production_per_node/s{simpl}_{clusters}_{planning_horizons}"
|
||||
script: 'scripts/build_industrial_production_per_node.py'
|
||||
|
||||
|
||||
rule build_industrial_energy_demand_per_node:
|
||||
input:
|
||||
industry_sector_ratios="resources/industry_sector_ratios.csv",
|
||||
industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}.csv",
|
||||
industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}_{planning_horizons}.csv",
|
||||
industrial_energy_demand_per_node_today="resources/industrial_energy_demand_today_elec_s{simpl}_{clusters}.csv"
|
||||
output:
|
||||
industrial_energy_demand_per_node="resources/industrial_energy_demand_elec_s{simpl}_{clusters}.csv"
|
||||
industrial_energy_demand_per_node="resources/industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
||||
threads: 1
|
||||
resources: mem_mb=1000
|
||||
benchmark: "benchmarks/build_industrial_energy_demand_per_node/s{simpl}_{clusters}"
|
||||
benchmark: "benchmarks/build_industrial_energy_demand_per_node/s{simpl}_{clusters}_{planning_horizons}"
|
||||
script: 'scripts/build_industrial_energy_demand_per_node.py'
|
||||
|
||||
|
||||
@ -333,7 +333,7 @@ rule prepare_sector_network:
|
||||
busmap=pypsaeur("resources/busmap_elec_s{simpl}_{clusters}.csv"),
|
||||
clustered_pop_layout="resources/pop_layout_elec_s{simpl}_{clusters}.csv",
|
||||
simplified_pop_layout="resources/pop_layout_elec_s{simpl}.csv",
|
||||
industrial_demand="resources/industrial_energy_demand_elec_s{simpl}_{clusters}.csv",
|
||||
industrial_demand="resources/industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv",
|
||||
heat_demand_urban="resources/heat_demand_urban_elec_s{simpl}_{clusters}.nc",
|
||||
heat_demand_rural="resources/heat_demand_rural_elec_s{simpl}_{clusters}.nc",
|
||||
heat_demand_total="resources/heat_demand_total_elec_s{simpl}_{clusters}.nc",
|
||||
|
@ -175,6 +175,14 @@ sector:
|
||||
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
|
||||
shipping_hydrogen_share: # 1 means all hydrogen FC
|
||||
2020: 0
|
||||
2025: 0
|
||||
2030: 0.05
|
||||
2035: 0.15
|
||||
2040: 0.3
|
||||
2045: 0.6
|
||||
2050: 1
|
||||
time_dep_hp_cop: true #time dependent heat pump coefficient of performance
|
||||
heat_pump_sink_T: 55. # Celsius, based on DTU / large area radiators; used in build_cop_profiles.py
|
||||
# conservatively high to cover hot water and space heating in poorly-insulated buildings
|
||||
@ -229,10 +237,32 @@ sector:
|
||||
|
||||
|
||||
industry:
|
||||
St_primary_fraction: 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6
|
||||
St_primary_fraction: # fraction of steel produced via primary route versus secondary route (scrap+EAF); today fraction is 0.6
|
||||
2020: 0.6
|
||||
2025: 0.55
|
||||
2030: 0.5
|
||||
2035: 0.45
|
||||
2040: 0.4
|
||||
2045: 0.35
|
||||
2050: 0.3
|
||||
DRI_fraction: # fraction of the primary route converted to DRI + EAF
|
||||
2020: 0
|
||||
2025: 0
|
||||
2030: 0.05
|
||||
2035: 0.2
|
||||
2040: 0.4
|
||||
2045: 0.7
|
||||
2050: 1
|
||||
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
|
||||
Al_primary_fraction: # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4
|
||||
2020: 0.4
|
||||
2025: 0.375
|
||||
2030: 0.35
|
||||
2035: 0.325
|
||||
2040: 0.3
|
||||
2045: 0.25
|
||||
2050: 0.2
|
||||
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)
|
||||
@ -472,4 +502,8 @@ plotting:
|
||||
solid biomass: '#DAA520'
|
||||
today: '#D2691E'
|
||||
shipping: '#6495ED'
|
||||
shipping oil: "#6495ED"
|
||||
shipping oil emissions: "#6495ED"
|
||||
electricity distribution grid: '#333333'
|
||||
H2 for industry: "#222222"
|
||||
H2 for shipping: "#6495ED"
|
||||
|
@ -60,11 +60,10 @@ Future release
|
||||
These are included in the environment specifications of PyPSA-Eur.
|
||||
* Consistent use of ``__main__`` block and further unspecific code cleaning.
|
||||
* Distinguish costs for home battery storage and inverter from utility-scale battery costs.
|
||||
|
||||
|
||||
* The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions.
|
||||
* The transformation of the Steel and Aluminium production can be now defined for different years in the ``config.yaml`` file.
|
||||
* Include the option to alter the maximum energy capacity of a store via the ``carrier+factor`` in the ``{sector_opts}`` wildcard. This can be useful for sensitivity analyses. Example: ``co2 stored+e2`` multiplies the ``e_nom_max`` by factor 2. In this example, ``e_nom_max`` represents the CO2 sequestration potential in Europe.
|
||||
|
||||
|
||||
PyPSA-Eur-Sec 0.5.0 (21st May 2021)
|
||||
===================================
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from prepare_sector_network import get
|
||||
|
||||
if __name__ == '__main__':
|
||||
if 'snakemake' not in globals():
|
||||
from helper import mock_snakemake
|
||||
@ -9,27 +11,35 @@ if __name__ == '__main__':
|
||||
|
||||
config = snakemake.config["industry"]
|
||||
|
||||
investment_year = int(snakemake.wildcards.planning_horizons)
|
||||
|
||||
fn = snakemake.input.industrial_production_per_country
|
||||
production = pd.read_csv(fn, index_col=0)
|
||||
|
||||
keys = ["Integrated steelworks", "Electric arc"]
|
||||
total_steel = production[keys].sum(axis=1)
|
||||
|
||||
st_primary_fraction = get(config["St_primary_fraction"], investment_year)
|
||||
dri_fraction = get(config["DRI_fraction"], investment_year)
|
||||
int_steel = production["Integrated steelworks"].sum()
|
||||
fraction_persistent_primary = config["St_primary_fraction"] * total_steel.sum() / int_steel
|
||||
fraction_persistent_primary = st_primary_fraction * total_steel.sum() / int_steel
|
||||
|
||||
dri = fraction_persistent_primary * production["Integrated steelworks"]
|
||||
dri = dri_fraction * fraction_persistent_primary * production["Integrated steelworks"]
|
||||
production.insert(2, "DRI + Electric arc", dri)
|
||||
|
||||
production["Electric arc"] = total_steel - production["DRI + Electric arc"]
|
||||
production["Integrated steelworks"] = 0.
|
||||
not_dri = (1 - dri_fraction)
|
||||
production["Integrated steelworks"] = not_dri * fraction_persistent_primary * production["Integrated steelworks"]
|
||||
production["Electric arc"] = total_steel - production["DRI + Electric arc"] - production["Integrated steelworks"]
|
||||
|
||||
keys = ["Aluminium - primary production", "Aluminium - secondary production"]
|
||||
total_aluminium = production[keys].sum(axis=1)
|
||||
|
||||
key_pri = "Aluminium - primary production"
|
||||
key_sec = "Aluminium - secondary production"
|
||||
fraction_persistent_primary = config["Al_primary_fraction"] * total_aluminium.sum() / production[key_pri].sum()
|
||||
|
||||
al_primary_fraction = get(config["Al_primary_fraction"], investment_year)
|
||||
fraction_persistent_primary = al_primary_fraction * total_aluminium.sum() / production[key_pri].sum()
|
||||
|
||||
production[key_pri] = fraction_persistent_primary * production[key_pri]
|
||||
production[key_sec] = total_aluminium - production[key_pri]
|
||||
|
||||
|
@ -34,7 +34,9 @@ def rename_techs(label):
|
||||
rename_if_contains_dict = {
|
||||
"water tanks": "hot water storage",
|
||||
"retrofitting": "building retrofitting",
|
||||
"H2": "hydrogen storage",
|
||||
"H2 Electrolysis": "hydrogen storage",
|
||||
"H2 Fuel Cell": "hydrogen storage",
|
||||
"H2 pipeline": "hydrogen storage",
|
||||
"battery": "battery storage",
|
||||
"CC": "CC"
|
||||
}
|
||||
|
@ -1716,7 +1716,8 @@ def add_industry(n, costs):
|
||||
|
||||
all_navigation = ["total international navigation", "total domestic navigation"]
|
||||
efficiency = options['shipping_average_efficiency'] / costs.at["fuel cell", "efficiency"]
|
||||
p_set = nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 * efficiency / 8760
|
||||
shipping_hydrogen_share = get(options['shipping_hydrogen_share'], investment_year)
|
||||
p_set = shipping_hydrogen_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 * efficiency / 8760
|
||||
|
||||
n.madd("Load",
|
||||
nodes,
|
||||
@ -1726,6 +1727,29 @@ def add_industry(n, costs):
|
||||
p_set=p_set
|
||||
)
|
||||
|
||||
if shipping_hydrogen_share < 1:
|
||||
|
||||
shipping_oil_share = 1 - shipping_hydrogen_share
|
||||
|
||||
p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760.
|
||||
|
||||
n.madd("Load",
|
||||
nodes,
|
||||
suffix=" shipping oil",
|
||||
bus="EU oil",
|
||||
carrier="shipping oil",
|
||||
p_set=p_set
|
||||
)
|
||||
|
||||
co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"]
|
||||
|
||||
n.add("Load",
|
||||
"shipping oil emissions",
|
||||
bus="co2 atmosphere",
|
||||
carrier="shipping oil emissions",
|
||||
p_set=-co2
|
||||
)
|
||||
|
||||
if "EU oil" not in n.buses.index:
|
||||
|
||||
n.add("Bus",
|
||||
|
Loading…
Reference in New Issue
Block a user