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

Separate basic chemicals into HVC, chlorine, methanol and ammonia #166

Merged
merged 10 commits into from
Sep 28, 2021
21 changes: 17 additions & 4 deletions config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ electricity:

# regulate what components with which carriers are kept from PyPSA-Eur;
# some technologies are removed because they are implemented differently
# (e.g. battery or H2 storage) or have different year-dependent costs
# (e.g. battery or H2 storage) or have different year-dependent costs
# in PyPSA-Eur-Sec
pypsa_eur:
Bus:
Expand Down Expand Up @@ -270,10 +270,23 @@ 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
HVC_primary_fraction: 1. # fraction of today's HVC produced via primary route
HVC_mechanical_recycling_fraction: 0. # fraction of today's HVC produced via mechanical recycling
HVC_chemical_recycling_fraction: 0. # fraction of today's HVC produced via chemical recycling
fneum marked this conversation as resolved.
Show resolved Hide resolved
HVC_production_today: 52. # MtHVC/a from DECHEMA (2017), Figure 16, page 107; includes ethylene, propylene and BTX
MWh_elec_per_tHVC_mechanical_recycling: 3. # estimate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MWh_elec_per_tHVC_mechanical_recycling: 3. # estimate
MWh_elec_per_tHVC_mechanical_recycling: 0.547 # from SI of https://doi.org/10.1016/j.resconrec.2020.105010, Table S5, for HDPE, PP, PS, PET. LDPE would be 0.756.

Adds the energy use of mechanical recycling.

I have assumed energy demand for recycling of HPTE, PET, PS, PP as they are all very similar whereas LDPE is higher as well as more difficult to recycle.

https://www.generalkinematics.com/blog/different-types-plastics-recycled/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! Also for reference, another source doi:10.1016/j.scitotenv.2017.05.278 with somewhat lower energy demand around 0.3 MWh/tPlastic. We can take the newer higher number.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also check that the numbers from https://doi.org/10.1016/j.resconrec.2020.105010 are consistent with our chemical recycling assumptions? @brynpickering warned about reliability of Material Economics numbers in a private email.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The paper describes for routes of chemical recycling:

  1. refinery feedstock: liquefy plastic -> use as a substitute for oil or naphtha in refinery and steam cracking processes
  2. fuel production: gasification / pyrolysis -> gaseous / liquid fuels
  3. monomer production: polyolefins -> monomers (e.g. ethylene) through thermal/catalytic pyrolysis
  4. chemical upcycling

Route 3) comes closes to the Material Economics study (which uses pyrolysis and electric steam cracking and methanol synthesis to produce HVC from HVC for which they need 6.9 kWh/kg electricity with a yield of 0.91 kg/kg).

Route 3) in the paper following table S10 in the SI requires 3 MJ/kg (0.78 kWh/kg) of heat to turn HDPE into ethylene with a yield of 0.85 kg_ethylene / kg.

Not sure how conclusive this comparison is. Seems Material Economics numbers are a bit high?

*polyolefins: LDPE, HDPE, PP
*HVC: ethylene, propylene, polyolefins etc.

MWh_elec_per_tHVC_chemical_recycling: 6.9 # Material Economics (2019), page 125; based on pyrolysis and steam cracking
chlorine_production_today: 9.58 # MtCl/a from DECHEMA (2017), Table 7, page 43
MWh_elec_per_tCl: 3.6 # DECHEMA (2017), Table 6, page 43
MWh_H2_per_tCl: -0.9372 # DECHEMA (2017), page 43; negative since hydrogen produced in chloralkali process
methanol_production_today: 1.5 # MtMeOH/a from DECHEMA (2017), page 62
MWh_elec_per_tMeOH: 0.167 # DECHEMA (2017), Table 14, page 65
MWh_CH4_per_tMeOH: 10.25 # DECHEMA (2017), Table 14, page 65
hotmaps_locate_missing: false
reference_year: 2015

# references:
# DECHEMA (2017): https://dechema.de/dechema_media/Downloads/Positionspapiere/Technology_study_Low_carbon_energy_and_feedstock_for_the_European_chemical_industry-p-20002750.pdf
# Material Economics (2019): https://materialeconomics.com/latest-updates/industrial-transformation-2050

costs:
lifetime: 25 #default lifetime
Expand Down Expand Up @@ -335,7 +348,7 @@ solving:

