From 4a3fe07edb1eb2a04af533299cfead6896a4089e Mon Sep 17 00:00:00 2001 From: toniseibold Date: Mon, 2 Dec 2024 14:37:21 +0100 Subject: [PATCH 1/6] first stab of flaechenziel for onwind --- config/config.yaml | 8 ++- workflow/Snakefile | 1 + workflow/scripts/additional_functionality.py | 66 ++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index 713449c9..b14ff1d9 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: 20241121-fix-missing-gas-capa + prefix: 20241202-adjust-onwind name: # - CurrentPolicies @@ -432,6 +432,12 @@ solving: H2 pipeline retrofitted: 0.05 fractional_last_unit_size: true constraints: + onwind_flaechenziel: + enable: true + percentage: # % of total land area + 2035: 0.5 + 2040: 0.75 + 2045: 1.0 limits_capacity_max: Generator: onwind: diff --git a/workflow/Snakefile b/workflow/Snakefile index 918b2a59..5f0a8c1f 100644 --- a/workflow/Snakefile +++ b/workflow/Snakefile @@ -311,6 +311,7 @@ use rule solve_sector_network_myopic from pypsaeur with: network=RESULTS + "prenetworks-final/base_s_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc", co2_totals_name=resources("co2_totals.csv"), + regions_onshore=resources("regions_onshore_base_s_{clusters}.geojson"), rule modify_existing_heating: diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index b47a4f90..e47c4ac9 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -3,6 +3,7 @@ import logging import pandas as pd +import geopandas as gpd from prepare_sector_network import determine_emission_sectors from xarray import DataArray @@ -663,6 +664,68 @@ def adapt_nuclear_output(n): ) +def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): + + regions_onshore = gpd.read_file(snakemake.input.regions_onshore) + regions_onshore.set_index("name", inplace=True) + regions_onshore = regions_onshore.to_crs(epsg=3035) + # area in sqkm + area = regions_onshore[regions_onshore.index.str.startswith("DE")].geometry.area / 1e6 + + mw_per_sqkm = 30 # source: https://www.ffe.de/wp-content/uploads/2022/02/FfE-Discussion-Paper-2-der-Landesflaeche-fuer-Windenergie-ein-geeignetes-Mass.pdf page 7 + # % into fraction + flaechenziel = onwind_constraint[investment_year] / 100 + limit = flaechenziel * area * mw_per_sqkm + + for region in area.index: + valid_components = ( + (n.generators.bus == region) + & (n.generators.carrier == "onwind") + ) + + existing_index = n.generators.index[ + valid_components & ~n.generators.p_nom_extendable + ] + extendable_index = n.generators.index[ + valid_components & n.generators.p_nom_extendable + ] + + if n.generators.loc[extendable_index[0], "p_nom_max"] < 10: + logger.warning(f"Skipping onwind constraint for {region} as no extendable capacity exists") + continue + elif existing_index.empty: + logger.info(f"No existing onwind capacity in {region}") + existing_cap = 0 + else: + existing_cap = n.generators.loc[existing_index, "p_nom"].sum() + + lhs = n.model["Generator-p_nom"].loc[extendable_index] + rhs = limit[region] - existing_cap + if rhs <= 0: + logger.info(f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit[region]/1000} GW in {region}.") + continue + + cname = f"flaechenziel_onwind-{region}" + + logger.info(f"Adding Flaechenziel for {region} of {rhs/1000} GW.") + n.model.add_constraints(lhs >= rhs, 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=rhs, + sense=">=", + type="", + carrier_attribute="", + ) + + def additional_functionality(n, snapshots, snakemake): logger.info("Adding Ariadne-specific functionality") @@ -712,3 +775,6 @@ def additional_functionality(n, snapshots, snakemake): if investment_year == 2020: adapt_nuclear_output(n) + + if constraints["onwind_flaechenziel"]["enable"] and investment_year in constraints["onwind_flaechenziel"]["percentage"].keys(): + add_onwind_constraint(n, investment_year, snakemake, constraints["onwind_flaechenziel"]["percentage"]) From 81fe15f1dcad88f341eaefe1367e08af919bd105 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:43:18 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- workflow/scripts/additional_functionality.py | 37 +++++++++++++------- workflow/scripts/build_scenarios.py | 5 +-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index e47c4ac9..d749d8c0 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -2,8 +2,8 @@ import logging -import pandas as pd import geopandas as gpd +import pandas as pd from prepare_sector_network import determine_emission_sectors from xarray import DataArray @@ -670,17 +670,18 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): regions_onshore.set_index("name", inplace=True) regions_onshore = regions_onshore.to_crs(epsg=3035) # area in sqkm - area = regions_onshore[regions_onshore.index.str.startswith("DE")].geometry.area / 1e6 + area = ( + regions_onshore[regions_onshore.index.str.startswith("DE")].geometry.area / 1e6 + ) - mw_per_sqkm = 30 # source: https://www.ffe.de/wp-content/uploads/2022/02/FfE-Discussion-Paper-2-der-Landesflaeche-fuer-Windenergie-ein-geeignetes-Mass.pdf page 7 + mw_per_sqkm = 30 # source: https://www.ffe.de/wp-content/uploads/2022/02/FfE-Discussion-Paper-2-der-Landesflaeche-fuer-Windenergie-ein-geeignetes-Mass.pdf page 7 # % into fraction flaechenziel = onwind_constraint[investment_year] / 100 limit = flaechenziel * area * mw_per_sqkm for region in area.index: - valid_components = ( - (n.generators.bus == region) - & (n.generators.carrier == "onwind") + valid_components = (n.generators.bus == region) & ( + n.generators.carrier == "onwind" ) existing_index = n.generators.index[ @@ -691,18 +692,22 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): ] if n.generators.loc[extendable_index[0], "p_nom_max"] < 10: - logger.warning(f"Skipping onwind constraint for {region} as no extendable capacity exists") + logger.warning( + f"Skipping onwind constraint for {region} as no extendable capacity exists" + ) continue elif existing_index.empty: logger.info(f"No existing onwind capacity in {region}") existing_cap = 0 else: existing_cap = n.generators.loc[existing_index, "p_nom"].sum() - + lhs = n.model["Generator-p_nom"].loc[extendable_index] rhs = limit[region] - existing_cap if rhs <= 0: - logger.info(f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit[region]/1000} GW in {region}.") + logger.info( + f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit[region]/1000} GW in {region}." + ) continue cname = f"flaechenziel_onwind-{region}" @@ -715,7 +720,7 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): f"Global constraint {cname} already exists. Dropping and adding it again." ) n.global_constraints.drop(cname, inplace=True) - + n.add( "GlobalConstraint", cname, @@ -776,5 +781,13 @@ def additional_functionality(n, snapshots, snakemake): if investment_year == 2020: adapt_nuclear_output(n) - if constraints["onwind_flaechenziel"]["enable"] and investment_year in constraints["onwind_flaechenziel"]["percentage"].keys(): - add_onwind_constraint(n, investment_year, snakemake, constraints["onwind_flaechenziel"]["percentage"]) + if ( + constraints["onwind_flaechenziel"]["enable"] + and investment_year in constraints["onwind_flaechenziel"]["percentage"].keys() + ): + add_onwind_constraint( + n, + investment_year, + snakemake, + constraints["onwind_flaechenziel"]["percentage"], + ) diff --git a/workflow/scripts/build_scenarios.py b/workflow/scripts/build_scenarios.py index 4fc00ce8..4fba8ec7 100644 --- a/workflow/scripts/build_scenarios.py +++ b/workflow/scripts/build_scenarios.py @@ -178,8 +178,9 @@ def write_to_scenario_yaml(input, output, scenarios, df): df.loc[:, fallback_reference_scenario, :], planning_horizons ) - - if reference_scenario.startswith("KN2045plus"): # Still waiting for REMIND uploads + if reference_scenario.startswith( + "KN2045plus" + ): # Still waiting for REMIND uploads fallback_reference_scenario = reference_scenario co2_budget_source = config[scenario]["co2_budget_DE_source"] From b041ac68e8a07cf157a25d0f9bc15920ae6480f6 Mon Sep 17 00:00:00 2001 From: toniseibold Date: Mon, 2 Dec 2024 16:41:45 +0100 Subject: [PATCH 3/6] adding limit to three German zones --- config/config.yaml | 62 ++++++++++---------- workflow/scripts/additional_functionality.py | 42 +++++++------ 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index b14ff1d9..a15a73c8 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -62,7 +62,7 @@ scenario: ll: - vopt clusters: - - 27 #current options: 27, 49 + - 49 #current options: 27, 49 opts: - '' sector_opts: @@ -206,38 +206,38 @@ clustering: # print(fw.div(fw.sum()).subtract(5e-5).round(4).to_dict().__repr__().replace(",","\n")) focus_weights: # 27 nodes: 8 for Germany, 3 for Italy, 2 each for Denmark, UK and Spain, 1 per each of other 10 "Stromnachbarn" - 'DE': 0.2966 - 'AT': 0.0370 - 'BE': 0.0370 - 'CH': 0.0370 - 'CZ': 0.0370 - 'DK': 0.0741 - 'FR': 0.0370 - 'GB': 0.0741 - 'LU': 0.0370 - 'NL': 0.0370 - 'NO': 0.0370 - 'PL': 0.0370 - 'SE': 0.0370 - 'ES': 0.0741 - 'IT': 0.1111 + # 'DE': 0.2966 + # 'AT': 0.0370 + # 'BE': 0.0370 + # 'CH': 0.0370 + # 'CZ': 0.0370 + # 'DK': 0.0741 + # 'FR': 0.0370 + # 'GB': 0.0741 + # 'LU': 0.0370 + # 'NL': 0.0370 + # 'NO': 0.0370 + # 'PL': 0.0370 + # 'SE': 0.0370 + # 'ES': 0.0741 + # 'IT': 0.1111 # high spatial resolution: change clusters to 49 # 49 nodes: 30 for Germany, 3 for Italy, 2 each for Denmark, UK and Spain, 1 per each of other 10 "Stromnachbarn" - # 'DE': 0.6124 - # 'AT': 0.0204 - # 'BE': 0.0204 - # 'CH': 0.0204 - # 'CZ': 0.0204 - # 'DK': 0.0408 - # 'FR': 0.0204 - # 'GB': 0.0408 - # 'LU': 0.0204 - # 'NL': 0.0204 - # 'NO': 0.0204 - # 'PL': 0.0204 - # 'SE': 0.0204 - # 'ES': 0.0408 - # 'IT': 0.0612 + 'DE': 0.6124 + 'AT': 0.0204 + 'BE': 0.0204 + 'CH': 0.0204 + 'CZ': 0.0204 + 'DK': 0.0408 + 'FR': 0.0204 + 'GB': 0.0408 + 'LU': 0.0204 + 'NL': 0.0204 + 'NO': 0.0204 + 'PL': 0.0204 + 'SE': 0.0204 + 'ES': 0.0408 + 'IT': 0.0612 temporal: resolution_sector: 365H diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index d749d8c0..4b674438 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -668,6 +668,15 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): regions_onshore = gpd.read_file(snakemake.input.regions_onshore) regions_onshore.set_index("name", inplace=True) + de_regions_onshore = regions_onshore[regions_onshore.index.str.startswith("DE")] + de_regions_onshore["centroid_lat"] = de_regions_onshore.geometry.centroid.y + + # get index that centroid_lat is smaller < 50 + bins = [[], [], []] + bins[0] = de_regions_onshore[de_regions_onshore["centroid_lat"] < 50].index.to_list() + bins[1] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 50) & (de_regions_onshore["centroid_lat"] < 52)].index.to_list() + bins[2] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 52)].index.to_list() + regions_onshore = regions_onshore.to_crs(epsg=3035) # area in sqkm area = ( @@ -677,11 +686,14 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): mw_per_sqkm = 30 # source: https://www.ffe.de/wp-content/uploads/2022/02/FfE-Discussion-Paper-2-der-Landesflaeche-fuer-Windenergie-ein-geeignetes-Mass.pdf page 7 # % into fraction flaechenziel = onwind_constraint[investment_year] / 100 - limit = flaechenziel * area * mw_per_sqkm - for region in area.index: - valid_components = (n.generators.bus == region) & ( - n.generators.carrier == "onwind" + for entry in bins: + area_region = area[entry] + limit = flaechenziel * area_region.sum() * mw_per_sqkm + + valid_components = ( + (n.generators.bus.isin(entry)) + & (n.generators.carrier == "onwind") ) existing_index = n.generators.index[ @@ -691,28 +703,24 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): valid_components & n.generators.p_nom_extendable ] - if n.generators.loc[extendable_index[0], "p_nom_max"] < 10: - logger.warning( - f"Skipping onwind constraint for {region} as no extendable capacity exists" - ) + if n.generators.loc[extendable_index, "p_nom_max"].sum() < 10: + logger.warning(f"Skipping onwind constraint for region consisting of {entry} as no extendable capacity exists") continue elif existing_index.empty: - logger.info(f"No existing onwind capacity in {region}") + logger.info(f"No existing onwind capacity in region consisting of {entry}") existing_cap = 0 else: existing_cap = n.generators.loc[existing_index, "p_nom"].sum() - - lhs = n.model["Generator-p_nom"].loc[extendable_index] - rhs = limit[region] - existing_cap + + lhs = n.model["Generator-p_nom"].loc[extendable_index].sum() + rhs = limit - existing_cap if rhs <= 0: - logger.info( - f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit[region]/1000} GW in {region}." - ) + logger.info(f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit/1000} GW in {entry}.") continue - cname = f"flaechenziel_onwind-{region}" + cname = f"flaechenziel_onwind-{entry}" - logger.info(f"Adding Flaechenziel for {region} of {rhs/1000} GW.") + logger.info(f"Adding Flaechenziel for {entry} of {rhs/1000} GW.") n.model.add_constraints(lhs >= rhs, name=f"GlobalConstraint-{cname}") if cname in n.global_constraints.index: From 423b8a7163d169a2157270d185919a0c040217dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:43:42 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- workflow/scripts/additional_functionality.py | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 4b674438..f24dac9b 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -673,9 +673,16 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): # get index that centroid_lat is smaller < 50 bins = [[], [], []] - bins[0] = de_regions_onshore[de_regions_onshore["centroid_lat"] < 50].index.to_list() - bins[1] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 50) & (de_regions_onshore["centroid_lat"] < 52)].index.to_list() - bins[2] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 52)].index.to_list() + bins[0] = de_regions_onshore[ + de_regions_onshore["centroid_lat"] < 50 + ].index.to_list() + bins[1] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] >= 50) + & (de_regions_onshore["centroid_lat"] < 52) + ].index.to_list() + bins[2] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] >= 52) + ].index.to_list() regions_onshore = regions_onshore.to_crs(epsg=3035) # area in sqkm @@ -691,9 +698,8 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): area_region = area[entry] limit = flaechenziel * area_region.sum() * mw_per_sqkm - valid_components = ( - (n.generators.bus.isin(entry)) - & (n.generators.carrier == "onwind") + valid_components = (n.generators.bus.isin(entry)) & ( + n.generators.carrier == "onwind" ) existing_index = n.generators.index[ @@ -704,18 +710,22 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): ] if n.generators.loc[extendable_index, "p_nom_max"].sum() < 10: - logger.warning(f"Skipping onwind constraint for region consisting of {entry} as no extendable capacity exists") + logger.warning( + f"Skipping onwind constraint for region consisting of {entry} as no extendable capacity exists" + ) continue elif existing_index.empty: logger.info(f"No existing onwind capacity in region consisting of {entry}") existing_cap = 0 else: existing_cap = n.generators.loc[existing_index, "p_nom"].sum() - + lhs = n.model["Generator-p_nom"].loc[extendable_index].sum() rhs = limit - existing_cap if rhs <= 0: - logger.info(f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit/1000} GW in {entry}.") + logger.info( + f"Existing capacity {existing_cap/1000} GW fullfills the Flaechenziel of {limit/1000} GW in {entry}." + ) continue cname = f"flaechenziel_onwind-{entry}" From a59ae1976b5b0b02ce3d82ac882f80e5ebae41eb Mon Sep 17 00:00:00 2001 From: toniseibold Date: Mon, 2 Dec 2024 19:03:22 +0100 Subject: [PATCH 5/6] iterating regions in Germany --- workflow/scripts/additional_functionality.py | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index f24dac9b..9a4b86ca 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -670,19 +670,19 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): regions_onshore.set_index("name", inplace=True) de_regions_onshore = regions_onshore[regions_onshore.index.str.startswith("DE")] de_regions_onshore["centroid_lat"] = de_regions_onshore.geometry.centroid.y + de_regions_onshore["centroid_lon"] = de_regions_onshore.geometry.centroid.x # get index that centroid_lat is smaller < 50 - bins = [[], [], []] - bins[0] = de_regions_onshore[ - de_regions_onshore["centroid_lat"] < 50 - ].index.to_list() - bins[1] = de_regions_onshore[ - (de_regions_onshore["centroid_lat"] >= 50) - & (de_regions_onshore["centroid_lat"] < 52) - ].index.to_list() - bins[2] = de_regions_onshore[ - (de_regions_onshore["centroid_lat"] >= 52) - ].index.to_list() + bins = [[], [], [], [], []] + # south by + bins[0] = de_regions_onshore[(de_regions_onshore["centroid_lat"] < 50) & (de_regions_onshore["centroid_lon"] > 10)].index.to_list() + # bw + bins[1] = de_regions_onshore[(de_regions_onshore["centroid_lat"] < 49) & (de_regions_onshore["centroid_lon"] <= 10)].index.to_list() + # sl, he, rp, nrw + bins[2] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 49) & (de_regions_onshore["centroid_lat"] < 52) & (de_regions_onshore["centroid_lon"] <= 10)].index.to_list() + # north by, th, sa + bins[3] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 50) & (de_regions_onshore["centroid_lat"] < 52) & (de_regions_onshore["centroid_lon"] > 10)].index.to_list() + bins[4] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 52)].index.to_list() regions_onshore = regions_onshore.to_crs(epsg=3035) # area in sqkm @@ -695,6 +695,8 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): flaechenziel = onwind_constraint[investment_year] / 100 for entry in bins: + if not entry: + continue area_region = area[entry] limit = flaechenziel * area_region.sum() * mw_per_sqkm From 94fcbd2bfd12818ea0f5f170027f0f5d3692d82e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:03:36 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- workflow/scripts/additional_functionality.py | 26 ++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/workflow/scripts/additional_functionality.py b/workflow/scripts/additional_functionality.py index 9a4b86ca..d3f626f4 100644 --- a/workflow/scripts/additional_functionality.py +++ b/workflow/scripts/additional_functionality.py @@ -675,14 +675,30 @@ def add_onwind_constraint(n, investment_year, snakemake, onwind_constraint): # get index that centroid_lat is smaller < 50 bins = [[], [], [], [], []] # south by - bins[0] = de_regions_onshore[(de_regions_onshore["centroid_lat"] < 50) & (de_regions_onshore["centroid_lon"] > 10)].index.to_list() + bins[0] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] < 50) + & (de_regions_onshore["centroid_lon"] > 10) + ].index.to_list() # bw - bins[1] = de_regions_onshore[(de_regions_onshore["centroid_lat"] < 49) & (de_regions_onshore["centroid_lon"] <= 10)].index.to_list() + bins[1] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] < 49) + & (de_regions_onshore["centroid_lon"] <= 10) + ].index.to_list() # sl, he, rp, nrw - bins[2] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 49) & (de_regions_onshore["centroid_lat"] < 52) & (de_regions_onshore["centroid_lon"] <= 10)].index.to_list() + bins[2] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] >= 49) + & (de_regions_onshore["centroid_lat"] < 52) + & (de_regions_onshore["centroid_lon"] <= 10) + ].index.to_list() # north by, th, sa - bins[3] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 50) & (de_regions_onshore["centroid_lat"] < 52) & (de_regions_onshore["centroid_lon"] > 10)].index.to_list() - bins[4] = de_regions_onshore[(de_regions_onshore["centroid_lat"] >= 52)].index.to_list() + bins[3] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] >= 50) + & (de_regions_onshore["centroid_lat"] < 52) + & (de_regions_onshore["centroid_lon"] > 10) + ].index.to_list() + bins[4] = de_regions_onshore[ + (de_regions_onshore["centroid_lat"] >= 52) + ].index.to_list() regions_onshore = regions_onshore.to_crs(epsg=3035) # area in sqkm