Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exogenous transition path for shipping, Steel, and Aluminum production #136

Merged
merged 14 commits into from Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -28,7 +28,7 @@ gurobi.log
/data/.nfs*
/data/Industrial_Database.csv
/data/retro/tabula-calculator-calcsetbuilding.csv

/data
*.org

*.nc
Expand Down
18 changes: 9 additions & 9 deletions Snakefile
Expand Up @@ -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'


Expand All @@ -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'


Expand Down Expand Up @@ -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",
Expand Down
38 changes: 36 additions & 2 deletions config.default.yaml
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"
5 changes: 2 additions & 3 deletions doc/release_notes.rst
Expand Up @@ -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)
===================================

Expand Down
20 changes: 15 additions & 5 deletions scripts/build_industrial_production_per_country_tomorrow.py
Expand Up @@ -2,34 +2,44 @@

import pandas as pd

from prepare_sector_network import get

if __name__ == '__main__':
if 'snakemake' not in globals():
from helper import mock_snakemake
snakemake = mock_snakemake('build_industrial_production_per_country_tomorrow')

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]

Expand Down
4 changes: 3 additions & 1 deletion scripts/plot_summary.py
Expand Up @@ -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"
}
Expand Down
26 changes: 25 additions & 1 deletion scripts/prepare_sector_network.py
Expand Up @@ -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,
Expand All @@ -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",
Expand Down