plotting:
map:
boundaries: [-11, 30, 34, 71]
boundaries: [-11, 30, 34, 71]
color_geomap:
ocean: white
land: whitesmoke
Expand Down
5 changes: 5 additions & 0 deletions scripts/build_industrial_energy_demand_per_country_today.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ def add_non_eu28_industrial_energy_demand(demand):
fn = snakemake.input.industrial_production_per_country
production = pd.read_csv(fn, index_col=0) / 1e3

#recombine HVC, Chlorine and Methanol to Basic chemicals (without ammonia)
chemicals = ["HVC", "Chlorine", "Methanol"]
production["Basic chemicals (without ammonia)"] = production[chemicals].sum(axis=1)
production.drop(columns=chemicals, inplace=True)

eu28_production = production.loc[eu28].sum()
eu28_energy = demand.groupby(level=1).sum()
eu28_averages = eu28_energy / eu28_production
Expand Down
19 changes: 14 additions & 5 deletions scripts/build_industrial_production_per_country.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ def industry_production(countries):
return demand


def add_ammonia_demand_separately(demand):
"""Include ammonia demand separately and remove ammonia from basic chemicals."""
def separate_basic_chemicals(demand):
"""Remove ammonia, chlorine and methanol from basic chemicals to get HVC."""
fneum marked this conversation as resolved.
Show resolved Hide resolved

ammonia = pd.read_csv(snakemake.input.ammonia_production, index_col=0)

Expand All @@ -198,9 +198,16 @@ def add_ammonia_demand_separately(demand):
# EE, HR and LT got negative demand through subtraction - poor data
demand['Basic chemicals'].clip(lower=0., inplace=True)

to_rename = {"Basic chemicals": "Basic chemicals (without ammonia)"}
demand.rename(columns=to_rename, inplace=True)
demand.insert(2, "HVC", 0.)
demand.insert(3, "Chlorine", 0.)
demand.insert(4, "Methanol", 0.)
fneum marked this conversation as resolved.
Show resolved Hide resolved

# assume HVC, methanol, chlorine production proportional to non-ammonia basic chemicals
demand["HVC"] = config["HVC_production_today"]*1e3/demand["Basic chemicals"].sum()*demand["Basic chemicals"]
demand["Chlorine"] = config["chlorine_production_today"]*1e3/demand["Basic chemicals"].sum()*demand["Basic chemicals"]
demand["Methanol"] = config["methanol_production_today"]*1e3/demand["Basic chemicals"].sum()*demand["Basic chemicals"]
fneum marked this conversation as resolved.
Show resolved Hide resolved

demand.drop(columns=["Basic chemicals"], inplace=True)

if __name__ == '__main__':
if 'snakemake' not in globals():
Expand All @@ -211,12 +218,14 @@ def add_ammonia_demand_separately(demand):

year = snakemake.config['industry']['reference_year']

config = snakemake.config["industry"]

jrc_dir = snakemake.input.jrc
eurostat_dir = snakemake.input.eurostat

demand = industry_production(countries)

add_ammonia_demand_separately(demand)
separate_basic_chemicals(demand)

fn = snakemake.output.industrial_production_per_country
demand.to_csv(fn, float_format='%.2f')
7 changes: 5 additions & 2 deletions scripts/build_industrial_production_per_country_tomorrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@

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]

production["Basic chemicals (without ammonia)"] *= config['HVC_primary_fraction']
production.insert(4, "HVC (mechanical recycling)", config["HVC_mechanical_recycling_fraction"]*production["HVC"])
production.insert(5, "HVC (chemical recycling)", config["HVC_chemical_recycling_fraction"]*production["HVC"])
fneum marked this conversation as resolved.
Show resolved Hide resolved

production["HVC"] *= config['HVC_primary_fraction']

fn = snakemake.output.industrial_production_per_country_tomorrow
production.to_csv(fn, float_format='%.2f')
10 changes: 7 additions & 3 deletions scripts/build_industrial_production_per_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
'Integrated steelworks': 'Iron and steel',
'DRI + Electric arc': 'Iron and steel',
'Ammonia': 'Chemical industry',
'Basic chemicals (without ammonia)': 'Chemical industry',
'HVC': 'Chemical industry',
'HVC (mechanical recycling)': 'Chemical industry',
'HVC (chemical recycling)': 'Chemical industry',
'Methanol': 'Chemical industry',
'Chlorine': 'Chemical industry',
'Other chemicals': 'Chemical industry',
'Pharmaceutical products etc.': 'Chemical industry',
'Cement': 'Cement',
Expand Down Expand Up @@ -40,12 +44,12 @@ def build_nodal_industrial_production():

