From 2563d1277a5daff685b50df9f1a7957f8f78f9e7 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Sun, 11 Jul 2021 17:52:32 +0200 Subject: [PATCH 01/10] spatially-explicit biomass potentials from ENSPRESO (NUTS2) --- Snakefile | 19 ++- config.default.yaml | 34 ++--- scripts/build_biomass_potentials.py | 193 ++++++++++++++++++++++------ scripts/prepare_sector_network.py | 11 +- 4 files changed, 186 insertions(+), 71 deletions(-) diff --git a/Snakefile b/Snakefile index b91785d9..286df421 100644 --- a/Snakefile +++ b/Snakefile @@ -1,4 +1,7 @@ +from snakemake.remote.HTTP import RemoteProvider as HTTPRemoteProvider +HTTP = HTTPRemoteProvider() + configfile: "config.yaml" @@ -170,13 +173,19 @@ rule build_energy_totals: rule build_biomass_potentials: input: - jrc_potentials="data/biomass/JRC Biomass Potentials.xlsx" + enspreso_biomass=HTTP.remote("https://cidportal.jrc.ec.europa.eu/ftp/jrc-opendata/ENSPRESO/ENSPRESO_BIOMASS.xlsx", keep_local=True), + nuts2="data/nuts/NUTS_RG_10M_2013_4326_LEVL_2.geojson", # https://gisco-services.ec.europa.eu/distribution/v2/nuts/download/#nuts21 + regions_onshore=pypsaeur("resources/regions_onshore_elec_s{simpl}_{clusters}.geojson"), + nuts3_population=pypsaeur("data/bundle/nama_10r_3popgdp.tsv.gz"), + swiss_cantons=pypsaeur("data/bundle/ch_cantons.csv"), + swiss_population=pypsaeur("data/bundle/je-e-21.03.02.xls"), + country_shapes=pypsaeur('resources/country_shapes.geojson') output: - biomass_potentials_all='resources/biomass_potentials_all.csv', - biomass_potentials='resources/biomass_potentials.csv' + biomass_potentials_all='resources/biomass_potentials_all_s{simpl}_{clusters}.csv', + biomass_potentials='resources/biomass_potentials_s{simpl}_{clusters}.csv' threads: 1 resources: mem_mb=1000 - benchmark: "benchmarks/build_biomass_potentials" + benchmark: "benchmarks/build_biomass_potentials_s{simpl}_{clusters}" script: 'scripts/build_biomass_potentials.py' @@ -323,7 +332,7 @@ rule prepare_sector_network: transport_name='resources/transport_data.csv', traffic_data_KFZ = "data/emobility/KFZ__count", traffic_data_Pkw = "data/emobility/Pkw__count", - biomass_potentials='resources/biomass_potentials.csv', + biomass_potentials='resources/biomass_potentials_s{simpl}_{clusters}.csv', heat_profile="data/heat_load_profile_BDEW.csv", costs=CDIR + "costs_{planning_horizons}.csv", profile_offwind_ac=pypsaeur("resources/profile_offwind-ac.nc"), diff --git a/config.default.yaml b/config.default.yaml index 457c3660..4161470e 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -99,28 +99,28 @@ energy: biomass: year: 2030 - scenario: Med + scenario: ENS_Med classes: solid biomass: - - Primary agricultural residues - - Forestry energy residue - - Secondary forestry residues - - Secondary Forestry residues sawdust - - Forestry residues from landscape care biomass + - Argicultural waste - Municipal waste + - Residues from landscape care + - Sawdust + - Secondary Forestry residues - woodchips not included: - - Bioethanol sugar beet biomass - - Rapeseeds for biodiesel - - sunflower and soya for Biodiesel - - Starchy crops biomass - - Grassy crops biomass - - Willow biomass - - Poplar biomass potential - - Roundwood fuelwood - - Roundwood Chips & Pellets + - Bioethanol barley, wheat, grain maize, oats, other cereals and rye + - Fuelwood residues + - C&P_RW + - FuelwoodRW + - Rape seed + - Sugar from sugar beet + - Miscanthus, switchgrass, RCG + - "Sunflower, soya seed " + - Poplar + - Willow biogas: - - Manure biomass potential - - Sludge biomass + - Manure solid, liquid + - Sludge solar_thermal: diff --git a/scripts/build_biomass_potentials.py b/scripts/build_biomass_potentials.py index f02c9093..59eb0051 100644 --- a/scripts/build_biomass_potentials.py +++ b/scripts/build_biomass_potentials.py @@ -1,55 +1,148 @@ import pandas as pd - -rename = {"UK" : "GB", "BH" : "BA"} +import geopandas as gpd -def build_biomass_potentials(): +def build_nuts_population_data(year=2013): - config = snakemake.config['biomass'] - year = config["year"] - scenario = config["scenario"] + pop = pd.read_csv( + snakemake.input.nuts3_population, + sep=r'\,| \t|\t', + engine='python', + na_values=[":"], + index_col=1 + )[str(year)] + + # only countries + pop.drop("EU28", inplace=True) - df = pd.read_excel(snakemake.input.jrc_potentials, - "Potentials (PJ)", - index_col=[0,1]) + # mapping from Cantons to NUTS3 + cantons = pd.read_csv(snakemake.input.swiss_cantons) + cantons = cantons.set_index(cantons.HASC.str[3:]).NUTS + cantons = cantons.str.pad(5, side='right', fillchar='0') - df.rename(columns={"Unnamed: 18": "Municipal waste"}, inplace=True) - df.drop(columns="Total", inplace=True) - df.replace("-", 0., inplace=True) + # get population by NUTS3 + swiss = pd.read_excel(snakemake.input.swiss_population, skiprows=3, index_col=0).loc["Residents in 1000"] + swiss = swiss.rename(cantons).filter(like="CH") - column = df.iloc[:,0] - countries = column.where(column.str.isalpha()).pad() - countries = [rename.get(ct, ct) for ct in countries] - countries_i = pd.Index(countries, name='country') - df.set_index(countries_i, append=True, inplace=True) + # aggregate also to higher order NUTS levels + swiss = [swiss.groupby(swiss.index.str[:i]).sum() for i in range(2, 6)] - df.drop(index='MS', level=0, inplace=True) + # merge Europe + Switzerland + pop = pd.DataFrame(pop.append(swiss), columns=["total"]) + + # add missing manually + pop["AL"] = 2893 + pop["BA"] = 3871 + pop["RS"] = 7210 + + pop["ct"] = pop.index.str[:2] + + return pop - # convert from PJ to MWh - df = df / 3.6 * 1e6 - df.to_csv(snakemake.output.biomass_potentials_all) +def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): + + glossary = pd.read_excel( + snakemake.input.enspreso_biomass, + sheet_name="Glossary", + usecols="B:D", + skiprows=1, + index_col=0 + ) + + df = pd.read_excel( + snakemake.input.enspreso_biomass, + sheet_name="ENER - NUTS2 BioCom E", + usecols="A:H" + ) - # solid biomass includes: - # Primary agricultural residues (MINBIOAGRW1), - # Forestry energy residue (MINBIOFRSF1), - # Secondary forestry residues (MINBIOWOOW1), - # Secondary Forestry residues – sawdust (MINBIOWOO1a)', - # Forestry residues from landscape care biomass (MINBIOFRSF1a), - # Municipal waste (MINBIOMUN1)', + df["group"] = df["E-Comm"].map(glossary.group) + df["commodity"] = df["E-Comm"].map(glossary.description) - # biogas includes: - # Manure biomass potential (MINBIOGAS1), - # Sludge biomass (MINBIOSLU1), + to_rename = { + "NUTS2 Potential available by Bio Commodity": "potential", + "NUST2": "NUTS2", + } + df.rename(columns=to_rename, inplace=True) + + # fill up with NUTS0 if NUTS2 is not given + df.NUTS2 = df.apply(lambda x: x.NUTS0 if x.NUTS2 == '-' else x.NUTS2, axis=1) - df = df.loc[year, scenario, :] + # convert PJ to TWh + df.potential /= 3.6 + df.Unit = "TWh/a" - grouper = {v: k for k, vv in config["classes"].items() for v in vv} - df = df.groupby(grouper, axis=1).sum() + dff = df.query("Year == @year and Scenario == @scenario") - df.index.name = "MWh/a" + bio = dff.groupby(["NUTS2", "commodity"]).potential.sum().unstack() + + # currently Serbia and Kosovo not split, so aggregate + bio.loc["RS"] += bio.loc["XK"] + bio.drop("XK", inplace=True) + + return bio - df.to_csv(snakemake.output.biomass_potentials) + +def disaggregate_nuts0(bio): + + pop = build_nuts_population_data() + + # get population in nuts2 + pop_nuts2 = pop.loc[pop.index.str.len() == 4] + by_country = pop_nuts2.total.groupby(pop_nuts2.ct).sum() + pop_nuts2["fraction"] = pop_nuts2.total / pop_nuts2.ct.map(by_country) + + # distribute nuts0 data to nuts2 by population + bio_nodal = bio.loc[pop_nuts2.ct] + bio_nodal.index = pop_nuts2.index + bio_nodal = bio_nodal.mul(pop_nuts2.fraction, axis=0) + + # update inplace + bio.update(bio_nodal) + + return bio + + +def build_nuts2_shapes(): + """ + - load NUTS2 geometries + - add RS, AL, BA country shapes (not covered in NUTS 2013) + - consistently name ME, MK + """ + + nuts2 = gpd.GeoDataFrame(gpd.read_file(snakemake.input.nuts2).set_index('id').geometry) + + countries = gpd.read_file(snakemake.input.country_shapes).set_index('name') + missing = countries.loc[["AL", "RS", "BA"]] + nuts2.rename(index={"ME00": "ME", "MK00": "MK"}, inplace=True) + + return nuts2.append(missing) + + +def area(gdf): + """Returns area of GeoDataFrame geometries in square kilometers.""" + return gdf.to_crs(epsg=3035).area.div(1e6) + + +def convert_nuts2_to_regions(bio_nuts2, regions): + + # calculate area of nuts2 regions + bio_nuts2["area_nuts2"] = area(bio_nuts2) + + overlay = gpd.overlay(regions, bio_nuts2) + + # calculate share of nuts2 area inside region + overlay["share"] = area(overlay) / overlay["area_nuts2"] + + # multiply all nuts2-level values with share of nuts2 inside region + adjust_cols = overlay.columns.difference({"name", "area_nuts2", "geometry", "share"}) + overlay[adjust_cols] = overlay[adjust_cols].multiply(overlay["share"], axis=0) + + bio_regions = overlay.groupby("name").sum() + + bio_regions.drop(["area_nuts2", "share"], axis=1, inplace=True) + + return bio_regions if __name__ == "__main__": @@ -57,12 +150,28 @@ if __name__ == "__main__": from helper import mock_snakemake snakemake = mock_snakemake('build_biomass_potentials') + config = snakemake.config['biomass'] + year = config["year"] + scenario = config["scenario"] - # This is a hack, to be replaced once snakemake is unicode-conform + enspreso = enspreso_biomass_potentials(year, scenario) - solid_biomass = snakemake.config['biomass']['classes']['solid biomass'] - if 'Secondary Forestry residues sawdust' in solid_biomass: - solid_biomass.remove('Secondary Forestry residues sawdust') - solid_biomass.append('Secondary Forestry residues – sawdust') + enspreso = disaggregate_nuts0(enspreso) - build_biomass_potentials() + nuts2 = build_nuts2_shapes() + + df_nuts2 = gpd.GeoDataFrame(nuts2.geometry).join(enspreso) + + regions = gpd.read_file(snakemake.input.regions_onshore) + + df = convert_nuts2_to_regions(df_nuts2, regions) + + df.to_csv(snakemake.output.biomass_potentials_all) + + grouper = {v: k for k, vv in config["classes"].items() for v in vv} + df = df.groupby(grouper, axis=1).sum() + + df *= 1e6 # TWh/a to MWh/a + df.index.name = "MWh/a" + + df.to_csv(snakemake.output.biomass_potentials) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 82e15e60..ebf2ee71 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1527,9 +1527,6 @@ def add_biomass(n, costs): print("adding biomass") - # biomass distributed at country level - i.e. transport within country allowed - countries = n.buses.country.dropna().unique() - biomass_potentials = pd.read_csv(snakemake.input.biomass_potentials, index_col=0) n.add("Carrier", "biogas") @@ -1552,18 +1549,18 @@ def add_biomass(n, costs): "EU biogas", bus="EU biogas", carrier="biogas", - e_nom=biomass_potentials.loc[countries, "biogas"].sum(), + e_nom=biomass_potentials["biogas"].sum(), marginal_cost=costs.at['biogas', 'fuel'], - e_initial=biomass_potentials.loc[countries, "biogas"].sum() + e_initial=biomass_potentials["biogas"].sum() ) n.add("Store", "EU solid biomass", bus="EU solid biomass", carrier="solid biomass", - e_nom=biomass_potentials.loc[countries, "solid biomass"].sum(), + e_nom=biomass_potentials["solid biomass"].sum(), marginal_cost=costs.at['solid biomass', 'fuel'], - e_initial=biomass_potentials.loc[countries, "solid biomass"].sum() + e_initial=biomass_potentials["solid biomass"].sum() ) n.add("Link", From ed3fec46641f2b4253bf1c40785321fda45c6cf8 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 10 Aug 2021 10:27:40 +0200 Subject: [PATCH 02/10] add data/nuts to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1401c0ad..10243def 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ gurobi.log /data/.nfs* /data/Industrial_Database.csv /data/retro/tabula-calculator-calcsetbuilding.csv +/data/nuts* *.org From 05c233242025971d7bc57a49c49d5296d6097da6 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 10 Aug 2021 10:27:54 +0200 Subject: [PATCH 03/10] fix syntax error in master --- scripts/prepare_sector_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index ebf2ee71..2a92b670 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1931,7 +1931,7 @@ def maybe_adjust_costs_and_potentials(n, opts): else: if attr == 'p_nom_max': comps = {"Generator", "Link", "StorageUnit"} - elif attr = 'e_nom_max': + elif attr == 'e_nom_max': comps = {"Store"} else: comps = {"Generator", "Link", "StorageUnit", "Store"} From bab51b0f54697c22c973ab0c5ee22b9edb05c63a Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 10 Aug 2021 10:28:22 +0200 Subject: [PATCH 04/10] fix read-in of pypsa-eur data --- Snakefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Snakefile b/Snakefile index 286df421..498cc7c9 100644 --- a/Snakefile +++ b/Snakefile @@ -24,7 +24,6 @@ subworkflow pypsaeur: snakefile: "../pypsa-eur/Snakefile" configfile: "../pypsa-eur/config.yaml" - rule all: input: SDIR + '/graphs/costs.pdf' @@ -176,9 +175,9 @@ rule build_biomass_potentials: enspreso_biomass=HTTP.remote("https://cidportal.jrc.ec.europa.eu/ftp/jrc-opendata/ENSPRESO/ENSPRESO_BIOMASS.xlsx", keep_local=True), nuts2="data/nuts/NUTS_RG_10M_2013_4326_LEVL_2.geojson", # https://gisco-services.ec.europa.eu/distribution/v2/nuts/download/#nuts21 regions_onshore=pypsaeur("resources/regions_onshore_elec_s{simpl}_{clusters}.geojson"), - nuts3_population=pypsaeur("data/bundle/nama_10r_3popgdp.tsv.gz"), - swiss_cantons=pypsaeur("data/bundle/ch_cantons.csv"), - swiss_population=pypsaeur("data/bundle/je-e-21.03.02.xls"), + nuts3_population="../pypsa-eur/data/bundle/nama_10r_3popgdp.tsv.gz", + swiss_cantons="../pypsa-eur/data/bundle/ch_cantons.csv", + swiss_population="../pypsa-eur/data/bundle/je-e-21.03.02.xls", country_shapes=pypsaeur('resources/country_shapes.geojson') output: biomass_potentials_all='resources/biomass_potentials_all_s{simpl}_{clusters}.csv', From 782323bee447338ef94053cd65f5aee3f9131aa6 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 10 Aug 2021 10:28:50 +0200 Subject: [PATCH 05/10] handle spaces in remote files --- scripts/build_biomass_potentials.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_biomass_potentials.py b/scripts/build_biomass_potentials.py index 59eb0051..cf5b0e6d 100644 --- a/scripts/build_biomass_potentials.py +++ b/scripts/build_biomass_potentials.py @@ -43,7 +43,7 @@ def build_nuts_population_data(year=2013): def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): glossary = pd.read_excel( - snakemake.input.enspreso_biomass, + str(snakemake.input.enspreso_biomass), sheet_name="Glossary", usecols="B:D", skiprows=1, @@ -51,7 +51,7 @@ def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): ) df = pd.read_excel( - snakemake.input.enspreso_biomass, + str(snakemake.input.enspreso_biomass), sheet_name="ENER - NUTS2 BioCom E", usecols="A:H" ) From e40461b1c046f1722fff4df81454c54c38d936a1 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 16 Aug 2021 13:19:20 +0200 Subject: [PATCH 06/10] fix typo in biomass config --- config.default.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 71613d9c..71c6b1e2 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -102,22 +102,22 @@ biomass: scenario: ENS_Med classes: solid biomass: - - Argicultural waste - - Municipal waste - - Residues from landscape care - - Sawdust - - Secondary Forestry residues - woodchips - not included: - - Bioethanol barley, wheat, grain maize, oats, other cereals and rye + - Agricultural waste - Fuelwood residues - - C&P_RW - - FuelwoodRW - - Rape seed + - Secondary Forestry residues - woodchips + - Sawdust + - Residues from landscape care + - Municipal waste + not included: - Sugar from sugar beet - - Miscanthus, switchgrass, RCG + - Rape seed - "Sunflower, soya seed " - - Poplar + - Bioethanol barley, wheat, grain maize, oats, other cereals and rye + - Miscanthus, switchgrass, RCG - Willow + - Poplar + - FuelwoodRW + - C&P_RW biogas: - Manure solid, liquid - Sludge From 99e602f7b25ea667b76ab0560c68c544840871de Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 16 Aug 2021 14:00:30 +0200 Subject: [PATCH 07/10] add ENSPRESO release notes and doc --- doc/data.csv | 1 + doc/release_notes.rst | 3 +++ doc/supply_demand.rst | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/data.csv b/doc/data.csv index 8e316281..26a5bea0 100644 --- a/doc/data.csv +++ b/doc/data.csv @@ -2,6 +2,7 @@ description,file/folder,licence,source JRC IDEES database,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees urban/rural fraction,urban_percent.csv,unknown,unknown JRC biomass potentials,biomass/,unknown,https://doi.org/10.2790/39014 +JRC ENSPRESO biomass potentials,remote,CC BY 4.0,https://data.jrc.ec.europa.eu/dataset/74ed5a04-7d74-4807-9eab-b94774309d9f EEA emission statistics,eea/UNFCCC_v23.csv,EEA standard re-use policy,https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16 Eurostat Energy Balances,eurostat-energy_balances-*/,Eurostat,https://ec.europa.eu/eurostat/web/energy/data/energy-balances Swiss energy statistics from Swiss Federal Office of Energy,switzerland-sfoe/,unknown,http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169 diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 15419438..eb57dce9 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -66,6 +66,9 @@ Future release * The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. * The transformation of the Steel and Aluminium production can be now defined for different years in the ``config.yaml`` file. * Include the option to alter the maximum energy capacity of a store via the ``carrier+factor`` in the ``{sector_opts}`` wildcard. This can be useful for sensitivity analyses. Example: ``co2 stored+e2`` multiplies the ``e_nom_max`` by factor 2. In this example, ``e_nom_max`` represents the CO2 sequestration potential in Europe. +* Use `JRC ENSPRESO database `_ to + spatially disaggregate biomass potentials to PyPSA-Eur regions based on overlaps with NUTS2 regions from ENSPRESO + (proportional to area) (`#151 `_). PyPSA-Eur-Sec 0.5.0 (21st May 2021) =================================== diff --git a/doc/supply_demand.rst b/doc/supply_demand.rst index 77317094..8e4f2130 100644 --- a/doc/supply_demand.rst +++ b/doc/supply_demand.rst @@ -183,7 +183,7 @@ Solid biomass provides process heat up to 500 Celsius in industry, as well as fe Solid biomass supply ===================== -Only wastes and residues from the JRC biomass dataset. +Only wastes and residues from the JRC ENSPRESO biomass dataset. Oil product demand From 0a16ca3b35435afa4cca4daa59fe481da6f54b32 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 16 Aug 2021 14:14:05 +0200 Subject: [PATCH 08/10] add biomass potentials docstrings --- scripts/build_biomass_potentials.py | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scripts/build_biomass_potentials.py b/scripts/build_biomass_potentials.py index cf5b0e6d..68d87808 100644 --- a/scripts/build_biomass_potentials.py +++ b/scripts/build_biomass_potentials.py @@ -41,7 +41,24 @@ def build_nuts_population_data(year=2013): def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): + """ + Loads the JRC ENSPRESO biomass potentials. + Parameters + ---------- + year : int + The year for which potentials are to be taken. + Can be {2010, 2020, 2030, 2040, 2050}. + scenario : str + The scenario. Can be {"ENS_Low", "ENS_Med", "ENS_High"}. + + Returns + ------- + pd.DataFrame + Biomass potentials for given year and scenario + in TWh/a by commodity and NUTS2 region. + """ + glossary = pd.read_excel( str(snakemake.input.enspreso_biomass), sheet_name="Glossary", @@ -84,6 +101,20 @@ def enspreso_biomass_potentials(year=2020, scenario="ENS_Low"): def disaggregate_nuts0(bio): + """ + Some commodities are only given on NUTS0 level. + These are disaggregated here using the NUTS2 + population as distribution key. + + Parameters + ---------- + bio : pd.DataFrame + from enspreso_biomass_potentials() + + Returns + ------- + pd.DataFrame + """ pop = build_nuts_population_data() @@ -125,6 +156,21 @@ def area(gdf): def convert_nuts2_to_regions(bio_nuts2, regions): + """ + Converts biomass potentials given in NUTS2 to PyPSA-Eur regions based on the + overlay of both GeoDataFrames in proportion to the area. + + Parameters + ---------- + bio_nuts2 : gpd.GeoDataFrame + JRC ENSPRESO biomass potentials indexed by NUTS2 shapes. + regions : gpd.GeoDataFrame + PyPSA-Eur clustered onshore regions + + Returns + ------- + gpd.GeoDataFrame + """ # calculate area of nuts2 regions bio_nuts2["area_nuts2"] = area(bio_nuts2) From 53eab1ead24aac20fe0e23653b2a54fd089dd0fb Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Tue, 28 Sep 2021 17:25:04 +0200 Subject: [PATCH 09/10] slice biomass potentials with the pop_layout index instead of the country if biomass transport = True --- scripts/prepare_sector_network.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 0b8518d4..81a60870 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1688,8 +1688,7 @@ def add_biomass(n, costs): if options["biomass_transport"]: # potential per node distributed within country by population - biomass_potentials_spatial = (biomass_potentials.loc[pop_layout.ct] - .set_index(pop_layout.index) + biomass_potentials_spatial = (biomass_potentials.loc[pop_layout.index] .mul(pop_layout.fraction, axis="index") .rename(index=lambda x: x + " solid biomass")) else: @@ -2206,7 +2205,7 @@ if __name__ == "__main__": lv=1.0, opts='', sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', - planning_horizons=2030, + planning_horizons="2030", ) logging.basicConfig(level=snakemake.config['logging_level']) From 1e248b314dcc481e4a668265e36d410704224d17 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Wed, 29 Sep 2021 15:45:14 +0200 Subject: [PATCH 10/10] compatibility with biomass transport --- scripts/prepare_sector_network.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 81a60870..5f4b680e 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1687,10 +1687,7 @@ def add_biomass(n, costs): biomass_potentials = pd.read_csv(snakemake.input.biomass_potentials, index_col=0) if options["biomass_transport"]: - # potential per node distributed within country by population - biomass_potentials_spatial = (biomass_potentials.loc[pop_layout.index] - .mul(pop_layout.fraction, axis="index") - .rename(index=lambda x: x + " solid biomass")) + biomass_potentials_spatial = biomass_potentials.rename(index=lambda x: x + " solid biomass") else: biomass_potentials_spatial = biomass_potentials.sum()