Merge pull request #1060 from PyPSA/landfill_master

Improve handling of plastics (for `master`)
This commit is contained in:
Fabian Neumann 2024-05-13 17:44:46 +02:00 committed by GitHub
commit ef395cadf9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 134 additions and 17 deletions

View File

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

View File

@ -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

View File

@ -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)."

1 Unit Values Description
16 HVC_primary_fraction -- float The fraction of high value chemicals (HVC) produced via primary route
17 HVC_mechanical_recycling _fraction -- float The fraction of high value chemicals (HVC) produced using mechanical recycling
18 HVC_chemical_recycling _fraction -- float The fraction of high value chemicals (HVC) produced using chemical recycling
19 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.
20 waste_to_energy -- bool Switch to enable expansion of waste to energy CHPs for conversion of plastics. Default is false.
21 waste_to_energy_cc -- bool Switch to enable expansion of waste to energy CHPs for conversion of plastics with carbon capture. Default is false.
22
23 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.
24 basic_chemicals_without_NH3_production_today Mt/a float The amount of basic chemicals produced without ammonia (= 86 Mtethylene-equiv - 17 MtNH3).

View File

@ -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

View File

@ -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:])