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 54b8c241..17f79dff 100644 --- a/Snakefile +++ b/Snakefile @@ -130,9 +130,9 @@ rule build_energy_totals: input: nuts3_shapes=pypsaeur('resources/nuts3_shapes.geojson') output: - energy_name='data/energy_totals.csv', - co2_name='data/co2_totals.csv', - transport_name='data/transport_data.csv' + energy_name='resources/energy_totals.csv', + co2_name='resources/co2_totals.csv', + transport_name='resources/transport_data.csv' threads: 1 resources: mem_mb=10000 script: 'scripts/build_energy_totals.py' @@ -141,13 +141,24 @@ rule build_biomass_potentials: input: jrc_potentials="data/biomass/JRC Biomass Potentials.xlsx" output: - biomass_potentials='data/biomass_potentials.csv' + biomass_potentials='resources/biomass_potentials.csv' threads: 1 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 @@ -155,20 +166,51 @@ rule build_industry_sector_ratios: script: 'scripts/build_industry_sector_ratios.py' -rule build_industrial_demand_per_country: +rule build_industrial_production_per_country: input: - industry_sector_ratios="resources/industry_sector_ratios.csv" + ammonia_production="resources/ammonia_production.csv" output: - industrial_demand_per_country="resources/industrial_demand_per_country.csv" + industrial_production_per_country="resources/industrial_production_per_country.csv" threads: 1 resources: mem_mb=1000 - script: 'scripts/build_industrial_demand_per_country.py' + script: 'scripts/build_industrial_production_per_country.py' + + +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" + threads: 1 + resources: mem_mb=1000 + script: 'scripts/build_industrial_production_per_country_tomorrow.py' + +rule build_industrial_energy_demand_per_country_today: + input: + ammonia_production="resources/ammonia_production.csv", + industrial_production_per_country="resources/industrial_production_per_country.csv" + output: + industrial_energy_demand_per_country_today="resources/industrial_energy_demand_per_country_today.csv" + threads: 1 + resources: mem_mb=1000 + script: 'scripts/build_industrial_energy_demand_per_country_today.py' + + +rule build_industrial_energy_demand_per_country: + input: + industry_sector_ratios="resources/industry_sector_ratios.csv", + industrial_production_per_country="resources/industrial_production_per_country_tomorrow.csv" + output: + industrial_energy_demand_per_country="resources/industrial_energy_demand_per_country.csv" + threads: 1 + resources: mem_mb=1000 + script: 'scripts/build_industrial_energy_demand_per_country.py' rule build_industrial_demand: input: clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv", - industrial_demand_per_country="resources/industrial_demand_per_country.csv" + industrial_demand_per_country="resources/industrial_energy_demand_per_country.csv" output: industrial_demand="resources/industrial_demand_{network}_s{simpl}_{clusters}.csv" threads: 1 @@ -179,10 +221,10 @@ rule build_industrial_demand: rule prepare_sector_network: input: network=pypsaeur('networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc'), - energy_totals_name='data/energy_totals.csv', - co2_totals_name='data/co2_totals.csv', - transport_name='data/transport_data.csv', - biomass_potentials='data/biomass_potentials.csv', + 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', timezone_mappings='data/timezone_mappings.csv', heat_profile="data/heat_load_profile_BDEW.csv", costs=config['costs_dir'] + "costs_{planning_horizons}.csv", diff --git a/config.default.yaml b/config.default.yaml index 575d6c78..135d7c25 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -158,10 +158,14 @@ solving: mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2 industry: - 'DRI_ratio' : 0.5 #ratio of today's blast-furnace steel (60% primary route, 40% secondary) to future assumption (30% primary, 70% secondary), transformed into DRI + electric arc - 'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 - 'Al_to_scrap' : 0.5 # ratio of primary-route Aluminum transformed into scrap (today 40% to future 20% primary route) - 'H2_for_NH3' : 85000 # H2 in GWh/a for 17 MtNH3/a transformed from SMR to electrolyzed-H2, following Lechtenböhmer(2016) + '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 diff --git a/config.myopic.yaml b/config.myopic.yaml index 48f6cb62..435f4eb6 100644 --- a/config.myopic.yaml +++ b/config.myopic.yaml @@ -158,10 +158,14 @@ solving: mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2 industry: - 'DRI_ratio' : 0.5 #ratio of today's blast-furnace steel (60% primary route, 40% secondary) to future assumption (30% primary, 70% secondary), transformed into DRI + electric arc - 'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 - 'Al_to_scrap' : 0.5 # ratio of primary-route Aluminum transformed into scrap (today 40% to future 20% primary route) - 'H2_for_NH3' : 85000 # H2 in GWh/a for 17 MtNH3/a transformed from SMR to electrolyzed-H2, following Lechtenböhmer(2016) + '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 diff --git a/doc/installation.rst b/doc/installation.rst index c99e69bc..2d969b39 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -65,8 +65,8 @@ To download and extract it on the command line: .. code:: bash - projects/pypsa-eur-sec/data % wget "https://nworbmot.org/pypsa-eur-sec-data-bundle-190719.tar.gz" - projects/pypsa-eur-sec/data % tar xvzf pypsa-eur-sec-data-bundle-190719.tar.gz + projects/pypsa-eur-sec/data % wget "https://nworbmot.org/pypsa-eur-sec-data-bundle-200921.tar.gz" + projects/pypsa-eur-sec/data % tar xvzf pypsa-eur-sec-data-bundle-200921.tar.gz Set up the default configuration ================================ diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 4c8fdf28..d02f79e0 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -74,3 +74,9 @@ Release Process * Make a `GitHub release `_, which automatically triggers archiving by `zenodo `_. * Send announcement on the `PyPSA mailing list `_. + +To make a new release of the data bundle, do: + +.. code:: bash + + data % tar pczf pypsa-eur-sec-data-bundle-date.tar.gz eea switzerland-sfoe biomass eurostat-energy_balances-* jrc-idees-2015 emobility urban_percent.csv timezone_mappings.csv heat_load_profile_DK_AdamJensen.csv WindWaveWEC_GLTB.xlsx myb1-2017-nitro.xls 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_demand.py b/scripts/build_industrial_demand.py index fce7b6ad..3bc56254 100644 --- a/scripts/build_industrial_demand.py +++ b/scripts/build_industrial_demand.py @@ -7,7 +7,7 @@ def build_industrial_demand(): pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout,index_col=0) pop_layout["ct"] = pop_layout.index.str[:2] ct_total = pop_layout.total.groupby(pop_layout["ct"]).sum() - pop_layout["ct_total"] = pop_layout["ct"].map(ct_total.get) + pop_layout["ct_total"] = pop_layout["ct"].map(ct_total) pop_layout["fraction"] = pop_layout["total"]/pop_layout["ct_total"] industrial_demand_per_country = pd.read_csv(snakemake.input.industrial_demand_per_country,index_col=0) diff --git a/scripts/build_industrial_energy_demand_per_country.py b/scripts/build_industrial_energy_demand_per_country.py new file mode 100644 index 00000000..6ee67f4f --- /dev/null +++ b/scripts/build_industrial_energy_demand_per_country.py @@ -0,0 +1,83 @@ + +import pandas as pd +import numpy as np + + +tj_to_ktoe = 0.0238845 +ktoe_to_twh = 0.01163 + +eb_base_dir = "data/eurostat-energy_balances-may_2018_edition" +jrc_base_dir = "data/jrc-idees-2015" + +# import EU ratios df as csv +industry_sector_ratios=pd.read_csv(snakemake.input.industry_sector_ratios, + index_col=0) + +#material demand per country and industry (kton/a) +countries_production = pd.read_csv(snakemake.input.industrial_production_per_country, index_col=0) + +#Annual energy consumption in Switzerland by sector in 2015 (in TJ) +#From: Energieverbrauch in der Industrie und im Dienstleistungssektor, Der Bundesrat +#http://www.bfe.admin.ch/themen/00526/00541/00543/index.html?lang=de&dossier_id=00775 + +dic_Switzerland ={'Iron and steel': 7889., + 'Chemicals Industry': 26871., + 'Non-metallic mineral products': 15513.+3820., + 'Pulp, paper and printing': 12004., + 'Food, beverages and tobacco': 17728., + 'Non Ferrous Metals': 3037., + 'Transport Equipment': 14993., + 'Machinery Equipment': 4724., + 'Textiles and leather': 1742., + 'Wood and wood products': 0., + 'Other Industrial Sectors': 10825., + 'current electricity': 53760.} + + +eb_names={'NO':'Norway', 'AL':'Albania', 'BA':'Bosnia and Herzegovina', + 'MK':'FYR of Macedonia', 'GE':'Georgia', 'IS':'Iceland', + 'KO':'Kosovo', 'MD':'Moldova', 'ME':'Montenegro', 'RS':'Serbia', + 'UA':'Ukraine', 'TR':'Turkey', } + +jrc_names = {"GR" : "EL", + "GB" : "UK"} + +#final energy consumption per country and industry (TWh/a) +countries_df = countries_production.dot(industry_sector_ratios.T) +countries_df*= 0.001 #GWh -> TWh (ktCO2 -> MtCO2) + + + +non_EU = ['NO', 'CH', 'ME', 'MK', 'RS', 'BA', 'AL'] + + +# save current electricity consumption +for country in countries_df.index: + if country in non_EU: + if country == 'CH': + countries_df.loc[country, 'current electricity']=dic_Switzerland['current electricity']*tj_to_ktoe*ktoe_to_twh + else: + excel_balances = pd.read_excel('{}/{}.XLSX'.format(eb_base_dir,eb_names[country]), + sheet_name='2016', index_col=1,header=0, skiprows=1 ,squeeze=True) + + countries_df.loc[country, 'current electricity'] = excel_balances.loc['Industry', 'Electricity']*ktoe_to_twh + + else: + + excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(jrc_base_dir,jrc_names.get(country,country)), + sheet_name='Ind_Summary',index_col=0,header=0,squeeze=True) # the summary sheet + + s_out = excel_out.iloc[27:48,-1] + countries_df.loc[country, 'current electricity'] = s_out['Electricity']*ktoe_to_twh + + +rename_sectors = {'elec':'electricity', + 'biomass':'solid biomass', + 'heat':'low-temperature heat'} + +countries_df.rename(columns=rename_sectors,inplace=True) + +countries_df.index.name = "TWh/a (MtCO2/a)" + +countries_df.to_csv(snakemake.output.industrial_energy_demand_per_country, + float_format='%.2f') diff --git a/scripts/build_industrial_energy_demand_per_country_today.py b/scripts/build_industrial_energy_demand_per_country_today.py new file mode 100644 index 00000000..7593477b --- /dev/null +++ b/scripts/build_industrial_energy_demand_per_country_today.py @@ -0,0 +1,140 @@ + +import pandas as pd + +# sub-sectors as used in PyPSA-Eur-Sec and listed in JRC-IDEES industry sheets +sub_sectors = {'Iron and steel' : ['Integrated steelworks','Electric arc'], + 'Non-ferrous metals' : ['Alumina production','Aluminium - primary production','Aluminium - secondary production','Other non-ferrous metals'], + 'Chemicals' : ['Basic chemicals', 'Other chemicals', 'Pharmaceutical products etc.', 'Basic chemicals feedstock'], + 'Non-metalic mineral' : ['Cement','Ceramics & other NMM','Glass production'], + 'Printing' : ['Pulp production','Paper production','Printing and media reproduction'], + 'Food' : ['Food, beverages and tobacco'], + 'Transport equipment' : ['Transport Equipment'], + 'Machinery equipment' : ['Machinery Equipment'], + 'Textiles and leather' : ['Textiles and leather'], + 'Wood and wood products' : ['Wood and wood products'], + 'Other Industrial Sectors' : ['Other Industrial Sectors'], +} + + +# name in JRC-IDEES Energy Balances +eb_sheet_name = {'Integrated steelworks' : 'cisb', + 'Electric arc' : 'cise', + 'Alumina production' : 'cnfa', + 'Aluminium - primary production' : 'cnfp', + 'Aluminium - secondary production' : 'cnfs', + 'Other non-ferrous metals' : 'cnfo', + 'Basic chemicals' : 'cbch', + 'Other chemicals' : 'coch', + 'Pharmaceutical products etc.' : 'cpha', + 'Basic chemicals feedstock' : 'cpch', + 'Cement' : 'ccem', + 'Ceramics & other NMM' : 'ccer', + 'Glass production' : 'cgla', + 'Pulp production' : 'cpul', + 'Paper production' : 'cpap', + 'Printing and media reproduction' : 'cprp', + 'Food, beverages and tobacco' : 'cfbt', + 'Transport Equipment' : 'ctre', + 'Machinery Equipment' : 'cmae', + 'Textiles and leather' : 'ctel', + 'Wood and wood products' : 'cwwp', + 'Mining and quarrying' : 'cmiq', + 'Construction' : 'ccon', + 'Non-specified': 'cnsi', +} + + + +fuels = {'all' : ['All Products'], + 'solid' : ['Solid Fuels'], + 'liquid' : ['Total petroleum products (without biofuels)'], + 'gas' : ['Gases'], + 'heat' : ['Nuclear heat','Derived heat'], + 'biomass' : ['Biomass and Renewable wastes'], + 'waste' : ['Wastes (non-renewable)'], + 'electricity' : ['Electricity'], +} + +ktoe_to_twh = 0.011630 + +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'] + +jrc_names = {"GR" : "EL", + "GB" : "UK"} + +year = 2015 +summaries = {} + +#for some reason the Energy Balances list Other Industrial Sectors separately +ois_subs = ['Mining and quarrying','Construction','Non-specified'] + + +#MtNH3/a +ammonia = pd.read_csv(snakemake.input.ammonia_production, + index_col=0)/1e3 + + + +for ct in eu28: + print(ct) + filename = 'data/jrc-idees-2015/JRC-IDEES-2015_EnergyBalance_{}.xlsx'.format(jrc_names.get(ct,ct)) + + summary = pd.DataFrame(index=list(fuels.keys()) + ['other']) + + for sector in sub_sectors: + if sector == 'Other Industrial Sectors': + subs = ois_subs + else: + subs = sub_sectors[sector] + + for sub in subs: + df = pd.read_excel(filename, + sheet_name=eb_sheet_name[sub], + index_col=0) + + s = df[year].astype(float) + + for fuel in fuels: + summary.at[fuel,sub] = s[fuels[fuel]].sum() + summary.at['other',sub] = summary.at['all',sub] - summary.loc[summary.index^['all','other'],sub].sum() + + summary['Other Industrial Sectors'] = summary[ois_subs].sum(axis=1) + summary.drop(columns=ois_subs,inplace=True) + + summary.drop(index=['all'],inplace=True) + + summary *= ktoe_to_twh + + summary['Basic chemicals'] += summary['Basic chemicals feedstock'] + summary.drop(columns=['Basic chemicals feedstock'], inplace=True) + + summary['Ammonia'] = 0. + summary.at['gas','Ammonia'] = snakemake.config['industry']['MWh_CH4_per_tNH3_SMR']*ammonia[str(year)].get(ct,0.) + summary.at['electricity','Ammonia'] = snakemake.config['industry']['MWh_elec_per_tNH3_SMR']*ammonia[str(year)].get(ct,0.) + summary['Basic chemicals (without ammonia)'] = summary['Basic chemicals'] - summary['Ammonia'] + summary.loc[summary['Basic chemicals (without ammonia)'] < 0, 'Basic chemicals (without ammonia)'] = 0. + summary.drop(columns=['Basic chemicals'], inplace=True) + + summaries[ct] = summary + +final_summary = pd.concat(summaries,axis=1) + +# add in the non-EU28 based on their output (which is derived from their energy too) +# output in MtMaterial/a +output = pd.read_csv(snakemake.input.industrial_production_per_country, + index_col=0)/1e3 + +eu28_averages = final_summary.groupby(level=1,axis=1).sum().divide(output.loc[eu28].sum(),axis=1) + +non_eu28 = output.index^eu28 + +for ct in non_eu28: + print(ct) + final_summary = pd.concat((final_summary,pd.concat({ct : eu28_averages.multiply(output.loc[ct],axis=1)},axis=1)),axis=1) + + +final_summary.index.name = 'TWh/a' + +final_summary.to_csv(snakemake.output.industrial_energy_demand_per_country_today) diff --git a/scripts/build_industrial_demand_per_country.py b/scripts/build_industrial_production_per_country.py similarity index 72% rename from scripts/build_industrial_demand_per_country.py rename to scripts/build_industrial_production_per_country.py index 7d7d0ef3..c8fa6910 100644 --- a/scripts/build_industrial_demand_per_country.py +++ b/scripts/build_industrial_production_per_country.py @@ -1,26 +1,17 @@ - -#%matplotlib inline import pandas as pd import numpy as np +tj_to_ktoe = 0.0238845 +ktoe_to_twh = 0.01163 jrc_base_dir = "data/jrc-idees-2015" eb_base_dir = "data/eurostat-energy_balances-may_2018_edition" - - -tj_to_ktoe = 0.0238845 - -ktoe_to_twh = 0.01163 - -# import EU ratios df as csv -df=pd.read_csv('resources/industry_sector_ratios.csv', sep=';', index_col=0) - - - - +# year for which data is retrieved +raw_year = 2015 +year = raw_year-2016 sub_sheet_name_dict = { 'Iron and steel':'ISI', 'Chemicals Industry':'CHI', @@ -36,20 +27,17 @@ sub_sheet_name_dict = { 'Iron and steel':'ISI', index = ['elec','biomass','methane','hydrogen','heat','naphtha','process emission','process emission from feedstock'] -countries_df = pd.DataFrame(columns=index) #data frame final energy consumption per country and source - - non_EU = ['NO', 'CH', 'ME', 'MK', 'RS', 'BA', 'AL'] -rename = {"GR" : "EL", - "GB" : "UK"} +jrc_names = {"GR" : "EL", + "GB" : "UK"} -eu28 = ['FR', 'DE', 'GB', 'IT', 'ES', 'PL', 'SE', 'NL', 'BE', 'FI', 'CZ', - 'DK', 'PT', 'RO', 'AT', 'BG', 'EE', 'GR', 'LV', - 'HU', 'IE', 'SK', 'LT', 'HR', 'LU', 'SI'] + ['CY','MT'] +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'] -countries = non_EU + [rename.get(eu,eu) for eu in eu28[:-2]] +countries = non_EU + eu28 sectors = ['Iron and steel','Chemicals Industry','Non-metallic mineral products', @@ -69,6 +57,14 @@ sect2sub = {'Iron and steel':['Electric arc','Integrated steelworks'], 'Wood and wood products' :['Wood and wood products'], 'Other Industrial Sectors':['Other Industrial Sectors']} +subsectors = [ss for s in sectors for ss in sect2sub[s]] + +#material demand per country and industry (kton/a) +countries_demand = pd.DataFrame(index=countries, + columns=subsectors, + dtype=float) + + out_dic ={'Electric arc': 'Electric arc', 'Integrated steelworks': 'Integrated steelworks', 'Basic chemicals': 'Basic chemicals (kt ethylene eq.)', @@ -117,10 +113,11 @@ dic_sec_summary = {'Iron and steel': 'Iron and steel', 'Other Industrial Sectors': ' Other Industrial Sectors'} #countries=['CH'] -dic_countries={'NO':'Norway', 'AL':'Albania', 'BA':'Bosnia and Herzegovina', - 'MK':'FYR of Macedonia', 'GE':'Georgia', 'IS':'Iceland', - 'KO':'Kosovo', 'MD':'Moldova', 'ME':'Montenegro', 'RS':'Serbia', - 'UA':'Ukraine', 'TR':'Turkey', } +eb_names={'NO':'Norway', 'AL':'Albania', 'BA':'Bosnia and Herzegovina', + 'MK':'FYR of Macedonia', 'GE':'Georgia', 'IS':'Iceland', + 'KO':'Kosovo', 'MD':'Moldova', 'ME':'Montenegro', 'RS':'Serbia', + 'UA':'Ukraine', 'TR':'Turkey', } + dic_sec ={'Iron and steel':'Iron & steel industry', 'Chemicals Industry': 'Chemical and Petrochemical industry', 'Non-metallic mineral products': 'Non-ferrous metal industry', @@ -153,8 +150,8 @@ dic_Switzerland ={'Iron and steel': 7889., dic_sec_position={} for country in countries: - countries_df.loc[country] = 0 - print (country) + countries_demand.loc[country] = 0. + print(country) for sector in sectors: if country in non_EU: if country == 'CH': @@ -162,14 +159,14 @@ for country in countries: else: # estimate physical output #energy consumption in the sector and country - excel_balances = pd.read_excel('{}/{}.XLSX'.format(eb_base_dir,dic_countries[country]), + excel_balances = pd.read_excel('{}/{}.XLSX'.format(eb_base_dir,eb_names[country]), sheet_name='2016', index_col=2,header=0, skiprows=1 ,squeeze=True) e_country = excel_balances.loc[dic_sec[sector], 'Total all products'] #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 @@ -177,62 +174,45 @@ 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]: - output = ratio_country_EU28*s_out[out_dic[subsector]] - - for ind in index: - countries_df.loc[country, ind] += float(output*df.loc[ind, subsector]) # kton * MWh = GWh (# kton * tCO2 = ktCO2) + countries_demand.loc[country,subsector] = ratio_country_EU28*s_out[out_dic[subsector]] else: # read the input sheets - excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(jrc_base_dir,country), sheet_name=sub_sheet_name_dict[sector],index_col=0,header=0,squeeze=True) # the summary sheet + 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]: - output = s_out[out_dic[subsector]] - for ind in index: - countries_df.loc[country, ind] += output*df.loc[ind, subsector] #kton * MWh = GWh (# kton * tCO2 = ktCO2) - -countries_df*= 0.001 #GWh -> TWh (ktCO2 -> MtCO2) - -# save current electricity consumption -for country in countries: - if country in non_EU: - if country == 'CH': - countries_df.loc[country, 'current electricity']=dic_Switzerland['current electricity']*tj_to_ktoe*ktoe_to_twh - else: - excel_balances = pd.read_excel('{}/{}.XLSX'.format(eb_base_dir,dic_countries[country]), - sheet_name='2016', index_col=1,header=0, skiprows=1 ,squeeze=True) - - countries_df.loc[country, 'current electricity'] = excel_balances.loc['Industry', 'Electricity']*ktoe_to_twh - - else: - - excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(jrc_base_dir,country), - sheet_name='Ind_Summary',index_col=0,header=0,squeeze=True) # the summary sheet - - s_out = excel_out.iloc[27:48,-1] - countries_df.loc[country, 'current electricity'] = s_out['Electricity']*ktoe_to_twh - print(countries_df.loc[country, 'current electricity']) + countries_demand.loc[country,subsector] = s_out[out_dic[subsector]] +#include ammonia demand separately and remove ammonia from basic chemicals -# save df as csv -for ind in index: - countries_df[ind]=countries_df[ind].astype('float') -countries_df = countries_df.round(3) +ammonia = pd.read_csv(snakemake.input.ammonia_production, + index_col=0) -countries_df.rename(index={value : key for key,value in rename.items()},inplace=True) +there = ammonia.index.intersection(countries_demand.index) +missing = countries_demand.index^there -rename_sectors = {'elec':'electricity', - 'biomass':'solid biomass', - 'heat':'low-temperature heat'} +print("Following countries have no ammonia demand:", missing) -countries_df.rename(columns=rename_sectors,inplace=True) +countries_demand.insert(2,"Ammonia",0.) -countries_df.to_csv('resources/industrial_demand_per_country.csv', - float_format='%.2f') +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, + float_format='%.2f') diff --git a/scripts/build_industrial_production_per_country_tomorrow.py b/scripts/build_industrial_production_per_country_tomorrow.py new file mode 100644 index 00000000..1bfc40f2 --- /dev/null +++ b/scripts/build_industrial_production_per_country_tomorrow.py @@ -0,0 +1,27 @@ + +import pandas as pd + +industrial_production = pd.read_csv(snakemake.input.industrial_production_per_country, + index_col=0) + +total_steel = industrial_production[["Integrated steelworks","Electric arc"]].sum(axis=1) + +fraction_primary_stays_primary = snakemake.config["industry"]["St_primary_fraction"]*total_steel.sum()/industrial_production["Integrated steelworks"].sum() + +industrial_production.insert(2, "DRI + Electric arc", + fraction_primary_stays_primary*industrial_production["Integrated steelworks"]) + +industrial_production["Electric arc"] = total_steel - industrial_production["DRI + Electric arc"] +industrial_production["Integrated steelworks"] = 0. + + +total_aluminium = industrial_production[["Aluminium - primary production","Aluminium - secondary production"]].sum(axis=1) + +fraction_primary_stays_primary = snakemake.config["industry"]["Al_primary_fraction"]*total_aluminium.sum()/industrial_production["Aluminium - primary production"].sum() + +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.to_csv(snakemake.output.industrial_production_per_country_tomorrow, + float_format='%.2f') diff --git a/scripts/build_industry_sector_ratios.py b/scripts/build_industry_sector_ratios.py index 5d3acb9c..810b242a 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' @@ -26,7 +26,7 @@ sub_sheet_name_dict = { 'Iron and steel':'ISI', 'Wood and wood products': 'WWP', 'Other Industrial Sectors': 'OIS'} -index = ['elec','biomass','methane','hydrogen','heat','naphtha','process emission','process emission from feedstock'] +index = ['elec','coal','coke','biomass','methane','hydrogen','heat','naphtha','process emission','process emission from feedstock'] df = pd.DataFrame(index=index) @@ -58,7 +58,7 @@ excel_emi = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(base_dir,c sector = 'Electric arc' -df[sector] = 0 +df[sector] = 0. # read the corresponding lines s_fec = excel_fec.iloc[51:57,year] @@ -150,21 +150,122 @@ df.loc['process emission',sector] = s_emi['Process emissions']/s_out[sector] # u # final energy consumption per t df.loc[['elec','heat','methane'],sector] = df.loc[['elec','heat','methane'],sector]*conv_factor/s_out[sector] # unit MWh/t material +### For primary route: DRI with H2 + EAF - -## Integrated steelworks is converted to Electric arc -# -#> Electric arc uses scrap metal and Direct Reduced Iron -# -#> We assume that when substituting Integrated Steelworks by Electric arc furnaces. -#> 50% of Integrated steelworks is substituted by scrap metal + electric furnaces -#> 50% of Integrated steelworks is substituted by Direct Reduce Iron (with Hydrogen) + electric furnaces - -df['Integrated steelworks']=df['Electric arc'] +df['DRI + Electric arc'] = df['Electric arc'] # adding the Hydrogen necessary for the Direct Reduction of Iron. consumption 1.7 MWh H2 /ton steel -#(0.5 because only half of the steel requires DRI, the rest is scrap metal) -df.loc['hydrogen', 'Integrated steelworks'] =snakemake.config["industry"]["H2_DRI"] * snakemake.config["industry"]["DRI_ratio"] +df.loc['hydrogen', 'DRI + Electric arc'] = snakemake.config["industry"]["H2_DRI"] +# add electricity consumption in DRI shaft (0.322 MWh/tSl) +df.loc['elec', 'DRI + Electric arc'] += snakemake.config["industry"]["elec_DRI"] + + +### Integrated steelworks (could be used in combination with CCS) +### Assume existing fuels are kept, except for furnaces, refining, rolling, finishing +### Ignore 'derived gases' since these are top gases from furnaces + +sector = 'Integrated steelworks' + +df['Integrated steelworks']= 0. + +# read the corresponding lines +s_fec = excel_fec.iloc[3:9,year] + +assert s_fec.index[0] == sector + +# Lighting, Air compressors, Motor drives, Fans and pumps +df.loc['elec',sector] += s_fec[['Lighting','Air compressors','Motor drives','Fans and pumps']].sum() + +# Low enthalpy heat +df.loc['heat',sector] += s_fec['Low enthalpy heat'] + + +#### Steel: Sinter/Pellet making + +subsector = 'Steel: Sinter/Pellet making' + +# read the corresponding lines +s_fec = excel_fec.iloc[13:19,year] + +s_ued = excel_ued.iloc[13:19,year] + +assert s_fec.index[0] == subsector + +df.loc['elec',sector] += s_fec['Electricity'] +df.loc['methane',sector] += s_fec['Natural gas (incl. biogas)'] +df.loc['methane',sector] += s_fec['Residual fuel oil'] +df.loc['coal',sector] += s_fec['Solids'] + + +#### Steel: Blast / Basic Oxygen Furnace + +subsector = 'Steel: Blast /Basic oxygen furnace' + +# read the corresponding lines +s_fec = excel_fec.iloc[19:25,year] + +s_ued = excel_ued.iloc[19:25,year] + +assert s_fec.index[0] == subsector + +df.loc['methane',sector] += s_fec['Natural gas (incl. biogas)'] +df.loc['methane',sector] += s_fec['Residual fuel oil'] +df.loc['coal',sector] += s_fec['Solids'] +df.loc['coke',sector] += s_fec['Coke'] + + +#### Steel: Furnaces, Refining and Rolling +#> assume fully electrified +# +#> other processes are scaled by the used energy + +subsector = 'Steel: Furnaces, Refining and Rolling' + +# read the corresponding lines +s_fec = excel_fec.iloc[25:32,year] + +s_ued = excel_ued.iloc[25:32,year] + +assert s_fec.index[0] == subsector + +# this process can be electrified +eff = s_ued['Steel: Furnaces, Refining and Rolling - Electric']/s_fec['Steel: Furnaces, Refining and Rolling - Electric'] + +df.loc['elec',sector] += s_ued[subsector]/eff + +#### Steel: Products finishing +#> assume fully electrified + +subsector = 'Steel: Products finishing' + +# read the corresponding lines +s_fec = excel_fec.iloc[32:49,year] + +s_ued = excel_ued.iloc[32:49,year] + +assert s_fec.index[0] == subsector + +# this process can be electrified +eff = s_ued['Steel: Products finishing - Electric']/s_fec['Steel: Products finishing - Electric'] + +df.loc['elec',sector] += s_ued[subsector]/eff + + +#### Process emissions (per physical output) + +s_emi = excel_emi.iloc[3:50,year] + +assert s_emi.index[0] == sector + +s_out = excel_out.iloc[6:7,year] + +assert sector in str(s_out.index) + +df.loc['process emission',sector] = s_emi['Process emissions']/s_out[sector] # unit tCO2/t material + +# final energy consumption per t +df.loc[['elec','heat','methane','coke','coal'],sector] = df.loc[['elec','heat','methane','coke','coal'],sector]*conv_factor/s_out[sector] # unit MWh/t material + ## Chemicals Industry @@ -186,6 +287,8 @@ excel_emi = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(base_dir,c ### Basic chemicals +## Ammonia is separated afterwards + sector = 'Basic chemicals' df[sector] = 0 @@ -204,9 +307,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)' @@ -219,19 +321,16 @@ 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'] + s_fec['Residual fuel oil'] + s_fec['Other liquids']) #### Chemicals: Steam processing -#> All the final energy consumption in the Stem processing is converted to biomass. +#> All the final energy consumption in the Steam processing is converted to methane, since we need >1000 C temperatures here. # -#> The current efficiency of biomass is assumed in the conversion. +#> The current efficiency of methane is assumed in the conversion. subsector = 'Chemicals: Steam processing' @@ -242,11 +341,11 @@ s_ued = excel_ued.iloc[22:33,year] assert s_fec.index[0] == subsector -# efficiency of biomass -eff_bio = s_ued['Biomass']/s_fec['Biomass'] +# efficiency of natural gas +eff_ch4 = s_ued['Natural gas (incl. biogas)']/s_fec['Natural gas (incl. biogas)'] -# replace all fec by biomass -df.loc['biomass',sector] += s_ued[subsector]/eff_bio +# replace all fec by methane +df.loc['methane',sector] += s_ued[subsector]/eff_ch4 #### Chemicals: Furnaces #> assume fully electrified @@ -298,10 +397,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 @@ -311,8 +425,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 @@ -405,7 +535,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. @@ -495,7 +625,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 @@ -527,7 +657,7 @@ excel_emi = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(base_dir,c # #> Temperatures above 1400C are required for procesing limestone and sand into clinker. # -#> Everything (except current electricity and heat consumption) is transformed into biomass +#> Everything (except current electricity and heat consumption and existing biomass) is transformed into methane for high T. sector = 'Cement' @@ -546,10 +676,11 @@ df.loc['elec',sector] += s_fec[['Lighting','Air compressors','Motor drives','Fan # Low enthalpy heat df.loc['heat',sector] += s_fec['Low enthalpy heat'] -# Efficiency changes due to biomass -eff_bio=s_ued['Biomass']/s_fec['Biomass'] +# pre-processing: keep existing elec and biomass, rest to methane +df.loc['elec', sector] += s_fec['Cement: Grinding, milling of raw material'] +df.loc['biomass', sector] += s_fec['Biomass'] +df.loc['methane', sector] += s_fec['Cement: Pre-heating and pre-calcination'] - s_fec['Biomass'] -df.loc['biomass', sector] += s_ued[['Cement: Grinding, milling of raw material', 'Cement: Pre-heating and pre-calcination']].sum()/eff_bio #### Cement: Clinker production (kilns) @@ -562,10 +693,10 @@ s_ued = excel_ued.iloc[34:43,year] assert s_fec.index[0] == subsector -# Efficiency changes due to biomass -eff_bio=s_ued['Biomass']/s_fec['Biomass'] +df.loc['biomass', sector] += s_fec['Biomass'] +df.loc['methane', sector] += s_fec['Cement: Clinker production (kilns)'] - s_fec['Biomass'] +df.loc['elec', sector] += s_fec['Cement: Grinding, packaging'] -df.loc['biomass', sector] += s_ued[['Cement: Clinker production (kilns)', 'Cement: Grinding, packaging']].sum()/eff_bio #### Process-emission came from the calcination of limestone to chemically reactive calcium oxide (lime). #> Calcium carbonate -> lime + CO2 @@ -635,7 +766,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 @@ -707,7 +838,7 @@ excel_out = pd.read_excel('{}/JRC-IDEES-2015_Industry_{}.xlsx'.format(base_dir,c # #> Includes three subcategories: (a) Wood preparation, grinding; (b) Pulping; (c) Cleaning. # -#> (b) Pulping is electrified. The efficiency is calculated from the pulping process that is already electric. +#> (b) Pulping is either biomass or electric; left like this (dominated by biomass). # #> (a) Wood preparation, grinding and (c) Cleaning represent only 10% their current energy consumption is assumed to be electrified without any change in efficiency @@ -729,14 +860,11 @@ df.loc['elec', sector] += s_fec[['Lighting','Air compressors','Motor drives','Fa df.loc['heat', sector] += s_fec['Low enthalpy heat'] # Industry-specific -df.loc['elec', sector] += s_fec[['Pulp: Wood preparation, grinding', 'Pulp: Cleaning']].sum() +df.loc['elec', sector] += s_fec[['Pulp: Wood preparation, grinding', 'Pulp: Cleaning', 'Pulp: Pulping electric']].sum() -# Efficiency changes due to electrification -eff_elec=s_ued['Pulp: Pulping electric']/s_fec['Pulp: Pulping electric'] -df.loc['elec', sector] += s_ued['Pulp: Pulping thermal']/eff_elec - -# add electricity from process that is already electrified -df.loc['elec', sector] += s_fec['Pulp: Pulping electric'] +# Efficiency changes due to biomass +eff_bio=s_ued['Biomass']/s_fec['Biomass'] +df.loc['biomass', sector] += s_ued['Pulp: Pulping thermal']/eff_bio s_out = excel_out.iloc[8:9,year] @@ -751,7 +879,7 @@ df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out['Pulp producti # #> Includes three subcategories: (a) Stock preparation; (b) Paper machine; (c) Product finishing. # -#> (b) Paper machine and (c) Product finishing are electrified. The efficiency is calculated from the pulping process that is already electric. +#> (b) Paper machine and (c) Product finishing are left electric and thermal is moved to biomass. The efficiency is calculated from the pulping process that is already biomass. # #> (a) Stock preparation represents only 7% and its current energy consumption is assumed to be electrified without any change in efficiency. @@ -775,16 +903,35 @@ df.loc['heat', sector] += s_fec['Low enthalpy heat'] # Industry-specific df.loc['elec', sector] += s_fec['Paper: Stock preparation'] -# Efficiency changes due to electrification -eff_elec=s_ued['Paper: Paper machine - Electricity']/s_fec['Paper: Paper machine - Electricity'] -df.loc['elec', sector] += s_ued['Paper: Paper machine - Steam use']/eff_elec - -eff_elec=s_ued['Paper: Product finishing - Electricity']/s_fec['Paper: Product finishing - Electricity'] -df.loc['elec', sector] += s_ued['Paper: Product finishing - Steam use']/eff_elec - # add electricity from process that is already electrified df.loc['elec', sector] += s_fec['Paper: Paper machine - Electricity'] +# add electricity from process that is already electrified +df.loc['elec', sector] += s_fec['Paper: Product finishing - Electricity'] + + +s_fec = excel_fec.iloc[53:64,year] + +s_ued = excel_ued.iloc[53:64,year] + +assert s_fec.index[0] == 'Paper: Paper machine - Steam use' + +# Efficiency changes due to biomass +eff_bio=s_ued['Biomass']/s_fec['Biomass'] +df.loc['biomass', sector] += s_ued['Paper: Paper machine - Steam use']/eff_bio + + +s_fec = excel_fec.iloc[66:77,year] + +s_ued = excel_ued.iloc[66:77,year] + +assert s_fec.index[0] == 'Paper: Product finishing - Steam use' + +# Efficiency changes due to biomass +eff_bio=s_ued['Biomass']/s_fec['Biomass'] +df.loc['biomass', sector] += s_ued['Paper: Product finishing - Steam use']/eff_bio + + # read the corresponding lines s_out = excel_out.iloc[9:10,year] @@ -878,8 +1025,8 @@ df.loc['elec', sector] += s_ued['Food: Drying']/eff_elec eff_elec=s_ued['Food: Electric cooling']/s_fec['Food: Electric cooling'] df.loc['elec', sector] += s_ued['Food: Process cooling and refrigeration']/eff_elec -# Steam processing is electrified without change in efficiency -df.loc['elec', sector] += s_fec['Food: Steam processing'] +# Steam processing goes all to biomass without change in efficiency +df.loc['biomass', sector] += s_fec['Food: Steam processing'] # add electricity from process that is already electrified df.loc['elec', sector] += s_fec['Food: Electric machinery'] @@ -1052,9 +1199,6 @@ sources=['elec','biomass', 'methane', 'hydrogen', 'heat','naphtha'] df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out['Aluminium - secondary production'] # unit MWh/t material # 1 ktoe = 11630 MWh -# primary route is divided into 50% remains as today and 50% is transformed into secondary route -df.loc[sources,'Aluminium - primary production'] = (1-snakemake.config["industry"]["Al_to_scrap"])*df.loc[sources,'Aluminium - primary production'] + snakemake.config["industry"]["Al_to_scrap"]*df.loc[sources,'Aluminium - secondary production'] -df.loc['process emission','Aluminium - primary production'] = (1-snakemake.config["industry"]["Al_to_scrap"])*df.loc['process emission','Aluminium - primary production'] ### Other non-ferrous metals @@ -1372,4 +1516,5 @@ sources=['elec','biomass', 'methane', 'hydrogen', 'heat','naphtha'] df.loc[sources,sector] = df.loc[sources,sector]*conv_factor/s_out['Physical output (index)'] # unit MWh/t material -df.to_csv('resources/industry_sector_ratios.csv', sep=';') +df.index.name = "MWh/tMaterial" +df.to_csv('resources/industry_sector_ratios.csv') diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index bdddd2cf..eef8206b 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -655,7 +655,8 @@ def insert_electricity_distribution_grid(network): lifetime=costs.at['electricity distribution grid','lifetime'], capital_cost=costs.at['electricity distribution grid','fixed']*snakemake.config["sector"]['electricity_distribution_grid_cost_factor']) - loads = network.loads.index[network.loads.carrier=="electricity"] + #this catches regular electricity load and "industry new electricity" + loads = network.loads.index[network.loads.carrier.str.contains("electricity")] network.loads.loc[loads,"bus"] += " low voltage" bevs = network.links.index[network.links.carrier == "BEV charger"]