options: biosng_cc, biomass_to_liquid_cc, 98% capture rate Allam gas,… (#1298)

* options: biosng_cc, biomass_to_liquid_cc, 98% capture rate Allam gas, avoid option.get

* fix duplicated bus port
This commit is contained in:
Fabian Neumann 2024-09-16 15:04:24 +02:00 committed by GitHub
parent df71b1a64c
commit d8f8a828f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 37 deletions

View File

@ -693,8 +693,10 @@ sector:
conventional_generation:
OCGT: gas
biomass_to_liquid: false
biomass_to_liquid_cc: false
electrobiofuels: false
biosng: false
biosng_cc: false
bioH2: false
municipal_solid_waste: false
limit_max_growth:

View File

@ -167,7 +167,9 @@ biomass_transport,--,"{true, false}",Add option for transporting solid biomass b
biogas_upgrading_cc,--,"{true, false}",Add option to capture CO2 from biomass upgrading
conventional_generation,,,Add a more detailed description of conventional carriers. Any power generation requires the consumption of fuel from nodes representing that fuel.
biomass_to_liquid,--,"{true, false}",Add option for transforming solid biomass into liquid fuel with the same properties as oil
biomass_to_liquid_cc,--,"{true, false}",Add option for transforming solid biomass into liquid fuel with the same properties as oil with carbon capture
biosng,--,"{true, false}",Add option for transforming solid biomass into synthesis gas with the same properties as natural gas
biosng_cc,--,"{true, false}",Add option for transforming solid biomass into synthesis gas with the same properties as natural gas with carbon capture
bioH2,--,"{true, false}",Add option for transforming solid biomass into hydrogen with carbon capture
municipal_solid_waste,--,"{true, false}",Add option for municipal solid waste
limit_max_growth,,,

1 Unit Values Description
167 biogas_upgrading_cc -- {true, false} Add option to capture CO2 from biomass upgrading
168 conventional_generation Add a more detailed description of conventional carriers. Any power generation requires the consumption of fuel from nodes representing that fuel.
169 biomass_to_liquid -- {true, false} Add option for transforming solid biomass into liquid fuel with the same properties as oil
170 biomass_to_liquid_cc -- {true, false} Add option for transforming solid biomass into liquid fuel with the same properties as oil with carbon capture
171 biosng -- {true, false} Add option for transforming solid biomass into synthesis gas with the same properties as natural gas
172 biosng_cc -- {true, false} Add option for transforming solid biomass into synthesis gas with the same properties as natural gas with carbon capture
173 bioH2 -- {true, false} Add option for transforming solid biomass into hydrogen with carbon capture
174 municipal_solid_waste -- {true, false} Add option for municipal solid waste
175 limit_max_growth

View File

@ -68,6 +68,11 @@ Upcoming Release
defaults to 10 km. Previously the distance to the region's centroid was
used, which is not practical when the regions are already aggregated.
* Added options ``biosng_cc`` and ``biomass_to_liquid_cc`` to separate the base
technology from the option to capture carbon from it.
* Added 98% imperfect capture rate of Allam cycle gas turbine.
PyPSA-Eur 0.13.0 (13th September 2024)
======================================

View File

@ -132,9 +132,9 @@ def define_spatial(nodes, options):
# ammonia
if options.get("ammonia"):
if options["ammonia"]:
spatial.ammonia = SimpleNamespace()
if options.get("ammonia") == "regional":
if options["ammonia"] == "regional":
spatial.ammonia.nodes = nodes + " NH3"
spatial.ammonia.locations = nodes
else:
@ -519,7 +519,7 @@ def add_carrier_buses(n, carrier, nodes=None):
)
fossils = ["coal", "gas", "oil", "lignite"]
if options.get("fossil_fuels", True) and carrier in fossils:
if options["fossil_fuels"] and carrier in fossils:
suffix = ""
@ -750,7 +750,7 @@ def add_co2_network(n, costs):
)
def add_allam(n, costs):
def add_allam_gas(n, costs):
logger.info("Adding Allam cycle gas power plants.")
nodes = pop_layout.index
@ -758,17 +758,18 @@ def add_allam(n, costs):
n.madd(
"Link",
nodes,
suffix=" allam",
suffix=" allam gas",
bus0=spatial.gas.df.loc[nodes, "nodes"].values,
bus1=nodes,
bus2=spatial.co2.df.loc[nodes, "nodes"].values,
carrier="allam",
bus3="co2 atmosphere",
carrier="allam gas",
p_nom_extendable=True,
# TODO: add costs to technology-data
capital_cost=costs.at["allam", "fixed"] * costs.at["allam", "efficiency"],
marginal_cost=costs.at["allam", "VOM"] * costs.at["allam", "efficiency"],
efficiency=costs.at["allam", "efficiency"],
efficiency2=costs.at["gas", "CO2 intensity"],
efficiency2=0.98 * costs.at["gas", "CO2 intensity"],
efficiency3=0.02 * costs.at["gas", "CO2 intensity"],
lifetime=costs.at["allam", "lifetime"],
)
@ -823,8 +824,10 @@ def add_biomass_to_methanol_cc(n, costs):
)
def add_methanol_to_power(n, costs, types={}):
# TODO: add costs to technology-data
def add_methanol_to_power(n, costs, types=None):
if types is None:
types = {}
nodes = pop_layout.index
@ -1121,8 +1124,7 @@ def add_generation(n, costs):
nodes = pop_layout.index
fallback = {"OCGT": "gas"}
conventionals = options.get("conventional_generation", fallback)
conventionals = options["conventional_generation"]
for generator, carrier in conventionals.items():
carrier_nodes = vars(spatial)[carrier].nodes
@ -1564,7 +1566,7 @@ def add_storage_and_grids(n, costs):
complement_edges["length"] = complement_edges.apply(haversine, axis=1)
# apply k_edge_augmentation weighted by length of complement edges
k_edge = options.get("gas_network_connectivity_upgrade", 3)
k_edge = options["gas_network_connectivity_upgrade"]
if augmentation := list(
k_edge_augmentation(G, k_edge, avail=complement_edges.values)
):
@ -1612,7 +1614,7 @@ def add_storage_and_grids(n, costs):
lifetime=costs.at["H2 (g) pipeline repurposed", "lifetime"],
)
if options.get("H2_network", True):
if options["H2_network"]:
logger.info("Add options for new hydrogen pipelines.")
h2_pipes = create_network_topology(
@ -1682,7 +1684,7 @@ def add_storage_and_grids(n, costs):
bus2=spatial.co2.nodes,
p_nom_extendable=True,
carrier="Sabatier",
p_min_pu=options.get("min_part_load_methanation", 0),
p_min_pu=options["min_part_load_methanation"],
efficiency=costs.at["methanation", "efficiency"],
efficiency2=-costs.at["methanation", "efficiency"]
* costs.at["gas", "CO2 intensity"],
@ -1691,7 +1693,7 @@ def add_storage_and_grids(n, costs):
lifetime=costs.at["methanation", "lifetime"],
)
if options.get("coal_cc"):
if options["coal_cc"]:
n.madd(
"Link",
spatial.nodes,
@ -1835,7 +1837,7 @@ def add_EVs(
p_set=profile,
)
p_nom = number_cars * options.get("bev_charge_rate", 0.011) * electric_share
p_nom = number_cars * options["bev_charge_rate"] * electric_share
n.madd(
"Link",
@ -1847,7 +1849,7 @@ def add_EVs(
carrier="BEV charger",
p_max_pu=avail_profile[spatial.nodes],
lifetime=1,
efficiency=options.get("bev_charge_efficiency", 0.9),
efficiency=options["bev_charge_efficiency"],
)
if options["v2g"]:
@ -1861,13 +1863,13 @@ def add_EVs(
carrier="V2G",
p_max_pu=avail_profile[spatial.nodes],
lifetime=1,
efficiency=options.get("bev_charge_efficiency", 0.9),
efficiency=options["bev_charge_efficiency"],
)
if options["bev_dsm"]:
e_nom = (
number_cars
* options.get("bev_energy", 0.05)
* options["bev_energy"]
* options["bev_availability"]
* electric_share
)
@ -2116,7 +2118,7 @@ def add_heat(n: pypsa.Network, costs: pd.DataFrame, cop: xr.DataArray):
unit="MWh_th",
)
if heat_system == HeatSystem.URBAN_CENTRAL and options.get("central_heat_vent"):
if heat_system == HeatSystem.URBAN_CENTRAL and options["central_heat_vent"]:
n.madd(
"Generator",
nodes + f" {heat_system} heat vent",
@ -2786,7 +2788,7 @@ def add_biomass(n, costs):
p_nom_extendable=True,
)
if options.get("biogas_upgrading_cc"):
if options["biogas_upgrading_cc"]:
# Assuming for costs that the CO2 from upgrading is pure, such as in amine scrubbing. I.e., with and without CC is
# equivalent. Adding biomass CHP capture because biogas is often small-scale and decentral so further
# from e.g. CO2 grid or buyers. This is a proxy for the added cost for e.g. a raw biogas pipeline to a central upgrading facility
@ -3034,6 +3036,8 @@ def add_biomass(n, costs):
marginal_cost=costs.at["BtL", "VOM"] * costs.at["BtL", "efficiency"],
)
# Solid biomass to liquid fuel with carbon capture
if options["biomass_to_liquid_cc"]:
# Assuming that acid gas removal (incl. CO2) from syngas i performed with Rectisol
# process (Methanol) and that electricity demand for this is included in the base process
n.madd(
@ -3044,7 +3048,7 @@ def add_biomass(n, costs):
bus1=spatial.oil.nodes,
bus2="co2 atmosphere",
bus3=spatial.co2.nodes,
carrier="biomass to liquid",
carrier="biomass to liquid CC",
lifetime=costs.at["BtL", "lifetime"],
efficiency=costs.at["BtL", "efficiency"],
efficiency2=-costs.at["solid biomass", "CO2 intensity"]
@ -3112,6 +3116,8 @@ def add_biomass(n, costs):
marginal_cost=costs.at["BioSNG", "VOM"] * costs.at["BioSNG", "efficiency"],
)
# BioSNG from solid biomass with carbon capture
if options["biosng_cc"]:
# Assuming that acid gas removal (incl. CO2) from syngas i performed with Rectisol
# process (Methanol) and that electricity demand for this is included in the base process
n.madd(
@ -3122,7 +3128,7 @@ def add_biomass(n, costs):
bus1=spatial.gas.nodes,
bus2=spatial.co2.nodes,
bus3="co2 atmosphere",
carrier="BioSNG",
carrier="BioSNG CC",
lifetime=costs.at["BioSNG", "lifetime"],
efficiency=costs.at["BioSNG", "efficiency"],
efficiency2=costs.at["BioSNG", "CO2 stored"]
@ -3162,10 +3168,6 @@ def add_biomass(n, costs):
* costs.at["solid biomass to hydrogen", "efficiency"]
+ costs.at["biomass CHP capture", "fixed"]
* costs.at["solid biomass", "CO2 intensity"],
overnight_cost=costs.at["solid biomass to hydrogen", "investment"]
* costs.at["solid biomass to hydrogen", "efficiency"]
+ costs.at["biomass CHP capture", "investment"]
* costs.at["solid biomass", "CO2 intensity"],
marginal_cost=0.0,
)
@ -3356,7 +3358,7 @@ def add_industry(n, costs):
bus3=spatial.co2.nodes,
carrier="methanolisation",
p_nom_extendable=True,
p_min_pu=options.get("min_part_load_methanolisation", 0),
p_min_pu=options["min_part_load_methanolisation"],
capital_cost=costs.at["methanolisation", "fixed"]
* options["MWh_MeOH_per_MWh_H2"], # EUR/MW_H2/a
marginal_cost=options["MWh_MeOH_per_MWh_H2"]
@ -3552,12 +3554,12 @@ def add_industry(n, costs):
efficiency2=-costs.at["oil", "CO2 intensity"]
* costs.at["Fischer-Tropsch", "efficiency"],
p_nom_extendable=True,
p_min_pu=options.get("min_part_load_fischer_tropsch", 0),
p_min_pu=options["min_part_load_fischer_tropsch"],
lifetime=costs.at["Fischer-Tropsch", "lifetime"],
)
# naphtha
demand_factor = options.get("HVC_demand_factor", 1)
demand_factor = options["HVC_demand_factor"]
if demand_factor != 1:
logger.warning(f"Changing HVC demand by {demand_factor*100-100:+.2f}%.")
@ -3630,7 +3632,7 @@ def add_industry(n, costs):
efficiency3=process_co2_per_naphtha,
)
if options.get("biomass", True) and options["municipal_solid_waste"]:
if options["biomass"] and options["municipal_solid_waste"]:
n.madd(
"Link",
spatial.msw.locations,
@ -3722,7 +3724,7 @@ def add_industry(n, costs):
)
# aviation
demand_factor = options.get("aviation_demand_factor", 1)
demand_factor = options["aviation_demand_factor"]
if demand_factor != 1:
logger.warning(f"Changing aviation demand by {demand_factor*100-100:+.2f}%.")
@ -3862,7 +3864,7 @@ def add_industry(n, costs):
lifetime=costs.at["cement capture", "lifetime"],
)
if options.get("ammonia"):
if options["ammonia"]:
if options["ammonia"] == "regional":
p_set = (
industrial_demand.loc[spatial.ammonia.locations, "ammonia"].rename(
@ -4639,8 +4641,8 @@ if __name__ == "__main__":
if options["co2network"]:
add_co2_network(n, costs)
if options["allam_cycle"]:
add_allam(n, costs)
if options["allam_cycle_gas"]:
add_allam_gas(n, costs)
n = set_temporal_aggregation(
n, snakemake.params.time_resolution, snakemake.input.snapshot_weightings
@ -4701,7 +4703,7 @@ if __name__ == "__main__":
snakemake.params.planning_horizons[0] == investment_year
)
if options.get("cluster_heat_buses", False) and not first_year_myopic:
if options["cluster_heat_buses"] and not first_year_myopic:
cluster_heat_buses(n)
maybe_adjust_costs_and_potentials(