diff --git a/config/config.default.yaml b/config/config.default.yaml index 15ad3dd5..90a086ab 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -669,6 +669,9 @@ industry: 2040: 0.12 2045: 0.16 2050: 0.20 + HVC_environment_sequestration_fraction: 0. + waste_to_energy: false + waste_to_energy_cc: false sector_ratios_fraction_future: 2020: 0.0 2025: 0.1 @@ -1153,3 +1156,6 @@ plotting: DC-DC: "#8a1caf" DC link: "#8a1caf" load: "#dd2e23" + waste CHP: '#e3d37d' + waste CHP CC: '#e3d3ff' + HVC to air: 'k' diff --git a/config/test/config.overnight.yaml b/config/test/config.overnight.yaml index 4b627dd4..604e00d8 100644 --- a/config/test/config.overnight.yaml +++ b/config/test/config.overnight.yaml @@ -71,6 +71,11 @@ sector: gas_network: true H2_retrofit: true +industry: + HVC_environment_sequestration_fraction: 0.5 + waste_to_energy: true + waste_to_energy_cc: true + solving: solver: name: glpk diff --git a/doc/configtables/industry.csv b/doc/configtables/industry.csv index d1b560ed..cee06c97 100644 --- a/doc/configtables/industry.csv +++ b/doc/configtables/industry.csv @@ -16,6 +16,9 @@ petrochemical_process _emissions,MtCO2/a,float,The emission of petrochemical pro HVC_primary_fraction,--,float,The fraction of high value chemicals (HVC) produced via primary route HVC_mechanical_recycling _fraction,--,float,The fraction of high value chemicals (HVC) produced using mechanical recycling HVC_chemical_recycling _fraction,--,float,The fraction of high value chemicals (HVC) produced using chemical recycling +HVC_environment_sequestration_fraction,--,float,The fraction of high value chemicals (HVC) put into landfill resulting in additional carbon sequestration. The default value is 0. +waste_to_energy,--,bool,Switch to enable expansion of waste to energy CHPs for conversion of plastics. Default is false. +waste_to_energy_cc,--,bool,Switch to enable expansion of waste to energy CHPs for conversion of plastics with carbon capture. Default is false. ,,, sector_ratios_fraction_future,--,Dictionary with planning horizons as keys.,The fraction of total progress in fuel and process switching achieved in the industry sector. basic_chemicals_without_NH3_production_today,Mt/a,float,"The amount of basic chemicals produced without ammonia (= 86 Mtethylene-equiv - 17 MtNH3)." diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 3bf1d15c..ef019ad6 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -10,6 +10,16 @@ Release Notes Upcoming Release ================ +* Added option ``industry: HVC_environment_sequestration_fraction:`` to specify + the fraction of carbon contained plastics that is permanently sequestered in + landfill. The default assumption is that all carbon contained in plastics is + eventually released to the atmosphere. + +* Added option for building waste-to-energy plants with and without carbon + capture to consume non-recycled and non-sequestered plastics. The config + settings are ``industry: waste_to_energy:`` and ``industry: + waste_to_energy_cc``. This does not include municipal solid waste. + * Bump minimum ``powerplantmatching`` version to v0.5.15. * Add floating wind technology for water depths below 60m diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 432d9a82..d35af1c9 100755 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -906,8 +906,6 @@ def add_ammonia(n, costs): nodes = pop_layout.index - cf_industry = snakemake.params.industry - n.add("Carrier", "NH3") n.madd( @@ -2865,7 +2863,7 @@ def add_industry(n, costs): if demand_factor != 1: logger.warning(f"Changing HVC demand by {demand_factor*100-100:+.2f}%.") - p_set_plastics = ( + p_set_naphtha = ( demand_factor * industrial_demand.loc[nodes, "naphtha"].rename( lambda x: x + " naphtha for industry" @@ -2874,7 +2872,7 @@ def add_industry(n, costs): ) if not options["regional_oil_demand"]: - p_set_plastics = p_set_plastics.sum() + p_set_naphtha = p_set_naphtha.sum() n.madd( "Bus", @@ -2889,7 +2887,7 @@ def add_industry(n, costs): spatial.oil.naphtha, bus=spatial.oil.naphtha, carrier="naphtha for industry", - p_set=p_set_plastics, + p_set=p_set_naphtha, ) # some CO2 from naphtha are process emissions from steam cracker @@ -2900,19 +2898,114 @@ def add_industry(n, costs): ) emitted_co2_per_naphtha = costs.at["oil", "CO2 intensity"] - process_co2_per_naphtha - n.madd( - "Link", - spatial.oil.naphtha, - bus0=spatial.oil.nodes, - bus1=spatial.oil.naphtha, - bus2="co2 atmosphere", - bus3=spatial.co2.process_emissions, - carrier="naphtha for industry", - p_nom_extendable=True, - efficiency2=emitted_co2_per_naphtha, - efficiency3=process_co2_per_naphtha, + non_sequestered = 1 - get( + cf_industry["HVC_environment_sequestration_fraction"], + investment_year, ) + if cf_industry["waste_to_energy"] or cf_industry["waste_to_energy_cc"]: + + non_sequestered_hvc_locations = ( + pd.Index(spatial.oil.demand_locations) + " non-sequestered HVC" + ) + + n.madd( + "Bus", + non_sequestered_hvc_locations, + location=spatial.oil.demand_locations, + carrier="non-sequestered HVC", + unit="MWh_LHV", + ) + + n.madd( + "Link", + spatial.oil.naphtha, + bus0=spatial.oil.nodes, + bus1=spatial.oil.naphtha, + bus2=non_sequestered_hvc_locations, + bus3=spatial.co2.process_emissions, + carrier="naphtha for industry", + p_nom_extendable=True, + efficiency2=non_sequestered + * emitted_co2_per_naphtha + / costs.at["oil", "CO2 intensity"], + efficiency3=process_co2_per_naphtha, + ) + + n.madd( + "Link", + spatial.oil.demand_locations, + suffix=" HVC to air", + bus0=non_sequestered_hvc_locations, + bus1="co2 atmosphere", + carrier="HVC to air", + p_nom_extendable=True, + efficiency=costs.at["oil", "CO2 intensity"], + ) + + if len(non_sequestered_hvc_locations) == 1: + waste_source = non_sequestered_hvc_locations[0] + else: + waste_source = non_sequestered_hvc_locations + + if cf_industry["waste_to_energy"]: + + n.madd( + "Link", + spatial.nodes + " waste CHP", + bus0=waste_source, + bus1=spatial.nodes, + bus2=spatial.nodes + " urban central heat", + bus3="co2 atmosphere", + carrier="waste CHP", + p_nom_extendable=True, + capital_cost=costs.at["waste CHP", "fixed"] + * costs.at["waste CHP", "efficiency"], + marginal_cost=costs.at["waste CHP", "VOM"], + efficiency=costs.at["waste CHP", "efficiency"], + efficiency2=costs.at["waste CHP", "efficiency-heat"], + efficiency3=costs.at["oil", "CO2 intensity"], + lifetime=costs.at["waste CHP", "lifetime"], + ) + + if cf_industry["waste_to_energy_cc"]: + + n.madd( + "Link", + spatial.nodes + " waste CHP CC", + bus0=waste_source, + bus1=spatial.nodes, + bus2=spatial.nodes + " urban central heat", + bus3="co2 atmosphere", + bus4=spatial.co2.nodes, + carrier="waste CHP CC", + p_nom_extendable=True, + capital_cost=costs.at["waste CHP CC", "fixed"] + * costs.at["waste CHP CC", "efficiency"], + marginal_cost=costs.at["waste CHP CC", "VOM"], + efficiency=costs.at["waste CHP CC", "efficiency"], + efficiency2=costs.at["waste CHP CC", "efficiency-heat"], + efficiency3=costs.at["oil", "CO2 intensity"] + * (1 - options["cc_fraction"]), + efficiency4=costs.at["oil", "CO2 intensity"] * options["cc_fraction"], + lifetime=costs.at["waste CHP CC", "lifetime"], + ) + + else: + + n.madd( + "Link", + spatial.oil.naphtha, + bus0=spatial.oil.nodes, + bus1=spatial.oil.naphtha, + bus2="co2 atmosphere", + bus3=spatial.co2.process_emissions, + carrier="naphtha for industry", + p_nom_extendable=True, + efficiency2=emitted_co2_per_naphtha * non_sequestered, + efficiency3=process_co2_per_naphtha, + ) + # aviation demand_factor = options.get("aviation_demand_factor", 1) if demand_factor != 1: @@ -3122,7 +3215,6 @@ def add_waste_heat(n): # TODO options? logger.info("Add possibility to use industrial waste heat in district heating") - cf_industry = snakemake.params.industry # AC buses with district heating urban_central = n.buses.index[n.buses.carrier == "urban central heat"] @@ -3587,6 +3679,7 @@ if __name__ == "__main__": update_config_from_wildcards(snakemake.config, snakemake.wildcards) options = snakemake.params.sector + cf_industry = snakemake.params.industry investment_year = int(snakemake.wildcards.planning_horizons[-4:])