From 96f68b1194b6aec5ad0c9359ab629fe6f745c9cb Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Tue, 7 May 2024 18:28:18 +0200 Subject: [PATCH 01/20] first ideas --- workflow/scripts/modify_prenetwork.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index 5fdbdf7f..580967a9 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -326,6 +326,31 @@ def transmission_costs_from_modified_cost_data(n, costs, length_factor=1.0): ) n.links.loc[dc_b, "capital_cost"] = costs +# specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() +specific_emisisons = { + "oil" : 0.2571, + "gas" : 0.198, # OCGT + "coal" : 0.3361, + "lignite" : 0.4069, + "co2 sequestered": 1.0, + "co2": 0.0, +} + +def emissions_upstream(n): + + n.remove("GlobalConstraint", "CO2Limit") + + n.add( + "GlobalConstraint", + "CO2Limit", + carrier_attribute="co2_emissions", + sense="<=", + constant=0, # -10000 + ) + + for carrier in specific_emisisons: + n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] + if __name__ == "__main__": if "snakemake" not in globals(): @@ -391,4 +416,6 @@ def transmission_costs_from_modified_cost_data(n, costs, length_factor=1.0): # change to NEP21 costs transmission_costs_from_modified_cost_data(n, costs_loaded, snakemake.params.length_factor) + emissions_downstream(n) + n.export_to_netcdf(snakemake.output.network) From 58f6ca447f2bc74c0806294632a25a87d8b557cf Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Wed, 8 May 2024 14:05:15 +0200 Subject: [PATCH 02/20] config changes --- config/config.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 01e368bf..cf0776f7 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,10 +4,10 @@ # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: - prefix: 20240424fixCurrentPolicies + prefix: 240507downstreamEmissions name: - - CurrentPolicies - # - KN2045_Bal_v4 + #- CurrentPolicies + - KN2045_Bal_v4 # - KN2045_Elec_v4 # - KN2045_H2_v4 # - KN2045plus_EasyRide @@ -58,11 +58,11 @@ scenario: - none planning_horizons: - 2020 - - 2025 - - 2030 - - 2035 - - 2040 - - 2045 + #- 2025 + #- 2030 + #- 2035 + #- 2040 + #- 2045 existing_capacities: grouping_years_power: [1895, 1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019, 2024, 2029] From 9e2e21f1c39468a3d65b90b807ed8f9d5244acf6 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Wed, 19 Jun 2024 10:28:45 +0200 Subject: [PATCH 03/20] add global limit --- config/config.yaml | 35 +++++++++++++++------------ workflow/Snakefile | 1 + workflow/scripts/modify_prenetwork.py | 23 +++++++++++------- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 6c988d19..3e70f3fd 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,16 +4,16 @@ # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: - prefix: 20240613scenariosredefined + prefix: 20240619upstreamEmissions name: - - CurrentPolicies - - KN2045_Bal_v4 - - KN2045_Elec_v4 - - KN2045_H2_v4 - - KN2045plus_EasyRide - - KN2045plus_LowDemand - - KN2045minus_WorstCase - - KN2045minus_SupplyFocus + # - CurrentPolicies + - KN2045_Bal_v4 + # - KN2045_Elec_v4 + # - KN2045_H2_v4 + # - KN2045plus_EasyRide + # - KN2045plus_LowDemand + # - KN2045minus_WorstCase + # - KN2045minus_SupplyFocus scenarios: enable: true file: config/scenarios.automated.yaml @@ -65,11 +65,11 @@ scenario: - none planning_horizons: - 2020 - #- 2025 - #- 2030 - #- 2035 - #- 2040 - #- 2045 + - 2025 + - 2030 + - 2035 + - 2040 + - 2045 existing_capacities: grouping_years_power: [1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020] @@ -103,7 +103,7 @@ clustering: 'PL': 0.0454 'SE': 0.0454 temporal: - resolution_sector: 365H + resolution_sector: 780H # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#co2-budget co2_budget: @@ -223,7 +223,7 @@ costs: # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#sector sector: - # solar_thermal: false + solar_thermal: false district_heating: potential: 0.4 progress: @@ -398,3 +398,6 @@ must_run_biomass: p_min_pu: 0.7 regions: ['DE'] +emissions_upstream: + enable: true + diff --git a/workflow/Snakefile b/workflow/Snakefile index 113ae8b8..7633f4af 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -145,6 +145,7 @@ rule modify_prenetwork: H2_retrofit_capacity_per_CH4=config_provider("sector", "H2_retrofit_capacity_per_CH4"), transmission_costs=config_provider("costs", "transmission"), biomass_must_run=config_provider("must_run_biomass"), + emissions_upstream=config_provider("emissions_upstream"), input: network=RESULTS + "prenetworks-brownfield/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc", diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index 0a946d3b..e5c39ff8 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -352,6 +352,12 @@ def must_run_biomass(n, p_min_pu, regions): def emissions_upstream(n): + # add co2_emissions attribute to carriers + for carrier in specific_emisisons: + n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] + + # alter constraint + limit = n.global_constraints.loc["CO2Limit","constant"] n.remove("GlobalConstraint", "CO2Limit") n.add( @@ -359,11 +365,9 @@ def emissions_upstream(n): "CO2Limit", carrier_attribute="co2_emissions", sense="<=", - constant=0, # -10000 - ) - - for carrier in specific_emisisons: - n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] + type="co2_emisisons", + constant=limit, + ) if __name__ == "__main__": @@ -378,10 +382,10 @@ def emissions_upstream(n): snakemake = mock_snakemake( "modify_prenetwork", simpl="", - clusters=22, + clusters=44, opts="", - ll="v1.2", - sector_opts="365H-T-H-B-I-A-solar+p3-linemaxext15", + ll="vopt", + sector_opts="none", planning_horizons="2040", run="KN2045_H2_v4" ) @@ -433,6 +437,7 @@ def emissions_upstream(n): if snakemake.params.biomass_must_run["enable"]: must_run_biomass(n, snakemake.params.biomass_must_run["p_min_pu"], snakemake.params.biomass_must_run["regions"]) - emissions_downstream(n) + if snakemake.params.emissions_upstream["enable"]: + emissions_upstream(n) n.export_to_netcdf(snakemake.output.network) From 247698e3002e79a12aec113b5a9b013a6640405d Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 20 Jun 2024 14:40:45 +0200 Subject: [PATCH 04/20] starting with country specific constraint --- workflow/scripts/additional_functionality.py | 172 ++++++++++++++----- 1 file changed, 126 insertions(+), 46 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 40ef5635..15d274b3 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -236,66 +236,146 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): """ logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels") - nhours = n.snapshot_weightings.generators.sum() - nyears = nhours / 8760 + # functionality if emissions upstream are not enabled + if not snakemake.params.emissions_upstream["enable"]: + nhours = n.snapshot_weightings.generators.sum() + nyears = nhours / 8760 - sectors = determine_emission_sectors(n.config['sector']) + sectors = determine_emission_sectors(n.config['sector']) - # convert MtCO2 to tCO2 - co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) + # convert MtCO2 to tCO2 + co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) - co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears + co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears - for ct in limit_countries: - limit = co2_total_totals[ct]*limit_countries[ct] - logger.info( - f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " - f"1990 levels, i.e. {limit:,.2f} tCO2/a", - ) + for ct in limit_countries: + limit = co2_total_totals[ct]*limit_countries[ct] + logger.info( + f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " + f"1990 levels, i.e. {limit:,.2f} tCO2/a", + ) - lhs = [] + lhs = [] - for port in [col[3:] for col in n.links if col.startswith("bus")]: + for port in [col[3:] for col in n.links if col.startswith("bus")]: - links = n.links.index[(n.links.index.str[:2] == ct) & (n.links[f"bus{port}"] == "co2 atmosphere")] + links = n.links.index[(n.links.index.str[:2] == ct) & (n.links[f"bus{port}"] == "co2 atmosphere")] - logger.info(f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}") + logger.info(f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}") - if port == "0": - efficiency = -1. - elif port == "1": - efficiency = n.links.loc[links, f"efficiency"] - else: - efficiency = n.links.loc[links, f"efficiency{port}"] + if port == "0": + efficiency = -1. + elif port == "1": + efficiency = n.links.loc[links, f"efficiency"] + else: + efficiency = n.links.loc[links, f"efficiency{port}"] - lhs.append((n.model["Link-p"].loc[:, links]*efficiency*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, links]*efficiency*n.snapshot_weightings.generators).sum()) - incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] - outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] + incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] + outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] - if not debug: - lhs.append((-1*n.model["Link-p"].loc[:, incoming]*0.2571*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, outgoing]*0.2571*n.snapshot_weightings.generators).sum()) + if not debug: + lhs.append((-1*n.model["Link-p"].loc[:, incoming]*0.2571*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, outgoing]*0.2571*n.snapshot_weightings.generators).sum()) - lhs = sum(lhs) + lhs = sum(lhs) - cname = f"co2_limit-{ct}" + cname = f"co2_limit-{ct}" - n.model.add_constraints( - lhs <= limit, - name=f"GlobalConstraint-{cname}", - ) + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint-{cname}", + ) - if cname not in n.global_constraints.index: - n.add( - "GlobalConstraint", - cname, - constant=limit, - sense="<=", - type="", - carrier_attribute="", + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) + # functionality if emissions upstream are enabled + else: + logger.info("Emissions upstream are enabled.") + + nhours = n.snapshot_weightings.generators.sum() + nyears = nhours / 8760 + + sectors = determine_emission_sectors(n.config['sector']) + + # convert MtCO2 to tCO2 + co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) + + co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears + + for ct in limit_countries: + limit = co2_total_totals[ct]*limit_countries[ct] + logger.info( + f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " + f"1990 levels, i.e. {limit:,.2f} tCO2/a", ) + # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() + specific_emisisons = { + "oil" : 0.2571, + "gas" : 0.198, # OCGT + "coal" : 0.3361, + "lignite" : 0.4069, + # "co2 sequestered": 1.0, + # "co2": 0.0, + } + + lhs = [] + + # restrict all trade and generation of fossil fuels in DE + + for c in specific_emisisons.keys(): + + links = n.links.index[(n.links.index.str[:2] == ct) & (n.links[f"bus{port}"] == "co2 atmosphere")] + + logger.info(f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}") + + if port == "0": + efficiency = -1. + elif port == "1": + efficiency = n.links.loc[links, f"efficiency"] + else: + efficiency = n.links.loc[links, f"efficiency{port}"] + + lhs.append((n.model["Link-p"].loc[:, links]*efficiency*n.snapshot_weightings.generators).sum()) + + incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] + outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] + + if not debug: + lhs.append((-1*n.model["Link-p"].loc[:, incoming]*0.2571*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, outgoing]*0.2571*n.snapshot_weightings.generators).sum()) + + lhs = sum(lhs) + + cname = f"co2_limit_upstream-{ct}" + + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint-{cname}", + ) + + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) + + + + def force_boiler_profiles_existing_per_load(n): """this scales the boiler dispatch to the load profile with a factor common to all boilers at load""" @@ -415,7 +495,7 @@ def additional_functionality(n, snapshots, snakemake): #force_boiler_profiles_existing_per_load(n) force_boiler_profiles_existing_per_boiler(n) - if snakemake.config["sector"]["co2_budget_national"]: - limit_countries = snakemake.config["co2_budget_national"][investment_year] - add_co2limit_country(n, limit_countries, snakemake, - debug=snakemake.config["run"]["debug_co2_limit"]) + # if snakemake.config["sector"]["co2_budget_national"]: + # limit_countries = snakemake.config["co2_budget_national"][investment_year] + # add_co2limit_country(n, limit_countries, snakemake, + # debug=snakemake.config["run"]["debug_co2_limit"]) From fb9d7650f452982540bdd58cfbaa9c651204ab99 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Wed, 3 Jul 2024 18:18:04 +0200 Subject: [PATCH 05/20] DE constraint --- workflow/scripts/additional_functionality.py | 142 ++++++++++++++----- workflow/scripts/export_ariadne_variables.py | 18 ++- workflow/scripts/modify_prenetwork.py | 82 +++++++++-- 3 files changed, 187 insertions(+), 55 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 15d274b3..b4d1b174 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -221,6 +221,76 @@ def electricity_import_limits(n, snapshots, investment_year, config): carrier_attribute="", ) +def emissions_upstream(n): + + # old constraint + limit = n.global_constraints.loc["CO2Limit","constant"] + n.remove("GlobalConstraint", "CO2Limit") + + # # add co2_emissions attribute to carriers + # for carrier in specific_emisisons: + # n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] + + # n.add( + # "GlobalConstraint", + # "CO2Limit", + # carrier_attribute="co2_emissions", + # sense="<=", + # type="co2_emisisons", + # constant=limit, + # ) + + # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() + specific_emisisons = { + "oil" : 0.2571, + "gas" : 0.198, # OCGT + "coal" : 0.3361, + "lignite" : 0.4069, + # "co2 sequestered": 1.0, + # "co2": 0.0, + } + + lhs = [] + + # gas (spatially distributed) + i_gas = n.generators.index[(n.generators.carrier == "gas")] + lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + + # oil (EU oild and DE oil) + i_oil = n.generators.index[(n.generators.carrier == "oil")] + lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) + + # coal (only EU coal) + i_coal = n.generators.index[(n.generators.carrier == "coal")] + lhs.append((n.model["Generator-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) + + # lignite (only EU lignite) + i_lignite = n.generators.index[(n.generators.carrier == "lignite")] + lhs.append((n.model["Generator-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) + + # sequestration + i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] + lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) + + lhs = sum(lhs) + + cname = "CO2Limit" + + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint", + ) + + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) + def add_co2limit_country(n, limit_countries, snakemake, debug=False): """ @@ -235,18 +305,18 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): snakemake: snakemake object """ logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels") + nhours = n.snapshot_weightings.generators.sum() + nyears = nhours / 8760 - # functionality if emissions upstream are not enabled - if not snakemake.params.emissions_upstream["enable"]: - nhours = n.snapshot_weightings.generators.sum() - nyears = nhours / 8760 + sectors = determine_emission_sectors(n.config['sector']) - sectors = determine_emission_sectors(n.config['sector']) + # convert MtCO2 to tCO2 + co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) - # convert MtCO2 to tCO2 - co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) + co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears - co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears + # functionality if emissions upstream are not enabled + if not snakemake.config["emissions_upstream"]["enable"]: for ct in limit_countries: limit = co2_total_totals[ct]*limit_countries[ct] @@ -297,20 +367,11 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): type="", carrier_attribute="", ) + # functionality if emissions upstream are enabled else: logger.info("Emissions upstream are enabled.") - nhours = n.snapshot_weightings.generators.sum() - nyears = nhours / 8760 - - sectors = determine_emission_sectors(n.config['sector']) - - # convert MtCO2 to tCO2 - co2_totals = 1e6 * pd.read_csv(snakemake.input.co2_totals_name, index_col=0) - - co2_total_totals = co2_totals[sectors].sum(axis=1) * nyears - for ct in limit_countries: limit = co2_total_totals[ct]*limit_countries[ct] logger.info( @@ -330,33 +391,39 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): lhs = [] - # restrict all trade and generation of fossil fuels in DE + # restrict all trade and generation of fossil fuels in country ct - for c in specific_emisisons.keys(): + # gas + i_gas = n.generators.index[(n.generators.carrier == "gas") & (n.generators.index.str[:2] == ct)] + lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - links = n.links.index[(n.links.index.str[:2] == ct) & (n.links[f"bus{port}"] == "co2 atmosphere")] + # oil + i_oil = n.generators.index[(n.generators.carrier == "oil") & (n.generators.index.str[:2] == ct)] + lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) - logger.info(f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}") + # coal + i_coal = n.links.index[(n.links.carrier == "coal") & (n.links.bus1.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) - if port == "0": - efficiency = -1. - elif port == "1": - efficiency = n.links.loc[links, f"efficiency"] - else: - efficiency = n.links.loc[links, f"efficiency{port}"] + # lignite + i_lignite = n.links.index[(n.links.carrier == "lignite") & (n.links.bus1.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, links]*efficiency*n.snapshot_weightings.generators).sum()) + # sequestration + i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered") & (n.links.index.str[:2] == ct)] + lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) + # trade incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] if not debug: - lhs.append((-1*n.model["Link-p"].loc[:, incoming]*0.2571*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, outgoing]*0.2571*n.snapshot_weightings.generators).sum()) + lhs.append((-1*n.model["Link-p"].loc[:, incoming]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, outgoing]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) lhs = sum(lhs) - cname = f"co2_limit_upstream-{ct}" + cname = f"co2_limit-{ct}" n.model.add_constraints( lhs <= limit, @@ -495,7 +562,10 @@ def additional_functionality(n, snapshots, snakemake): #force_boiler_profiles_existing_per_load(n) force_boiler_profiles_existing_per_boiler(n) - # if snakemake.config["sector"]["co2_budget_national"]: - # limit_countries = snakemake.config["co2_budget_national"][investment_year] - # add_co2limit_country(n, limit_countries, snakemake, - # debug=snakemake.config["run"]["debug_co2_limit"]) + if snakemake.config["sector"]["co2_budget_national"]: + limit_countries = snakemake.config["co2_budget_national"][investment_year] + add_co2limit_country(n, limit_countries, snakemake, + debug=snakemake.config["run"]["debug_co2_limit"]) + + if snakemake.config["emissions_upstream"]["enable"]: + emissions_upstream(n) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index d4e97759..c7214caa 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -1852,6 +1852,9 @@ def get_emissions(n, region, _energy_totals): bus_carrier="co2",**kwargs ).filter(like=region).groupby("carrier").sum().multiply(t2Mt) + co2_emissions_global = n.statistics.supply( + bus_carrier="co2",**kwargs + ).groupby("carrier").sum().multiply(t2Mt) CHP_emissions = n.statistics.supply( bus_carrier="co2",**kwargs @@ -1890,6 +1893,10 @@ def get_emissions(n, region, _energy_totals): bus_carrier="co2",**kwargs ).filter(like=region).groupby("carrier").sum().multiply(t2Mt) + co2_negative_emissions_global = n.statistics.withdrawal( + bus_carrier="co2",**kwargs + ).groupby("carrier").sum().multiply(t2Mt) + co2_storage = n.statistics.supply( bus_carrier ="co2 stored",**kwargs ).filter(like=region).groupby("carrier").sum().multiply(t2Mt) @@ -1920,6 +1927,9 @@ def get_emissions(n, region, _energy_totals): var["Emissions|CO2"] = \ co2_emissions.sum() - co2_negative_emissions.sum() + + var["Emissions|CO2|Global"] = \ + co2_emissions_global.sum() - co2_negative_emissions_global.sum() # ! LULUCF should also be subtracted (or added??), we get from REMIND, # TODO how to consider it here? @@ -2323,7 +2333,7 @@ def get_prices(n, region): } # co2 additions - co2_price = -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price = -n.global_constraints.loc["CO2Limit", "mu"] #- n.global_constraints.loc["co2_limit-DE", "mu"] # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emisisons = { "oil" : 0.2571, @@ -2937,15 +2947,15 @@ def get_policy(n, investment_year): co2_price_add_on = 0.0 var["Price|Carbon"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price_add_on + -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on # - n.global_constraints.loc["co2_limit-DE", "mu"] var["Price|Carbon|EU-wide Regulation All Sectors"] = \ -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on # Price|Carbon|EU-wide Regulation Non-ETS - var["Price|Carbon|National Climate Target"] = \ - -n.global_constraints.loc["co2_limit-DE", "mu"] + # var["Price|Carbon|National Climate Target"] = \ + # -n.global_constraints.loc["co2_limit-DE", "mu"] # Price|Carbon|National Climate Target Non-ETS diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index e5c39ff8..3b2de8a7 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -352,22 +352,74 @@ def must_run_biomass(n, p_min_pu, regions): def emissions_upstream(n): - # add co2_emissions attribute to carriers - for carrier in specific_emisisons: - n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] - - # alter constraint + # old constraint limit = n.global_constraints.loc["CO2Limit","constant"] n.remove("GlobalConstraint", "CO2Limit") + + # # add co2_emissions attribute to carriers + # for carrier in specific_emisisons: + # n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] + + # n.add( + # "GlobalConstraint", + # "CO2Limit", + # carrier_attribute="co2_emissions", + # sense="<=", + # type="co2_emisisons", + # constant=limit, + # ) + + # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() + specific_emisisons = { + "oil" : 0.2571, + "gas" : 0.198, # OCGT + "coal" : 0.3361, + "lignite" : 0.4069, + # "co2 sequestered": 1.0, + # "co2": 0.0, + } + + lhs = [] + + # gas (spatially distributed) + i_gas = n.generators.index[(n.generators.carrier == "gas")] + lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + + # oil (EU oild and DE oil) + i_oil = n.generators.index[(n.generators.carrier == "oil")] + lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) + + # coal (only EU coal) + i_coal = n.generators.index[(n.generators.carrier == "coal")] + lhs.append((n.model["Generator-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) + + # lignite (only EU lignite) + i_lignite = n.generators.index[(n.generators.carrier == "lignite")] + lhs.append((n.model["Generator-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) + + # sequestration + i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] + lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) + + lhs = sum(lhs) + + cname = "CO2Limit" + + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint", + ) + + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) - n.add( - "GlobalConstraint", - "CO2Limit", - carrier_attribute="co2_emissions", - sense="<=", - type="co2_emisisons", - constant=limit, - ) if __name__ == "__main__": @@ -437,7 +489,7 @@ def emissions_upstream(n): if snakemake.params.biomass_must_run["enable"]: must_run_biomass(n, snakemake.params.biomass_must_run["p_min_pu"], snakemake.params.biomass_must_run["regions"]) - if snakemake.params.emissions_upstream["enable"]: - emissions_upstream(n) + # if snakemake.params.emissions_upstream["enable"]: + # emissions_upstream(n) n.export_to_netcdf(snakemake.output.network) From f42c1e139fffa336629d8bebfb011b9e87658983 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Tue, 9 Jul 2024 18:40:21 +0200 Subject: [PATCH 06/20] extend constraint with gas trade --- workflow/scripts/additional_functionality.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index b4d1b174..34e02924 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -402,18 +402,28 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) # coal - i_coal = n.links.index[(n.links.carrier == "coal") & (n.links.bus1.str[:2] == ct)] + i_coal = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) # lignite - i_lignite = n.links.index[(n.links.carrier == "lignite") & (n.links.bus1.str[:2] == ct)] + i_lignite = n.links.index[(n.links.bus0 == "EU lignite") & (n.links.bus1.str[:2] == ct)] lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) # sequestration i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered") & (n.links.index.str[:2] == ct)] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) - # trade + ## trade + + # gas + gas_pipe_c = ['gas pipeline', 'gas pipeline new'] + gas_out = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] == ct) & (n.links.bus1.str[:2] != ct)] + gas_in = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] != ct) & (n.links.bus1.str[:2] == ct)] + + lhs.append((-1*n.model["Link-p"].loc[:, gas_in]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, gas_out]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + + # oil incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] From 2fcef43d4fa810e3df0abc0c3eb0550bc0ebb484 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 11 Jul 2024 16:27:20 +0200 Subject: [PATCH 07/20] global constraint not working anymore --- workflow/scripts/additional_functionality.py | 69 +++++++------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 34e02924..505c9c78 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -223,22 +223,9 @@ def electricity_import_limits(n, snapshots, investment_year, config): def emissions_upstream(n): - # old constraint + # remove old constraint limit = n.global_constraints.loc["CO2Limit","constant"] n.remove("GlobalConstraint", "CO2Limit") - - # # add co2_emissions attribute to carriers - # for carrier in specific_emisisons: - # n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] - - # n.add( - # "GlobalConstraint", - # "CO2Limit", - # carrier_attribute="co2_emissions", - # sense="<=", - # type="co2_emisisons", - # constant=limit, - # ) # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emisisons = { @@ -246,32 +233,29 @@ def emissions_upstream(n): "gas" : 0.198, # OCGT "coal" : 0.3361, "lignite" : 0.4069, - # "co2 sequestered": 1.0, - # "co2": 0.0, } lhs = [] - # gas (spatially distributed) - i_gas = n.generators.index[(n.generators.carrier == "gas")] - lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - - # oil (EU oild and DE oil) - i_oil = n.generators.index[(n.generators.carrier == "oil")] - lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) - - # coal (only EU coal) - i_coal = n.generators.index[(n.generators.carrier == "coal")] - lhs.append((n.model["Generator-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) - - # lignite (only EU lignite) - i_lignite = n.generators.index[(n.generators.carrier == "lignite")] - lhs.append((n.model["Generator-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) + for c in specific_emisisons.keys(): + + i_fossil = n.generators.index[(n.generators.carrier == c)] + lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emisisons[c]*n.snapshot_weightings.generators).sum()) # sequestration i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) + # process emisions + i_pe = n.links.index[n.links.carrier == "process emissions"] + lhs.append((n.model["Link-p"].loc[:, i_pe]*n.snapshot_weightings.generators).sum()) + + i_pecc = n.links.index[n.links.carrier == "process emissions CC"] + lhs.append((n.model["Link-p"].loc[:, i_pe]*n.links.loc[i_pecc, "efficiency"]*n.snapshot_weightings.generators).sum()) + + i_nfi = n.links.index[(n.links.carrier == "naphtha for industry")] + lhs.append(-1*(n.model["Link-p"].loc[:, i_nfi]*n.links.loc[i_nfi, "efficiency3"]*n.snapshot_weightings.generators).sum()) + lhs = sum(lhs) cname = "CO2Limit" @@ -385,43 +369,38 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): "gas" : 0.198, # OCGT "coal" : 0.3361, "lignite" : 0.4069, - # "co2 sequestered": 1.0, - # "co2": 0.0, } lhs = [] - # restrict all trade and generation of fossil fuels in country ct - - # gas + # restrict all generation of fossil fuels i_gas = n.generators.index[(n.generators.carrier == "gas") & (n.generators.index.str[:2] == ct)] lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - # oil i_oil = n.generators.index[(n.generators.carrier == "oil") & (n.generators.index.str[:2] == ct)] lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) - # coal i_coal = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) - # lignite i_lignite = n.links.index[(n.links.bus0 == "EU lignite") & (n.links.bus1.str[:2] == ct)] lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) - # sequestration i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered") & (n.links.index.str[:2] == ct)] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) + # pe = n.loads.index[(n.loads.carrier == "process emissions") & (n.loads.bus.str[:2] == ct)] + # lhs.append(-1*(n.loads.loc[pe, "p_set"]*n.snapshot_weightings.generators.sum()).sum()) + ## trade # gas - gas_pipe_c = ['gas pipeline', 'gas pipeline new'] - gas_out = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] == ct) & (n.links.bus1.str[:2] != ct)] - gas_in = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] != ct) & (n.links.bus1.str[:2] == ct)] + # gas_pipe_c = ['gas pipeline', 'gas pipeline new'] + # gas_out = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] == ct) & (n.links.bus1.str[:2] != ct)] + # gas_in = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] != ct) & (n.links.bus1.str[:2] == ct)] - lhs.append((-1*n.model["Link-p"].loc[:, gas_in]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, gas_out]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + # lhs.append((-1*n.model["Link-p"].loc[:, gas_in]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + # lhs.append((n.model["Link-p"].loc[:, gas_out]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) # oil incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] From 3887b2e7a6c02c3dee59790d46d4e6dcbff0c4f3 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 11 Jul 2024 16:38:04 +0200 Subject: [PATCH 08/20] revert chenges for exporter --- workflow/scripts/export_ariadne_variables.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index eb1119d2..c923450e 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -2602,7 +2602,7 @@ def get_prices(n, region): } # co2 additions - co2_price = -n.global_constraints.loc["CO2Limit", "mu"] #- n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price = -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emisisons = { "oil" : 0.2571, @@ -3216,15 +3216,15 @@ def get_policy(n, investment_year): co2_price_add_on = 0.0 var["Price|Carbon"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on # - n.global_constraints.loc["co2_limit-DE", "mu"] + -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on - n.global_constraints.loc["co2_limit-DE", "mu"] var["Price|Carbon|EU-wide Regulation All Sectors"] = \ -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on # Price|Carbon|EU-wide Regulation Non-ETS - # var["Price|Carbon|National Climate Target"] = \ - # -n.global_constraints.loc["co2_limit-DE", "mu"] + var["Price|Carbon|National Climate Target"] = \ + -n.global_constraints.loc["co2_limit-DE", "mu"] # Price|Carbon|National Climate Target Non-ETS From 99184d46e1bca30c3bfb5875e4fe3acc42d2e730 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 11 Jul 2024 16:38:51 +0200 Subject: [PATCH 09/20] revert changes --- workflow/scripts/export_ariadne_variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index c923450e..5cf9c131 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -3216,7 +3216,7 @@ def get_policy(n, investment_year): co2_price_add_on = 0.0 var["Price|Carbon"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on - n.global_constraints.loc["co2_limit-DE", "mu"] + -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price_add_on var["Price|Carbon|EU-wide Regulation All Sectors"] = \ -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on From 6d483fe96c788d5935bfd54b2311f6b3a6f807b9 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 11 Jul 2024 16:40:57 +0200 Subject: [PATCH 10/20] remove space --- workflow/scripts/export_ariadne_variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index 5cf9c131..1ab26b58 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -3216,7 +3216,7 @@ def get_policy(n, investment_year): co2_price_add_on = 0.0 var["Price|Carbon"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price_add_on + -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price_add_on var["Price|Carbon|EU-wide Regulation All Sectors"] = \ -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on From 134166ff5e364994f8168b24630adfee2299ba1b Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Fri, 12 Jul 2024 08:58:32 +0200 Subject: [PATCH 11/20] wrong intend --- workflow/scripts/additional_functionality.py | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index c2c63d44..2097197a 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -353,24 +353,24 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): # Methane still missing, because its complicated - lhs = sum(lhs) + lhs = sum(lhs) - cname = f"co2_limit-{ct}" + cname = f"co2_limit-{ct}" - n.model.add_constraints( - lhs <= limit, - name=f"GlobalConstraint-{cname}", - ) + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint-{cname}", + ) - if cname not in n.global_constraints.index: - n.add( - "GlobalConstraint", - cname, - constant=limit, - sense="<=", - type="", - carrier_attribute="", - ) + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) # functionality if emissions upstream are enabled else: @@ -384,7 +384,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): ) # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() - specific_emisisons = { + specific_emissions = { "oil" : 0.2571, "gas" : 0.198, # OCGT "coal" : 0.3361, @@ -395,16 +395,16 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): # restrict all generation of fossil fuels i_gas = n.generators.index[(n.generators.carrier == "gas") & (n.generators.index.str[:2] == ct)] - lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emissions["gas"]*n.snapshot_weightings.generators).sum()) i_oil = n.generators.index[(n.generators.carrier == "oil") & (n.generators.index.str[:2] == ct)] - lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) i_coal = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] - lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emissions["coal"]*n.snapshot_weightings.generators).sum()) i_lignite = n.links.index[(n.links.bus0 == "EU lignite") & (n.links.bus1.str[:2] == ct)] - lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emissions["lignite"]*n.snapshot_weightings.generators).sum()) i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered") & (n.links.index.str[:2] == ct)] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) @@ -427,8 +427,8 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] if not debug: - lhs.append((-1*n.model["Link-p"].loc[:, incoming]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, outgoing]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) + lhs.append((-1*n.model["Link-p"].loc[:, incoming]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, outgoing]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) lhs = sum(lhs) From 45efb9ddc143afd788aa29c8da93504c86a77a30 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Wed, 17 Jul 2024 16:21:25 +0200 Subject: [PATCH 12/20] global constraint working --- workflow/scripts/additional_functionality.py | 28 +++--- workflow/scripts/modify_prenetwork.py | 89 +++----------------- 2 files changed, 27 insertions(+), 90 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 2097197a..d7dfda7f 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -2,6 +2,7 @@ import logging import pandas as pd +import os from prepare_sector_network import determine_emission_sectors from xarray import DataArray @@ -223,9 +224,7 @@ def electricity_import_limits(n, snapshots, investment_year, config): def emissions_upstream(n): - # remove old constraint - limit = n.global_constraints.loc["CO2Limit","constant"] - n.remove("GlobalConstraint", "CO2Limit") + limit = n.meta["_global_co2_limit"] # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emisisons = { @@ -246,23 +245,24 @@ def emissions_upstream(n): i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) - # process emisions + # process emissions i_pe = n.links.index[n.links.carrier == "process emissions"] lhs.append((n.model["Link-p"].loc[:, i_pe]*n.snapshot_weightings.generators).sum()) i_pecc = n.links.index[n.links.carrier == "process emissions CC"] - lhs.append((n.model["Link-p"].loc[:, i_pe]*n.links.loc[i_pecc, "efficiency"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, i_pecc]*n.snapshot_weightings.generators).sum()) + # lost oil emissions: this is the hvc sequestered emissions that are not accounted in the downstream constraint i_nfi = n.links.index[(n.links.carrier == "naphtha for industry")] - lhs.append(-1*(n.model["Link-p"].loc[:, i_nfi]*n.links.loc[i_nfi, "efficiency3"]*n.snapshot_weightings.generators).sum()) + lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum())) lhs = sum(lhs) - cname = "CO2Limit" + cname = "CO2LimitUpstream" n.model.add_constraints( lhs <= limit, - name=f"GlobalConstraint", + name=f"GlobalConstraint-{cname}", ) if cname not in n.global_constraints.index: @@ -571,10 +571,12 @@ def additional_functionality(n, snapshots, snakemake): #force_boiler_profiles_existing_per_load(n) force_boiler_profiles_existing_per_boiler(n) - if snakemake.config["sector"]["co2_budget_national"]: - limit_countries = snakemake.config["co2_budget_national"][investment_year] - add_co2limit_country(n, limit_countries, snakemake, - debug=snakemake.config["run"]["debug_co2_limit"]) - + # if snakemake.config["sector"]["co2_budget_national"]: + # limit_countries = snakemake.config["co2_budget_national"][investment_year] + # add_co2limit_country(n, limit_countries, snakemake, + # debug=snakemake.config["run"]["debug_co2_limit"]) + if snakemake.config["emissions_upstream"]["enable"]: emissions_upstream(n) + + n.export_to_netcdf("/home/julian-geis/repos/pypsa-ariadne-1/results/models/model_export.nc") diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index 995e1a08..aaccc99d 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -433,85 +433,20 @@ def aladin_mobility_demand(n): if not dsm_i.empty: n.stores.loc[dsm_i].e_nom *= pd.Series(factor.values, index=dsm_i) -# specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() -specific_emisisons = { - "oil" : 0.2571, - "gas" : 0.198, # OCGT - "coal" : 0.3361, - "lignite" : 0.4069, - "co2 sequestered": 1.0, - "co2": 0.0, -} def emissions_upstream(n): + """ + Delete current downstream constraint and save global co2 limit in n.meta. - # old constraint - limit = n.global_constraints.loc["CO2Limit","constant"] - n.remove("GlobalConstraint", "CO2Limit") - - # # add co2_emissions attribute to carriers - # for carrier in specific_emisisons: - # n.carriers.loc[carrier, "co2_emissions"] = specific_emisisons[carrier] - - # n.add( - # "GlobalConstraint", - # "CO2Limit", - # carrier_attribute="co2_emissions", - # sense="<=", - # type="co2_emisisons", - # constant=limit, - # ) - - # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() - specific_emisisons = { - "oil" : 0.2571, - "gas" : 0.198, # OCGT - "coal" : 0.3361, - "lignite" : 0.4069, - # "co2 sequestered": 1.0, - # "co2": 0.0, - } - - lhs = [] - - # gas (spatially distributed) - i_gas = n.generators.index[(n.generators.carrier == "gas")] - lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - - # oil (EU oild and DE oil) - i_oil = n.generators.index[(n.generators.carrier == "oil")] - lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum()) - - # coal (only EU coal) - i_coal = n.generators.index[(n.generators.carrier == "coal")] - lhs.append((n.model["Generator-p"].loc[:, i_coal]*specific_emisisons["coal"]*n.snapshot_weightings.generators).sum()) - - # lignite (only EU lignite) - i_lignite = n.generators.index[(n.generators.carrier == "lignite")] - lhs.append((n.model["Generator-p"].loc[:, i_lignite]*specific_emisisons["lignite"]*n.snapshot_weightings.generators).sum()) - - # sequestration - i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] - lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) - - lhs = sum(lhs) - - cname = "CO2Limit" - - n.model.add_constraints( - lhs <= limit, - name=f"GlobalConstraint", - ) + Parameters: + n (pypsa.Network): The PyPSA network object. - if cname not in n.global_constraints.index: - n.add( - "GlobalConstraint", - cname, - constant=limit, - sense="<=", - type="", - carrier_attribute="", - ) + Returns: + None + """ + + n.meta["_global_co2_limit"] = n.global_constraints.loc["CO2Limit","constant"] + n.remove("GlobalConstraint", "CO2Limit") @@ -584,7 +519,7 @@ def emissions_upstream(n): if snakemake.params.biomass_must_run["enable"]: must_run_biomass(n, snakemake.params.biomass_must_run["p_min_pu"], snakemake.params.biomass_must_run["regions"]) - # if snakemake.params.emissions_upstream["enable"]: - # emissions_upstream(n) + if snakemake.params.emissions_upstream["enable"]: + emissions_upstream(n) n.export_to_netcdf(snakemake.output.network) From b9b8cbb1306468f53d7fb99b79c5a96fc8711c05 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Thu, 18 Jul 2024 15:26:21 +0200 Subject: [PATCH 13/20] DE limit working, adpating exporter --- workflow/scripts/additional_functionality.py | 101 +++++++++---------- workflow/scripts/export_ariadne_variables.py | 26 +++-- workflow/scripts/modify_prenetwork.py | 6 +- 3 files changed, 64 insertions(+), 69 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index d7dfda7f..48ca0137 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -9,6 +9,13 @@ logger = logging.getLogger(__name__) +# specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() +specific_emissions = { + "oil" : 0.2571, + "gas" : 0.198, # OCGT + "coal" : 0.3361, + "lignite" : 0.4069, +} def add_min_limits(n, investment_year, config): @@ -224,22 +231,15 @@ def electricity_import_limits(n, snapshots, investment_year, config): def emissions_upstream(n): + logger.info(f"Adding global upstream co2 constraint.") limit = n.meta["_global_co2_limit"] - # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() - specific_emisisons = { - "oil" : 0.2571, - "gas" : 0.198, # OCGT - "coal" : 0.3361, - "lignite" : 0.4069, - } - lhs = [] - for c in specific_emisisons.keys(): + for c in specific_emissions.keys(): i_fossil = n.generators.index[(n.generators.carrier == c)] - lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emisisons[c]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emissions[c]*n.snapshot_weightings.generators).sum()) # sequestration i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] @@ -254,7 +254,7 @@ def emissions_upstream(n): # lost oil emissions: this is the hvc sequestered emissions that are not accounted in the downstream constraint i_nfi = n.links.index[(n.links.carrier == "naphtha for industry")] - lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emisisons["oil"]*n.snapshot_weightings.generators).sum())) + lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emissions["oil"]*n.snapshot_weightings.generators).sum())) lhs = sum(lhs) @@ -288,7 +288,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): limit_countries : dict snakemake: snakemake object """ - logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels") + logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels (downstream)") nhours = n.snapshot_weightings.generators.sum() nyears = nhours / 8760 @@ -306,7 +306,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): limit = co2_total_totals[ct]*limit_countries[ct] logger.info( f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " - f"1990 levels, i.e. {limit:,.2f} tCO2/a", + f"1990 levels, i.e. {limit:,.2f} tCO2/a (downstream)", ) lhs = [] @@ -374,65 +374,56 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): # functionality if emissions upstream are enabled else: - logger.info("Emissions upstream are enabled.") + logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels (upstream)") for ct in limit_countries: limit = co2_total_totals[ct]*limit_countries[ct] logger.info( f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " - f"1990 levels, i.e. {limit:,.2f} tCO2/a", + f"1990 levels, i.e. {limit:,.2f} tCO2/a (upstream)", ) - # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() - specific_emissions = { - "oil" : 0.2571, - "gas" : 0.198, # OCGT - "coal" : 0.3361, - "lignite" : 0.4069, - } - lhs = [] - # restrict all generation of fossil fuels - i_gas = n.generators.index[(n.generators.carrier == "gas") & (n.generators.index.str[:2] == ct)] - lhs.append((n.model["Generator-p"].loc[:, i_gas]*specific_emissions["gas"]*n.snapshot_weightings.generators).sum()) - - i_oil = n.generators.index[(n.generators.carrier == "oil") & (n.generators.index.str[:2] == ct)] - lhs.append((n.model["Generator-p"].loc[:, i_oil]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) - - i_coal = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] - lhs.append((n.model["Link-p"].loc[:, i_coal]*specific_emissions["coal"]*n.snapshot_weightings.generators).sum()) - - i_lignite = n.links.index[(n.links.bus0 == "EU lignite") & (n.links.bus1.str[:2] == ct)] - lhs.append((n.model["Link-p"].loc[:, i_lignite]*specific_emissions["lignite"]*n.snapshot_weightings.generators).sum()) + # generation + for c in specific_emissions.keys(): + i_fossil = n.generators.index[(n.generators.carrier == c) & (n.generators.index.str[:2] == ct)] + lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emissions[c]*n.snapshot_weightings.generators).sum()) + # sequestration i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered") & (n.links.index.str[:2] == ct)] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) - # pe = n.loads.index[(n.loads.carrier == "process emissions") & (n.loads.bus.str[:2] == ct)] - # lhs.append(-1*(n.loads.loc[pe, "p_set"]*n.snapshot_weightings.generators.sum()).sum()) + # process emissions + i_pe = n.links.index[(n.links.carrier == "process emissions") & (n.links.index.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, i_pe]*n.snapshot_weightings.generators).sum()) + + i_pecc = n.links.index[(n.links.carrier == "process emissions CC") & (n.links.index.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, i_pecc]*n.snapshot_weightings.generators).sum()) + + # lost oil emissions: this is the hvc sequestered emissions that are not accounted in the downstream constraint + i_nfi = n.links.index[(n.links.carrier == "naphtha for industry") & (n.links.index.str[:2] == ct)] + lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emissions["oil"]*n.snapshot_weightings.generators).sum())) - ## trade + # trade: import of fossils must be restricted; trade of gas as well - # gas - # gas_pipe_c = ['gas pipeline', 'gas pipeline new'] - # gas_out = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] == ct) & (n.links.bus1.str[:2] != ct)] - # gas_in = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] != ct) & (n.links.bus1.str[:2] == ct)] + # trade: import of fossils must be restricted; gas trade must not be considered? + coal_in = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, coal_in]*specific_emissions["coal"]*n.snapshot_weightings.generators).sum()) - # lhs.append((-1*n.model["Link-p"].loc[:, gas_in]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) - # lhs.append((n.model["Link-p"].loc[:, gas_out]*specific_emisisons["gas"]*n.snapshot_weightings.generators).sum()) + lignite_in = n.links.index[(n.links.bus0 == "EU lignite") & (n.links.bus1.str[:2] == ct)] + lhs.append((n.model["Link-p"].loc[:, lignite_in]*specific_emissions["lignite"]*n.snapshot_weightings.generators).sum()) - # oil - incoming = n.links.index[n.links.index == "EU renewable oil -> DE oil"] - outgoing = n.links.index[n.links.index == "DE renewable oil -> EU oil"] + gas_pipe_c = ['gas pipeline', 'gas pipeline new'] + gas_out = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] == ct) & (n.links.bus1.str[:2] != ct)] + gas_in = n.links.index[(n.links.carrier.isin(gas_pipe_c)) & (n.links.bus0.str[:2] != ct) & (n.links.bus1.str[:2] == ct)] - if not debug: - lhs.append((-1*n.model["Link-p"].loc[:, incoming]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) - lhs.append((n.model["Link-p"].loc[:, outgoing]*specific_emissions["oil"]*n.snapshot_weightings.generators).sum()) + lhs.append((n.model["Link-p"].loc[:, gas_in]*specific_emissions["gas"]*n.snapshot_weightings.generators).sum()) + lhs.append(-1*(n.model["Link-p"].loc[:, gas_out]*specific_emissions["gas"]*n.snapshot_weightings.generators).sum()) lhs = sum(lhs) - cname = f"co2_limit-{ct}" + cname = f"co2_limit_upstream-{ct}" n.model.add_constraints( lhs <= limit, @@ -571,10 +562,10 @@ def additional_functionality(n, snapshots, snakemake): #force_boiler_profiles_existing_per_load(n) force_boiler_profiles_existing_per_boiler(n) - # if snakemake.config["sector"]["co2_budget_national"]: - # limit_countries = snakemake.config["co2_budget_national"][investment_year] - # add_co2limit_country(n, limit_countries, snakemake, - # debug=snakemake.config["run"]["debug_co2_limit"]) + if snakemake.config["sector"]["co2_budget_national"]: + limit_countries = snakemake.config["co2_budget_national"][investment_year] + add_co2limit_country(n, limit_countries, snakemake, + debug=snakemake.config["run"]["debug_co2_limit"]) if snakemake.config["emissions_upstream"]["enable"]: emissions_upstream(n) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index 1ab26b58..8b4f8301 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -28,7 +28,6 @@ toe_to_MWh = 11.630 # GWh/ktoe OR MWh/toe - def _get_oil_fossil_fraction(n, region): kwargs = { 'groupby': n.statistics.groupers.get_name_bus_and_carrier, @@ -1296,7 +1295,7 @@ def get_secondary_energy(n, region, _industry_demand): var["Secondary Energy|Hydrogen"], hydrogen_production[ ~hydrogen_production.index.isin( - ["H2", "H2 pipeline", "H2 pipeline (Kernnetz)"] + ["H2", "H2 pipeline", "H2 pipeline (Kernnetz)", "H2 Store"] ) ].sum() ) @@ -2601,10 +2600,13 @@ def get_prices(n, region): 'nice_names': False, } + n_glob_co2 = "CO2Limit" if "CO2Limit" in n.global_constraints.index else "CO2LimitUpstream" + n_loc_co2 = "co2_limit-DE" if "co2_limit-DE" in n.global_constraints.index else "co2_limit_upstream-DE" + # co2 additions - co2_price = -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price = -n.global_constraints.loc[n_glob_co2, "mu"] - n.global_constraints.loc[n_loc_co2, "mu"] # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() - specific_emisisons = { + specific_emissions = { "oil" : 0.2571, "gas" : 0.198, # OCGT "hard coal" : 0.3361, @@ -2645,8 +2647,8 @@ def get_prices(n, region): coal_fraction = nf_coal.values.sum() / (nf_coal.values.sum() + nf_lignite.values.sum()) lignite_fraction = nf_lignite.values.sum() / (nf_coal.values.sum() + nf_lignite.values.sum()) co2_add_coal = \ - coal_fraction * specific_emisisons["hard coal"] * co2_price \ - + lignite_fraction * specific_emisisons["lignite"] * co2_price + coal_fraction * specific_emissions["hard coal"] * co2_price \ + + lignite_fraction * specific_emissions["lignite"] * co2_price var["Price|Primary Energy|Coal"] = \ (get_weighted_costs([coal_price, lignite_price], [nf_coal.values.sum(), nf_lignite.values.sum()]) + co2_add_coal)/ MWh2GJ @@ -2657,7 +2659,7 @@ def get_prices(n, region): # co2 part gas_fractions = _get_gas_fractions(n) - co2_add_gas = gas_fractions["Natural Gas"] * specific_emisisons["gas"] * co2_price + co2_add_gas = gas_fractions["Natural Gas"] * specific_emissions["gas"] * co2_price var["Price|Primary Energy|Gas"] = \ @@ -2670,7 +2672,7 @@ def get_prices(n, region): # co2 part oil_fossil_fraction = _get_oil_fossil_fraction(n, region) - co2_add_oil = oil_fossil_fraction * specific_emisisons["oil"] * co2_price + co2_add_oil = oil_fossil_fraction * specific_emissions["oil"] * co2_price var["Price|Primary Energy|Oil"] = \ (nodal_flows_oil.mul(nodal_prices_oil).values.sum() / nodal_flows_oil.values.sum() + co2_add_oil) /MWh2GJ @@ -3208,6 +3210,8 @@ def get_grid_investments(n, costs, region, dg_cost_factor=1.0, length_factor=1.0 def get_policy(n, investment_year): var = pd.Series() + n_glob_co2 = "CO2Limit" if "CO2Limit" in n.global_constraints.index else "CO2LimitUpstream" + n_loc_co2 = "co2_limit-DE" if "co2_limit-DE" in n.global_constraints.index else "co2_limit_upstream-DE" # add carbon component to fossil fuels if specified if investment_year in snakemake.params.co2_price_add_on_fossils.keys(): @@ -3216,15 +3220,15 @@ def get_policy(n, investment_year): co2_price_add_on = 0.0 var["Price|Carbon"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] - n.global_constraints.loc["co2_limit-DE", "mu"] + co2_price_add_on + -n.global_constraints.loc[n_glob_co2, "mu"] - n.global_constraints.loc[n_loc_co2, "mu"] + co2_price_add_on var["Price|Carbon|EU-wide Regulation All Sectors"] = \ - -n.global_constraints.loc["CO2Limit", "mu"] + co2_price_add_on + -n.global_constraints.loc[n_glob_co2, "mu"] + co2_price_add_on # Price|Carbon|EU-wide Regulation Non-ETS var["Price|Carbon|National Climate Target"] = \ - -n.global_constraints.loc["co2_limit-DE", "mu"] + -n.global_constraints.loc[n_loc_co2, "mu"] # Price|Carbon|National Climate Target Non-ETS diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index aaccc99d..28346ae5 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -434,7 +434,7 @@ def aladin_mobility_demand(n): n.stores.loc[dsm_i].e_nom *= pd.Series(factor.values, index=dsm_i) -def emissions_upstream(n): +def remove_downstream_constraint(n): """ Delete current downstream constraint and save global co2 limit in n.meta. @@ -444,7 +444,7 @@ def emissions_upstream(n): Returns: None """ - + logger.info(f"Remove global downstream co2 constraint.") n.meta["_global_co2_limit"] = n.global_constraints.loc["CO2Limit","constant"] n.remove("GlobalConstraint", "CO2Limit") @@ -520,6 +520,6 @@ def emissions_upstream(n): must_run_biomass(n, snakemake.params.biomass_must_run["p_min_pu"], snakemake.params.biomass_must_run["regions"]) if snakemake.params.emissions_upstream["enable"]: - emissions_upstream(n) + remove_downstream_constraint(n) n.export_to_netcdf(snakemake.output.network) From 43cb1bf956accf89a5cdd06752124d639b0af5d6 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Fri, 19 Jul 2024 00:57:57 +0200 Subject: [PATCH 14/20] comment --- workflow/scripts/additional_functionality.py | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 48ca0137..4b891546 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -407,7 +407,6 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): # trade: import of fossils must be restricted; trade of gas as well - # trade: import of fossils must be restricted; gas trade must not be considered? coal_in = n.links.index[(n.links.bus0 == "EU coal") & (n.links.bus1.str[:2] == ct)] lhs.append((n.model["Link-p"].loc[:, coal_in]*specific_emissions["coal"]*n.snapshot_weightings.generators).sum()) From 229e2df4c85ebeaf7d795dffea4445193332c9e9 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Fri, 19 Jul 2024 11:30:01 +0200 Subject: [PATCH 15/20] removed debug code --- workflow/scripts/additional_functionality.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 4b891546..65dde3b5 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -568,5 +568,3 @@ def additional_functionality(n, snapshots, snakemake): if snakemake.config["emissions_upstream"]["enable"]: emissions_upstream(n) - - n.export_to_netcdf("/home/julian-geis/repos/pypsa-ariadne-1/results/models/model_export.nc") From d709404cc13e3616f13812bf829abd355b81eeed Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Mon, 16 Sep 2024 10:43:23 +0200 Subject: [PATCH 16/20] error handling --- workflow/scripts/export_ariadne_variables.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index 8b4f8301..b5ea3e10 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -874,7 +874,8 @@ def get_primary_energy(n, region): "Store", ("Link", "gas pipeline"), ("Link", "gas pipeline new"), - ]).groupby( + ],errors="ignore" + ).groupby( "carrier" ).sum().multiply(gas_fractions["Natural Gas"]).multiply(MWh2PJ) From fd35fd497f96ad837aa3ef0bd5d2a1a370299e80 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Tue, 17 Sep 2024 15:03:56 +0200 Subject: [PATCH 17/20] config adaptions --- config/config.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 9b1a3018..3331293d 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,10 +4,11 @@ # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: - prefix: 20240710limitwasteheat + prefix: 20240807UEOnlyGlobalComparison name: # - CurrentPolicies - KN2045_Bal_v4 + - KN2045_Bal_v4_ue # - KN2045_Elec_v4 # - KN2045_H2_v4 # - KN2045plus_EasyRide @@ -257,7 +258,7 @@ sector: regional_methanol_demand: true #set to true if regional CO2 constraints needed regional_oil_demand: true #set to true if regional CO2 constraints needed regional_coal_demand: true #set to true if regional CO2 constraints needed - gas_network: true + gas_network: false biogas_upgrading_cc: true cluster_heat_buses: true # calculated based on ariadne "Stock|Space Heating" @@ -352,7 +353,7 @@ solving: mem_mb: 70000 #30000 is OK for 22 nodes, 365H; 140000 for 22 nodes 3H; 400000 for 44 nodes 3H options: assign_all_duals: true - load_shedding: false + load_shedding: true skip_iterations: true # settings for post-discretization: false min_iterations: 1 # settings for post-discretization: 1 max_iterations: 1 # settings for post-discretization: 1 From cd5389146c1d5d72fc053ef6068fd598b851619e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:20:41 +0000 Subject: [PATCH 18/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- config/config.yaml | 1 - workflow/scripts/additional_functionality.py | 14 ++--- workflow/scripts/export_ariadne_variables.py | 62 +++++++++----------- workflow/scripts/modify_prenetwork.py | 16 ++--- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index c1e3fa51..0535d3e0 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -614,4 +614,3 @@ must_run_biogas: emissions_upstream: enable: true - diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 7feb7349..95443cc7 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- import logging +import os import pandas as pd -import os from prepare_sector_network import determine_emission_sectors from xarray import DataArray @@ -261,7 +261,7 @@ def emissions_upstream(n): lhs = [] for c in specific_emissions.keys(): - + i_fossil = n.generators.index[(n.generators.carrier == c)] lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emissions[c]*n.snapshot_weightings.generators).sum()) @@ -297,7 +297,7 @@ def emissions_upstream(n): sense="<=", type="", carrier_attribute="", - ) + ) def add_co2limit_country(n, limit_countries, snakemake, debug=False): @@ -441,7 +441,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): type="", carrier_attribute="", ) - + # functionality if emissions upstream are enabled else: logger.info(f"Adding CO2 budget limit for each country as per unit of 1990 levels (upstream)") @@ -455,7 +455,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): lhs = [] - # generation + # generation for c in specific_emissions.keys(): i_fossil = n.generators.index[(n.generators.carrier == c) & (n.generators.index.str[:2] == ct)] lhs.append((n.model["Generator-p"].loc[:, i_fossil]*specific_emissions[c]*n.snapshot_weightings.generators).sum()) @@ -507,7 +507,7 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): sense="<=", type="", carrier_attribute="", - ) + ) @@ -694,6 +694,6 @@ def additional_functionality(n, snapshots, snakemake): ) else: logger.warning("No national CO2 budget specified!") - + if snakemake.config["emissions_upstream"]["enable"]: emissions_upstream(n) diff --git a/workflow/scripts/export_ariadne_variables.py b/workflow/scripts/export_ariadne_variables.py index 4c5931d5..38f28d65 100644 --- a/workflow/scripts/export_ariadne_variables.py +++ b/workflow/scripts/export_ariadne_variables.py @@ -177,13 +177,8 @@ def _get_gas_fractions(n, region): # the difference stays roughly the same after the calculation. assert isclose( domestic_gas_supply.get("renewable gas", 0) - renewable_gas_balance.sum(), - total_gas_supply.get( - ["DE renewable gas -> DE gas"], - pd.Series(0)).sum() - + total_gas_supply.get( - ["DE renewable gas -> EU gas"], - pd.Series(0) - ).sum() + total_gas_supply.get(["DE renewable gas -> DE gas"], pd.Series(0)).sum() + + total_gas_supply.get(["DE renewable gas -> EU gas"], pd.Series(0)).sum() - renewable_gas_supply.get("DE renewable gas", pd.Series(0)).sum(), rtol=1e-3, ) @@ -2995,23 +2990,19 @@ def get_prices(n, region): "groupby": n.statistics.groupers.get_name_bus_and_carrier, "nice_names": False, } - try: + try: co2_limit_de = n.global_constraints.loc["co2_limit-DE", "mu"] except KeyError: co2_limit_de = 0 - # co2 additions - co2_price = ( - -n.global_constraints.loc["CO2Limit", "mu"] - - co2_limit_de - ) + co2_price = -n.global_constraints.loc["CO2Limit", "mu"] - co2_limit_de # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emissions = { - "oil" : 0.2571, - "gas" : 0.198, # OCGT - "hard coal" : 0.3361, - "lignite" : 0.4069, + "oil": 0.2571, + "gas": 0.198, # OCGT + "hard coal": 0.3361, + "lignite": 0.4069, } nodal_flows_lv = get_nodal_flows( @@ -3602,8 +3593,7 @@ def get_grid_investments(n, costs, region, length_factor=1.0): - distribution_grid[distribution_grid.build_year <= year_pre].p_nom_opt.sum() ) dg_investment = ( - dg_expansion - * costs.at["electricity distribution grid", "investment"] + dg_expansion * costs.at["electricity distribution grid", "investment"] ) var["Investment|Energy Supply|Electricity|Distribution"] = dg_investment / 5 @@ -3686,22 +3676,26 @@ def get_grid_investments(n, costs, region, length_factor=1.0): def get_policy(n, investment_year): var = pd.Series() - n_glob_co2 = "CO2Limit" if "CO2Limit" in n.global_constraints.index else "CO2LimitUpstream" - n_loc_co2 = "co2_limit-DE" if "co2_limit-DE" in n.global_constraints.index else "co2_limit_upstream-DE" - + n_glob_co2 = ( + "CO2Limit" if "CO2Limit" in n.global_constraints.index else "CO2LimitUpstream" + ) + n_loc_co2 = ( + "co2_limit-DE" + if "co2_limit-DE" in n.global_constraints.index + else "co2_limit_upstream-DE" + ) + # add carbon component to fossil fuels if specified if investment_year in snakemake.params.co2_price_add_on_fossils.keys(): co2_price_add_on = snakemake.params.co2_price_add_on_fossils[investment_year] else: co2_price_add_on = 0.0 - try: + try: co2_limit_de = n.global_constraints.loc["co2_limit-DE", "mu"] except KeyError: co2_limit_de = 0 var["Price|Carbon"] = ( - -n.global_constraints.loc["CO2Limit", "mu"] - - co2_limit_de - + co2_price_add_on + -n.global_constraints.loc["CO2Limit", "mu"] - co2_limit_de + co2_price_add_on ) var["Price|Carbon|EU-wide Regulation All Sectors"] = ( @@ -3836,20 +3830,24 @@ def get_export_import_links(n, region, carriers): if DE_renewable_gas.sum() == 0: DE_bio_fraction = 0 else: - DE_bio_fraction = DE_renewable_gas.filter(like="biogas to gas").sum() / DE_renewable_gas.sum() + DE_bio_fraction = ( + DE_renewable_gas.filter(like="biogas to gas").sum() / DE_renewable_gas.sum() + ) if EU_renewable_gas.sum() == 0: EU_bio_fraction = 0 else: - EU_bio_fraction = EU_renewable_gas.filter(like="biogas to gas").sum() / EU_renewable_gas.sum() + EU_bio_fraction = ( + EU_renewable_gas.filter(like="biogas to gas").sum() / EU_renewable_gas.sum() + ) - assert region == "DE" # only DE is implemented at the moment + assert region == "DE" # only DE is implemented at the moment exports_gas_renew, imports_gas_renew = get_export_import_links( n, region, ["renewable gas"] ) var["Trade|Secondary Energy|Gases|Hydrogen|Volume"] = ( - exports_gas_renew * (1 - DE_bio_fraction) + exports_gas_renew * (1 - DE_bio_fraction) - imports_gas_renew * (1 - EU_bio_fraction) ) * MWh2PJ var["Trade|Secondary Energy|Gases|Hydrogen|Gross Import|Volume"] = ( @@ -3857,14 +3855,12 @@ def get_export_import_links(n, region, carriers): ) var["Trade|Secondary Energy|Gases|Biomass|Volume"] = ( - exports_gas_renew * DE_bio_fraction - - imports_gas_renew * EU_bio_fraction + exports_gas_renew * DE_bio_fraction - imports_gas_renew * EU_bio_fraction ) * MWh2PJ var["Trade|Secondary Energy|Gases|Biomass|Gross Import|Volume"] = ( imports_gas_renew * EU_bio_fraction * MWh2PJ ) - # TODO add methanol trade, renewable gas trade # Trade|Primary Energy|Coal|Volume diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index 72a85d3d..f2c8934f 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -363,10 +363,9 @@ def unravel_oilbus(n): carrier="renewable oil", p_nom=1e6, p_min_pu=0, - marginal_cost=0.01 -, - ) - + marginal_cost=0.01, + ) + n.madd( "Link", [ @@ -427,8 +426,7 @@ def unravel_oilbus(n): carrier="methanol", p_nom=1e6, p_min_pu=0, - marginal_cost=0.01 -, + marginal_cost=0.01, ) # add stores @@ -535,8 +533,7 @@ def unravel_gasbus(n, costs): carrier="renewable gas", p_nom=1e6, p_min_pu=0, - marginal_cost=0.01 -, + marginal_cost=0.01, ) ### add links between renewable and fossil gas buses @@ -711,11 +708,10 @@ def remove_downstream_constraint(n): None """ logger.info(f"Remove global downstream co2 constraint.") - n.meta["_global_co2_limit"] = n.global_constraints.loc["CO2Limit","constant"] + n.meta["_global_co2_limit"] = n.global_constraints.loc["CO2Limit", "constant"] n.remove("GlobalConstraint", "CO2Limit") - def add_hydrogen_turbines(n): """ This adds links that instead of a gas turbine use a hydrogen turbine. From 16d10a6145d25a3cdbf3e7dd7787fc9f1424cfc7 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Fri, 20 Sep 2024 14:47:00 +0200 Subject: [PATCH 19/20] minor fixes --- config/config.yaml | 3 +- workflow/scripts/additional_functionality.py | 164 +++++++++---------- workflow/scripts/modify_prenetwork.py | 3 - 3 files changed, 83 insertions(+), 87 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 0535d3e0..b2431fe9 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,11 +4,10 @@ # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: - prefix: 20240807UEOnlyGlobalComparison + prefix: 20240920UpstreamEmissions name: # - CurrentPolicies - KN2045_Bal_v4 - - KN2045_Bal_v4_ue # - KN2045_Elec_v4 # - KN2045_H2_v4 # - KN2045plus_EasyRide diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 95443cc7..d5c0ca2b 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -19,10 +19,11 @@ def add_capacity_limits(n, investment_year, limits_capacity, sense="maximum"): - for c in n.iterate_components(limits_capacity): logger.info(f"Adding {sense} constraints for {c.list_name}") + attr = "e" if c.name == "Store" else "p" + units = "MWh or tCO2" if c.name == "Store" else "MW" for carrier in limits_capacity[c.name]: @@ -327,119 +328,119 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): if not snakemake.config["emissions_upstream"]["enable"]: for ct in limit_countries: - limit = co2_total_totals[ct]*limit_countries[ct] + limit = co2_total_totals[ct] * limit_countries[ct] logger.info( f"Limiting emissions in country {ct} to {limit_countries[ct]:.1%} of " - f"1990 levels, i.e. {limit:,.2f} tCO2/a (downstream)", + f"1990 levels, i.e. {limit:,.2f} tCO2/a", ) lhs = [] for port in [col[3:] for col in n.links if col.startswith("bus")]: - links = n.links.index[ - (n.links.index.str[:2] == ct) - & (n.links[f"bus{port}"] == "co2 atmosphere") - ] + links = n.links.index[ + (n.links.index.str[:2] == ct) + & (n.links[f"bus{port}"] == "co2 atmosphere") + ] - logger.info( - f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}" - ) + logger.info( + f"For {ct} adding following link carriers to port {port} CO2 constraint: {n.links.loc[links,'carrier'].unique()}" + ) + + if port == "0": + efficiency = -1.0 + elif port == "1": + efficiency = n.links.loc[links, f"efficiency"] + else: + efficiency = n.links.loc[links, f"efficiency{port}"] + + lhs.append( + ( + n.model["Link-p"].loc[:, links] + * efficiency + * n.snapshot_weightings.generators + ).sum() + ) + + # Adding Efuel imports and exports to constraint + incoming_oil = n.links.index[n.links.index == "EU renewable oil -> DE oil"] + outgoing_oil = n.links.index[n.links.index == "DE renewable oil -> EU oil"] + + if not debug: + lhs.append( + ( + -1 + * n.model["Link-p"].loc[:, incoming_oil] + * 0.2571 + * n.snapshot_weightings.generators + ).sum() + ) + lhs.append( + ( + n.model["Link-p"].loc[:, outgoing_oil] + * 0.2571 + * n.snapshot_weightings.generators + ).sum() + ) - if port == "0": - efficiency = -1.0 - elif port == "1": - efficiency = n.links.loc[links, f"efficiency"] - else: - efficiency = n.links.loc[links, f"efficiency{port}"] + incoming_methanol = n.links.index[n.links.index == "EU methanol -> DE methanol"] + outgoing_methanol = n.links.index[n.links.index == "DE methanol -> EU methanol"] lhs.append( ( - n.model["Link-p"].loc[:, links] - * efficiency + -1 + * n.model["Link-p"].loc[:, incoming_methanol] + / snakemake.config["sector"]["MWh_MeOH_per_tCO2"] + * n.snapshot_weightings.generators + ).sum() + ) + + lhs.append( + ( + n.model["Link-p"].loc[:, outgoing_methanol] + / snakemake.config["sector"]["MWh_MeOH_per_tCO2"] * n.snapshot_weightings.generators ).sum() ) - # Adding Efuel imports and exports to constraint - incoming_oil = n.links.index[n.links.index == "EU renewable oil -> DE oil"] - outgoing_oil = n.links.index[n.links.index == "DE renewable oil -> EU oil"] + # Methane + incoming_CH4 = n.links.index[n.links.index == "EU renewable gas -> DE gas"] + outgoing_CH4 = n.links.index[n.links.index == "DE renewable gas -> EU gas"] - if not debug: lhs.append( ( -1 - * n.model["Link-p"].loc[:, incoming_oil] - * 0.2571 + * n.model["Link-p"].loc[:, incoming_CH4] + * 0.198 * n.snapshot_weightings.generators ).sum() ) + lhs.append( ( - n.model["Link-p"].loc[:, outgoing_oil] - * 0.2571 + n.model["Link-p"].loc[:, outgoing_CH4] + * 0.198 * n.snapshot_weightings.generators ).sum() ) - incoming_methanol = n.links.index[n.links.index == "EU methanol -> DE methanol"] - outgoing_methanol = n.links.index[n.links.index == "DE methanol -> EU methanol"] - - lhs.append( - ( - -1 - * n.model["Link-p"].loc[:, incoming_methanol] - / snakemake.config["sector"]["MWh_MeOH_per_tCO2"] - * n.snapshot_weightings.generators - ).sum() - ) - - lhs.append( - ( - n.model["Link-p"].loc[:, outgoing_methanol] - / snakemake.config["sector"]["MWh_MeOH_per_tCO2"] - * n.snapshot_weightings.generators - ).sum() - ) - - # Methane - incoming_CH4 = n.links.index[n.links.index == "EU renewable gas -> DE gas"] - outgoing_CH4 = n.links.index[n.links.index == "DE renewable gas -> EU gas"] - - lhs.append( - ( - -1 - * n.model["Link-p"].loc[:, incoming_CH4] - * 0.198 - * n.snapshot_weightings.generators - ).sum() - ) - - lhs.append( - ( - n.model["Link-p"].loc[:, outgoing_CH4] - * 0.198 - * n.snapshot_weightings.generators - ).sum() - ) - - lhs = sum(lhs) + lhs = sum(lhs) - cname = f"co2_limit-{ct}" + cname = f"co2_limit-{ct}" - n.model.add_constraints( - lhs <= limit, - name=f"GlobalConstraint-{cname}", - ) + n.model.add_constraints( + lhs <= limit, + name=f"GlobalConstraint-{cname}", + ) - if cname not in n.global_constraints.index: - n.add( - "GlobalConstraint", - cname, - constant=limit, - sense="<=", - type="", - carrier_attribute="", + if cname not in n.global_constraints.index: + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", ) # functionality if emissions upstream are enabled @@ -511,7 +512,6 @@ def add_co2limit_country(n, limit_countries, snakemake, debug=False): - def force_boiler_profiles_existing_per_load(n): """ This scales the boiler dispatch to the load profile with a factor common to diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index f2c8934f..1c06ee59 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -912,7 +912,4 @@ def force_retrofit(n, params): if snakemake.params.emissions_upstream["enable"]: remove_downstream_constraint(n) - if snakemake.params.emissions_upstream["enable"]: - remove_downstream_constraint(n) - n.export_to_netcdf(snakemake.output.network) From c37495ef514fece93ece822229754a3af777d851 Mon Sep 17 00:00:00 2001 From: JulianGeis Date: Fri, 8 Nov 2024 10:23:00 +0100 Subject: [PATCH 20/20] merging and testing --- config/config.yaml | 10 ++-- workflow/scripts/additional_functionality.py | 63 ++++++++++---------- workflow/scripts/modify_prenetwork.py | 7 +-- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 2d2b26c0..5bd589ad 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,7 +4,7 @@ # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run run: - prefix: 20241011PlotReport + prefix: 20241023-UpstreamEmissions-100H name: # - CurrentPolicies @@ -233,7 +233,7 @@ clustering: # 'ES': 0.0408 # 'IT': 0.0612 temporal: - resolution_sector: 780H + resolution_sector: 100H # docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#co2-budget co2_budget: @@ -298,8 +298,8 @@ sector: regional_coal_demand: true #set to true if regional CO2 constraints needed gas_network: false biogas_upgrading_cc: true - biomass_to_liquid: true - biomass_to_liquid_cc: true + biomass_to_liquid: false + biomass_to_liquid_cc: false cluster_heat_buses: true # calculated based on ariadne "Stock|Space Heating" # and then 2% of buildings renovated per year to reduce their demand by 80% @@ -399,7 +399,7 @@ solving: mem_mb: 70000 #30000 is OK for 22 nodes, 365H; 140000 for 22 nodes 3H; 400000 for 44 nodes 3H options: assign_all_duals: true - load_shedding: true + load_shedding: false skip_iterations: true # settings for post-discretization: false min_iterations: 1 # settings for post-discretization: 1 max_iterations: 1 # settings for post-discretization: 1 diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 38c54e01..24969ce9 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -11,6 +11,7 @@ # specific emissions in tons CO2/MWh according to n.links[n.links.carrier =="your_carrier].efficiency2.unique().item() specific_emissions = { + "oil primary" : 0.2571, "oil" : 0.2571, "gas" : 0.198, # OCGT "coal" : 0.3361, @@ -292,16 +293,16 @@ def emissions_upstream(n): i_sequestered = n.links.index[(n.links.carrier == "co2 sequestered")] lhs.append((-1*n.model["Link-p"].loc[:, i_sequestered]*n.snapshot_weightings.generators).sum()) - # process emissions - i_pe = n.links.index[n.links.carrier == "process emissions"] - lhs.append((n.model["Link-p"].loc[:, i_pe]*n.snapshot_weightings.generators).sum()) + # # process emissions + # i_pe = n.links.index[n.links.carrier == "process emissions"] + # lhs.append((n.model["Link-p"].loc[:, i_pe]*n.snapshot_weightings.generators).sum()) - i_pecc = n.links.index[n.links.carrier == "process emissions CC"] - lhs.append((n.model["Link-p"].loc[:, i_pecc]*n.snapshot_weightings.generators).sum()) + # i_pecc = n.links.index[n.links.carrier == "process emissions CC"] + # lhs.append((n.model["Link-p"].loc[:, i_pecc]*n.snapshot_weightings.generators).sum()) - # lost oil emissions: this is the hvc sequestered emissions that are not accounted in the downstream constraint - i_nfi = n.links.index[(n.links.carrier == "naphtha for industry")] - lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emissions["oil"]*n.snapshot_weightings.generators).sum())) + # # lost oil emissions: this is the hvc sequestered emissions that are not accounted in the downstream constraint + # i_nfi = n.links.index[(n.links.carrier == "naphtha for industry")] + # lhs.append(-1*((n.model["Link-p"].loc[:, i_nfi]*(1-n.links.loc[i_nfi, "efficiency2"])*specific_emissions["oil"]*n.snapshot_weightings.generators).sum())) lhs = sum(lhs) @@ -312,20 +313,20 @@ def emissions_upstream(n): name=f"GlobalConstraint-{cname}", ) - if cname in n.global_constraints.index: - logger.warning( - f"Global constraint {cname} already exists. Dropping and adding it again." - ) - n.global_constraints.drop(cname, inplace=True) - - n.add( - "GlobalConstraint", - cname, - constant=limit, - sense="<=", - type="", - carrier_attribute="", + if cname in n.global_constraints.index: + logger.warning( + f"Global constraint {cname} already exists. Dropping and adding it again." ) + n.global_constraints.drop(cname, inplace=True) + + n.add( + "GlobalConstraint", + cname, + constant=limit, + sense="<=", + type="", + carrier_attribute="", + ) def add_co2limit_country(n, limit_countries, snakemake, debug=False): @@ -760,16 +761,16 @@ def additional_functionality(n, snapshots, snakemake): # force_boiler_profiles_existing_per_load(n) force_boiler_profiles_existing_per_boiler(n) - if isinstance(constraints["co2_budget_national"], dict): - limit_countries = constraints["co2_budget_national"][investment_year] - add_co2limit_country( - n, - limit_countries, - snakemake, - debug=snakemake.config["run"]["debug_co2_limit"], - ) - else: - logger.warning("No national CO2 budget specified!") + # if isinstance(constraints["co2_budget_national"], dict): + # limit_countries = constraints["co2_budget_national"][investment_year] + # add_co2limit_country( + # n, + # limit_countries, + # snakemake, + # debug=snakemake.config["run"]["debug_co2_limit"], + # ) + # else: + # logger.warning("No national CO2 budget specified!") if snakemake.config["emissions_upstream"]["enable"]: emissions_upstream(n) diff --git a/workflow/scripts/modify_prenetwork.py b/workflow/scripts/modify_prenetwork.py index 34f896ff..7d491e74 100644 --- a/workflow/scripts/modify_prenetwork.py +++ b/workflow/scripts/modify_prenetwork.py @@ -393,9 +393,6 @@ def unravel_carbonaceous_fuels(n): marginal_cost=0.01, ) - marginal_cost=0.01, - ) - n.madd( "Link", [ @@ -1175,9 +1172,9 @@ def force_connection_nep_offshore(n, current_year): new_boiler_ban(n) - fix_new_boiler_profiles(n) + # fix_new_boiler_profiles(n) - remove_old_boiler_profiles(n) + # remove_old_boiler_profiles(n) coal_generation_ban(n)