diff --git a/config/config.default.yaml b/config/config.default.yaml index 31858a5b..2a3be87b 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -497,6 +497,7 @@ sector: gas_distribution_grid_cost_factor: 1.0 biomass_spatial: false biomass_transport: false + biogas_upgrading_cc: false conventional_generation: OCGT: gas biomass_to_liquid: false @@ -778,6 +779,7 @@ plotting: fossil gas: '#e05b09' natural gas: '#e05b09' biogas to gas: '#e36311' + biogas to gas CC: '#e51245' CCGT: '#a85522' CCGT marginal: '#a85522' allam: '#B98F76' diff --git a/doc/configtables/sector.csv b/doc/configtables/sector.csv index 856ea074..280c1906 100644 --- a/doc/configtables/sector.csv +++ b/doc/configtables/sector.csv @@ -118,6 +118,7 @@ gas_distribution_grid _cost_factor,,,Multiplier for the investment cost of the g ,,, biomass_spatial,--,"{true, false}",Add option for resolving biomass demand regionally biomass_transport,--,"{true, false}",Add option for transporting solid biomass between nodes +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 biosng,--,"{true, false}",Add option for transforming solid biomass into synthesis gas with the same properties as natural gas diff --git a/doc/release_notes.rst b/doc/release_notes.rst index c319bce9..b7035974 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -44,8 +44,12 @@ Upcoming Release network has been moved from ``focus_weights:`` to ``clustering: focus_weights:``. Backwards compatibility to old config files is maintained. +* Add VOM as marginal cost to PtX processes. + * The ``mock_snakemake`` function can now be used with a Snakefile from a different directory using the new ``root_dir`` argument. +* Add option to capture CO2 contained in biogas when upgrading (``sector: biogas_to_gas_cc``). + * Merged option to extend geographical scope to Ukraine and Moldova. These countries are excluded by default and is currently constrained to power-sector only parts of the workflow. A special config file diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index d23143ff..49d26726 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -95,12 +95,14 @@ def define_spatial(nodes, options): spatial.gas.industry = nodes + " gas for industry" spatial.gas.industry_cc = nodes + " gas for industry CC" spatial.gas.biogas_to_gas = nodes + " biogas to gas" + spatial.gas.biogas_to_gas_cc = nodes + "biogas to gas CC" else: spatial.gas.nodes = ["EU gas"] spatial.gas.locations = ["EU"] spatial.gas.biogas = ["EU biogas"] spatial.gas.industry = ["gas for industry"] spatial.gas.biogas_to_gas = ["EU biogas to gas"] + spatial.gas.biogas_to_gas_cc = ["EU biogas to gas CC"] if options.get("co2_spatial", options["co2network"]): spatial.gas.industry_cc = nodes + " gas for industry CC" else: @@ -808,6 +810,7 @@ def add_ammonia(n, costs): efficiency=1 / costs.at["Haber-Bosch", "electricity-input"], efficiency2=-costs.at["Haber-Bosch", "hydrogen-input"] / costs.at["Haber-Bosch", "electricity-input"], capital_cost=costs.at["Haber-Bosch", "fixed"] / costs.at["Haber-Bosch", "electricity-input"], + marginal_cost=costs.at["Haber-Bosch", "VOM"] / costs.at["Haber-Bosch", "electricity-input"], lifetime=costs.at["Haber-Bosch", "lifetime"], ) @@ -1018,7 +1021,7 @@ def insert_gas_distribution_costs(n, costs): f"Inserting gas distribution grid with investment cost factor of {f_costs}" ) - capital_cost = costs.loc["electricity distribution grid"]["fixed"] * f_costs + capital_cost = costs.at["electricity distribution grid", "fixed"] * f_costs # gas boilers gas_b = n.links.index[ @@ -1095,6 +1098,7 @@ def add_storage_and_grids(n, costs): efficiency=costs.at["OCGT", "efficiency"], capital_cost=costs.at["OCGT", "fixed"] * costs.at["OCGT", "efficiency"], # NB: fixed cost is per MWel + marginal_cost=costs.at["OCGT", "VOM"], lifetime=costs.at["OCGT", "lifetime"], ) @@ -2163,12 +2167,42 @@ def add_biomass(n, costs): bus1=spatial.gas.nodes, bus2="co2 atmosphere", carrier="biogas to gas", - capital_cost=costs.loc["biogas upgrading", "fixed"], - marginal_cost=costs.loc["biogas upgrading", "VOM"], + capital_cost=costs.at["biogas", "fixed"] + + costs.at["biogas upgrading", "fixed"], + marginal_cost=costs.at["biogas upgrading", "VOM"], + efficiency=costs.at["biogas", "efficiency"], efficiency2=-costs.at["gas", "CO2 intensity"], p_nom_extendable=True, ) + if options.get("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 + + n.madd( + "Link", + spatial.gas.biogas_to_gas_cc, + bus0=spatial.gas.biogas, + bus1=spatial.gas.nodes, + bus2="co2 stored", + bus3="co2 atmosphere", + carrier="biogas to gas CC", + capital_cost=costs.at["biogas CC", "fixed"] + + costs.at["biogas upgrading", "fixed"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["biogas CC", "CO2 stored"], + marginal_cost=costs.at["biogas CC", "VOM"] + + costs.at["biogas upgrading", "VOM"], + efficiency=costs.at["biogas CC", "efficiency"], + efficiency2=costs.at["biogas CC", "CO2 stored"] + * costs.at["biogas CC", "capture rate"], + efficiency3=-costs.at["gas", "CO2 intensity"] + - costs.at["biogas CC", "CO2 stored"] + * costs.at["biogas CC", "capture rate"], + p_nom_extendable=True, + ) + if options["biomass_transport"]: # add biomass transport transport_costs = pd.read_csv( @@ -2313,7 +2347,7 @@ def add_biomass(n, costs): + costs.at["BtL", "CO2 stored"], p_nom_extendable=True, capital_cost=costs.at["BtL", "fixed"], - marginal_cost=costs.at["BtL", "efficiency"] * costs.loc["BtL", "VOM"], + marginal_cost=costs.at["BtL", "efficiency"] * costs.at["BtL", "VOM"], ) # TODO: Update with energy penalty @@ -2334,7 +2368,7 @@ def add_biomass(n, costs): p_nom_extendable=True, capital_cost=costs.at["BtL", "fixed"] + costs.at["biomass CHP capture", "fixed"] * costs.at["BtL", "CO2 stored"], - marginal_cost=costs.at["BtL", "efficiency"] * costs.loc["BtL", "VOM"], + marginal_cost=costs.at["BtL", "efficiency"] * costs.at["BtL", "VOM"], ) # BioSNG from solid biomass @@ -2353,7 +2387,7 @@ def add_biomass(n, costs): + costs.at["BioSNG", "CO2 stored"], p_nom_extendable=True, capital_cost=costs.at["BioSNG", "fixed"], - marginal_cost=costs.at["BioSNG", "efficiency"] * costs.loc["BioSNG", "VOM"], + marginal_cost=costs.at["BioSNG", "efficiency"] * costs.at["BioSNG", "VOM"], ) # TODO: Update with energy penalty for CC @@ -2377,7 +2411,7 @@ def add_biomass(n, costs): capital_cost=costs.at["BioSNG", "fixed"] + costs.at["biomass CHP capture", "fixed"] * costs.at["BioSNG", "CO2 stored"], - marginal_cost=costs.at["BioSNG", "efficiency"] * costs.loc["BioSNG", "VOM"], + marginal_cost=costs.at["BioSNG", "efficiency"] * costs.at["BioSNG", "VOM"], ) @@ -2610,6 +2644,8 @@ def add_industry(n, costs): p_min_pu=options.get("min_part_load_methanolisation", 0), capital_cost=costs.at["methanolisation", "fixed"] * options["MWh_MeOH_per_MWh_H2"], # EUR/MW_H2/a + marginal_cost=options["MWh_MeOH_per_MWh_H2"] + * costs.at["methanolisation", "VOM"], lifetime=costs.at["methanolisation", "lifetime"], efficiency=options["MWh_MeOH_per_MWh_H2"], efficiency2=-options["MWh_MeOH_per_MWh_H2"] / options["MWh_MeOH_per_MWh_e"], @@ -2727,6 +2763,8 @@ def add_industry(n, costs): efficiency=costs.at["Fischer-Tropsch", "efficiency"], capital_cost=costs.at["Fischer-Tropsch", "fixed"] * costs.at["Fischer-Tropsch", "efficiency"], # EUR/MW_H2/a + marginal_cost=costs.at["Fischer-Tropsch", "efficiency"] + * costs.at["Fischer-Tropsch", "VOM"], efficiency2=-costs.at["oil", "CO2 intensity"] * costs.at["Fischer-Tropsch", "efficiency"], p_nom_extendable=True,