diff --git a/.gitignore b/.gitignore index ed3291f6..b41436e7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ gurobi.log config.yaml doc/_build + +*.xls \ No newline at end of file diff --git a/Snakefile b/Snakefile index 7558a5ac..f31ef836 100644 --- a/Snakefile +++ b/Snakefile @@ -146,8 +146,19 @@ rule build_biomass_potentials: resources: mem_mb=1000 script: 'scripts/build_biomass_potentials.py' +rule build_ammonia_production: + input: + usgs="data/myb1-2017-nitro.xls" + output: + ammonia_production="resources/ammonia_production.csv" + threads: 1 + resources: mem_mb=1000 + script: 'scripts/build_ammonia_production.py' + rule build_industry_sector_ratios: + input: + ammonia_production="resources/ammonia_production.csv" output: industry_sector_ratios="resources/industry_sector_ratios.csv" threads: 1 @@ -156,6 +167,8 @@ rule build_industry_sector_ratios: rule build_industrial_production_per_country: + input: + ammonia_production="resources/ammonia_production.csv" output: industrial_production_per_country="resources/industrial_production_per_country.csv" threads: 1 diff --git a/config.default.yaml b/config.default.yaml index 55380f63..0c111485 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -161,7 +161,10 @@ 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 'Al_primary_fraction' : 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 - 'H2_for_NH3' : 85000 # H2 in GWh/a for 17 MtNH3/a transformed from SMR to electrolyzed-H2, following Lechtenböhmer(2016) + '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 diff --git a/config.myopic.yaml b/config.myopic.yaml index 24213b44..00f7b062 100644 --- a/config.myopic.yaml +++ b/config.myopic.yaml @@ -161,7 +161,10 @@ 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 'Al_primary_fraction' : 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 - 'H2_for_NH3' : 85000 # H2 in GWh/a for 17 MtNH3/a transformed from SMR to electrolyzed-H2, following Lechtenböhmer(2016) + '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 diff --git a/scripts/build_ammonia_production.py b/scripts/build_ammonia_production.py new file mode 100644 index 00000000..9f2c2690 --- /dev/null +++ b/scripts/build_ammonia_production.py @@ -0,0 +1,45 @@ + + +import pandas as pd + +ammonia = pd.read_excel(snakemake.input.usgs, + sheet_name="T12", + skiprows=5, + header=0, + index_col=0, + skipfooter=19) + +rename = {"Austriae" : "AT", + "Bulgaria" : "BG", + "Belgiume" : "BE", + "Croatia" : "HR", + "Czechia" : "CZ", + "Estonia" : "EE", + "Finland" : "FI", + "France" : "FR", + "Germany" : "DE", + "Greece" : "GR", + "Hungarye" : "HU", + "Italye" : "IT", + "Lithuania" : "LT", + "Netherlands" : "NL", + "Norwaye" : "NO", + "Poland" : "PL", + "Romania" : "RO", + "Serbia" : "RS", + "Slovakia" : "SK", + "Spain" : "ES", + "Switzerland" : "CH", + "United Kingdom" : "GB", +} + +ammonia = ammonia.rename(rename) + +ammonia = ammonia.loc[rename.values(),[str(i) for i in range(2013,2018)]].astype(float) + +#convert from ktonN to ktonNH3 +ammonia = ammonia*17/14 + +ammonia.index.name = "ktonNH3/a" + +ammonia.to_csv(snakemake.output.ammonia_production) diff --git a/scripts/build_industrial_production_per_country.py b/scripts/build_industrial_production_per_country.py index 4c4de875..c8fa6910 100644 --- a/scripts/build_industrial_production_per_country.py +++ b/scripts/build_industrial_production_per_country.py @@ -9,6 +9,10 @@ ktoe_to_twh = 0.01163 jrc_base_dir = "data/jrc-idees-2015" eb_base_dir = "data/eurostat-energy_balances-may_2018_edition" +# year for which data is retrieved +raw_year = 2015 +year = raw_year-2016 + sub_sheet_name_dict = { 'Iron and steel':'ISI', 'Chemicals Industry':'CHI', 'Non-metallic mineral products': 'NMM', @@ -162,7 +166,7 @@ for country in countries: #energy consumption in the sector and EU28 excel_sum_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_EU28.xlsx'.format(jrc_base_dir), sheet_name='Ind_Summary', index_col=0,header=0,squeeze=True) # the summary sheet - s_sum_out = excel_sum_out.iloc[49:76,-1] + s_sum_out = excel_sum_out.iloc[49:76,year] e_EU28 = s_sum_out[dic_sec_summary[sector]] ratio_country_EU28=e_country/e_EU28 @@ -170,7 +174,7 @@ for country in countries: excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_EU28.xlsx'.format(jrc_base_dir), sheet_name=sub_sheet_name_dict[sector],index_col=0,header=0,squeeze=True) # the summary sheet - s_out = excel_out.iloc[loc_dic[sector][0]:loc_dic[sector][1],-1] + s_out = excel_out.iloc[loc_dic[sector][0]:loc_dic[sector][1],year] for subsector in sect2sub[sector]: countries_demand.loc[country,subsector] = ratio_country_EU28*s_out[out_dic[subsector]] @@ -180,11 +184,34 @@ for country in countries: # read the input sheets excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(jrc_base_dir,jrc_names.get(country,country)), sheet_name=sub_sheet_name_dict[sector],index_col=0,header=0,squeeze=True) # the summary sheet - s_out = excel_out.iloc[loc_dic[sector][0]:loc_dic[sector][1],-1] + s_out = excel_out.iloc[loc_dic[sector][0]:loc_dic[sector][1],year] for subsector in sect2sub[sector]: countries_demand.loc[country,subsector] = s_out[out_dic[subsector]] + +#include ammonia demand separately and remove ammonia from basic chemicals + +ammonia = pd.read_csv(snakemake.input.ammonia_production, + index_col=0) + +there = ammonia.index.intersection(countries_demand.index) +missing = countries_demand.index^there + +print("Following countries have no ammonia demand:", missing) + +countries_demand.insert(2,"Ammonia",0.) + +countries_demand.loc[there,"Ammonia"] = ammonia.loc[there, str(raw_year)] + +countries_demand["Basic chemicals"] -= countries_demand["Ammonia"] + +#EE, HR and LT got negative demand through subtraction - poor data +countries_demand.loc[countries_demand["Basic chemicals"] < 0.,"Basic chemicals"] = 0. + +countries_demand.rename(columns={"Basic chemicals" : "Basic chemicals (without ammonia)"}, + inplace=True) + countries_demand.index.name = "kton/a" countries_demand.to_csv(snakemake.output.industrial_production_per_country, diff --git a/scripts/build_industry_sector_ratios.py b/scripts/build_industry_sector_ratios.py index 3c567a38..5b7d4ba3 100644 --- a/scripts/build_industry_sector_ratios.py +++ b/scripts/build_industry_sector_ratios.py @@ -5,11 +5,11 @@ import numpy as np base_dir = "data/jrc-idees-2015" -# year for wich data is retrieved -year = 2015 -year = year-2016 +# year for which data is retrieved +raw_year = 2015 +year = raw_year-2016 -conv_factor=11.630 #ktoe/kton -> MWh/ton +conv_factor=11.630 #GWh/ktoe OR MWh/toe country = 'EU28' @@ -185,6 +185,8 @@ excel_emi = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(base_dir,c ### Basic chemicals +## Ammonia is separate afterwards + sector = 'Basic chemicals' df[sector] = 0 @@ -203,9 +205,8 @@ df.loc['heat',sector] += s_fec['Low enthalpy heat'] #### Chemicals: Feedstock (energy used as raw material) #> There are Solids, Refinery gas, LPG, Diesel oil, Residual fuel oil, Other liquids, Naphtha, Natural gas for feedstock. # -#> Naphta represents 47%, methane 17%. LPG (18%) solids, refinery gas, diesel oil, residual fuel oils and other liquids are asimilated to Napthta -# -#> Following Lechtenbohmer 2016, the 85 TWh/year of methane for the ammonia industry are substited by hydrogen. +#> Naphta represents 47%, methane 17%. LPG (18%) solids, refinery gas, diesel oil, residual fuel oils and other liquids are asimilated to Naphtha + subsector = 'Chemicals: Feedstock (energy used as raw material)' @@ -218,10 +219,7 @@ assert s_fec.index[0] == subsector df.loc['naphtha',sector] += s_fec['Naphtha'] # natural gas -# 85 TWh/year of methane for the ammonia industry are substituted by hydrogen -df.loc['methane',sector] += s_fec['Natural gas'] - snakemake.config["industry"]["H2_for_NH3"]/conv_factor -df.loc['hydrogen',sector] += snakemake.config["industry"]["H2_for_NH3"]/conv_factor -# 1 ktoe = 11630 MWh +df.loc['methane',sector] += s_fec['Natural gas'] # LPG and other feedstock materials are assimilated to naphtha since they will be produced trough Fischer-Tropsh process df.loc['naphtha',sector] += (s_fec['Solids'] + s_fec['Refinery gas'] + s_fec['LPG'] + s_fec['Diesel oil'] @@ -244,8 +242,10 @@ assert s_fec.index[0] == subsector # efficiency of biomass eff_bio = s_ued['Biomass']/s_fec['Biomass'] -# replace all fec by biomass -df.loc['biomass',sector] += s_ued[subsector]/eff_bio +# replace all non-methane fec by biomass +df.loc['biomass',sector] += (s_ued[subsector]-s_ued['Natural gas (incl. biogas)'])/eff_bio + +df.loc['methane',sector] += s_fec['Natural gas (incl. biogas)'] #### Chemicals: Furnaces #> assume fully electrified @@ -297,10 +297,25 @@ s_emi = excel_emi.iloc[3:57,year] assert s_emi.index[0] == sector + +## Correct everything by subtracting 2015's ammonia demand and putting in ammonia demand for H2 and electricity separately + s_out = excel_out.iloc[8:9,year] assert sector in str(s_out.index) +ammonia = pd.read_csv(snakemake.input.ammonia_production, + index_col=0) + +eu28 = ['FR', 'DE', 'GB', 'IT', 'ES', 'PL', 'SE', 'NL', 'BE', 'FI', + 'DK', 'PT', 'RO', 'AT', 'BG', 'EE', 'GR', 'LV', 'CZ', + 'HU', 'IE', 'SK', 'LT', 'HR', 'LU', 'SI', 'CY', 'MT'] + +#ktNH3/a +total_ammonia = ammonia.loc[ammonia.index.intersection(eu28),str(raw_year)].sum() + +s_out -= total_ammonia + df.loc['process emission',sector] += (s_emi['Process emissions'] - snakemake.config["industry"]['petrochemical_process_emissions']*1e3 - snakemake.config["industry"]['NH3_process_emissions']*1e3)/s_out.values # unit tCO2/t material #these are emissions originating from feedstock, i.e. could be non-fossil origin @@ -310,8 +325,24 @@ df.loc['process emission from feedstock',sector] += (snakemake.config["industry" # final energy consumption per t sources=['elec','biomass', 'methane', 'hydrogen', 'heat','naphtha'] -df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out.values# unit MWh/t material -# 1 ktoe = 11630 MWh +#convert from ktoe/a to GWh/a +df.loc[sources,sector] *= conv_factor + +df.loc['methane',sector] -= total_ammonia*snakemake.config['industry']['MWh_CH4_per_tNH3_SMR'] +df.loc['elec',sector] -= total_ammonia*snakemake.config['industry']['MWh_elec_per_tNH3_SMR'] + +df.loc[sources,sector] = df.loc[sources,sector]/s_out.values # unit MWh/t material + +df.rename(columns={sector : sector + " (without ammonia)"}, + inplace=True) + +sector = 'Ammonia' + +df[sector] = 0. + +df.loc['hydrogen',sector] = snakemake.config['industry']['MWh_H2_per_tNH3_electrolysis'] +df.loc['elec',sector] = snakemake.config['industry']['MWh_elec_per_tNH3_electrolysis'] + ### Other chemicals @@ -404,7 +435,7 @@ df.loc['process emission',sector] += s_emi['Process emissions']/s_out.values # u # final energy consumption per t sources=['elec','biomass', 'methane', 'hydrogen', 'heat','naphtha'] -df.loc[sources,sector] = df.loc[sources,sector]*11.630/s_out.values # unit MWh/t material +df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out.values # unit MWh/t material # 1 ktoe = 11630 MWh ### Pharmaceutical products etc. @@ -494,7 +525,7 @@ df.loc['process emission',sector] += 0 # unit tCO2/t material # final energy consumption per t sources=['elec','biomass', 'methane', 'hydrogen', 'heat', 'naphtha'] -df.loc[sources,sector] = df.loc[sources,sector]*11.630/s_out.values # unit MWh/t material +df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out.values # unit MWh/t material # 1 ktoe = 11630 MWh ## Non-metallic mineral products @@ -634,7 +665,7 @@ df.loc['process emission',sector] += s_emi['Process emissions']/s_out.values # u # final energy consumption per t sources=['elec','biomass', 'methane', 'hydrogen', 'heat','naphtha'] -df.loc[sources,sector] = df.loc[sources,sector]*11.630/s_out.values # unit MWh/t material +df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out.values # unit MWh/t material # 1 ktoe = 11630 MWh ### Glass production