countries = keys.country.unique()
sectors = industrial_production.columns

for country, sector in product(countries, sectors):

buses = keys.index[keys.country == country]
mapping = sector_mapping.get(sector, "population")

key = keys.loc[buses, mapping]
nodal_production.loc[buses, sector] = industrial_production.at[country, sector] * key

Expand Down
62 changes: 47 additions & 15 deletions scripts/build_industry_sector_ratios.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def chemicals_industry():

df = pd.DataFrame(index=index)

# Basid chemicals
# Basic chemicals

sector = "Basic chemicals"

Expand Down Expand Up @@ -374,52 +374,84 @@ def chemicals_industry():
# putting in ammonia demand for H2 and electricity separately

s_emi = idees["emi"][3:57]
s_out = idees["out"][8:9]
assert s_emi.index[0] == sector
assert sector in str(s_out.index)

ammonia = pd.read_csv(snakemake.input.ammonia_production, index_col=0)

# ktNH3/a
ammonia_total = ammonia.loc[ammonia.index.intersection(eu28), str(year)].sum()

s_out -= ammonia_total
# convert from MtHVC/a to ktHVC/a
s_out = config["HVC_production_today"]*1e3
fneum marked this conversation as resolved.
Show resolved Hide resolved

# tCO2/t material
df.loc["process emission", sector] += (
s_emi["Process emissions"]
- config["petrochemical_process_emissions"] * 1e3
- config["NH3_process_emissions"] * 1e3
) / s_out.values
) / s_out

# emissions originating from feedstock, could be non-fossil origin
# tCO2/t material
df.loc["process emission from feedstock", sector] += (
config["petrochemical_process_emissions"] * 1e3
) / s_out.values
) / s_out

# convert from ktoe/a to GWh/a
sources = ["elec", "biomass", "methane", "hydrogen", "heat", "naphtha"]
df.loc[sources, sector] *= toe_to_MWh

# subtract ammonia energy demand
ammonia = pd.read_csv(snakemake.input.ammonia_production, index_col=0)
# ktNH3/a
ammonia_total = ammonia.loc[ammonia.index.intersection(eu28), str(year)].sum()
df.loc["methane", sector] -= ammonia_total * config["MWh_CH4_per_tNH3_SMR"]
df.loc["elec", sector] -= ammonia_total * config["MWh_elec_per_tNH3_SMR"]

# subtract chlorine demand
chlorine_total = config["chlorine_production_today"]
df.loc["hydrogen", sector] -= chlorine_total * config["MWh_H2_per_tCl"]
df.loc["elec", sector] -= chlorine_total * config["MWh_elec_per_tCl"]

# subtract methanol demand
methanol_total = config["methanol_production_today"]
df.loc["methane", sector] -= methanol_total * config["MWh_CH4_per_tMeOH"]
df.loc["elec", sector] -= methanol_total * config["MWh_elec_per_tMeOH"]

# MWh/t material
df.loc[sources, sector] = df.loc[sources, sector] / s_out.values
df.loc[sources, sector] = df.loc[sources, sector] / s_out

to_rename = {sector: f"{sector} (without ammonia)"}
to_rename = {sector: "HVC"}
df.rename(columns=to_rename, inplace=True)

# Ammonia
# HVC mechanical recycling

sector = "Ammonia"
sector = "HVC (mechanical recycling)"
df[sector] = 0.0
df.loc["elec", sector] = config["MWh_elec_per_tHVC_mechanical_recycling"]

# HVC chemical recycling

sector = "HVC (chemical recycling)"
df[sector] = 0.0
df.loc["elec", sector] = config["MWh_elec_per_tHVC_chemical_recycling"]

# Ammonia

sector = "Ammonia"
df[sector] = 0.0
df.loc["hydrogen", sector] = config["MWh_H2_per_tNH3_electrolysis"]
df.loc["elec", sector] = config["MWh_elec_per_tNH3_electrolysis"]

# Chlorine

sector = "Chlorine"
df[sector] = 0.0
df.loc["hydrogen", sector] = config["MWh_H2_per_tCl"]
df.loc["elec", sector] = config["MWh_elec_per_tCl"]

# Methanol

sector = "Methanol"
df[sector] = 0.0
df.loc["methane", sector] = config["MWh_CH4_per_tMeOH"]
df.loc["elec", sector] = config["MWh_elec_per_tMeOH"]

# Other chemicals

sector = "Other chemicals"
Expand Down