diff --git a/scripts/build_egs_potentials.py b/scripts/build_egs_potentials.py index 61feee92..4a66f416 100644 --- a/scripts/build_egs_potentials.py +++ b/scripts/build_egs_potentials.py @@ -3,7 +3,8 @@ # # SPDX-License-Identifier: MIT """ -This rule extracts potential and cost for electricity generation through enhanced geothermal systems +This rule extracts potential and cost for electricity generation through +enhanced geothermal systems. For this, we use data from "From hot rock to useful energy..." by Aghahosseini, Breyer (2020) 'https://www.sciencedirect.com/science/article/pii/S0306261920312551' @@ -20,30 +21,30 @@ import logging logger = logging.getLogger(__name__) import json -import pandas as pd -import geopandas as gpd +import geopandas as gpd +import pandas as pd from shapely.geometry import Polygon def prepare_egs_data(egs_file): - with open(egs_file) as f: jsondata = json.load(f) - def point_to_square(p, lon_extent=1., lat_extent=1.): - + def point_to_square(p, lon_extent=1.0, lat_extent=1.0): try: x, y = p.coords.xy[0][0], p.coords.xy[1][0] except IndexError: return p - - return Polygon([ - [x-lon_extent/2, y-lat_extent/2], - [x-lon_extent/2, y+lat_extent/2], - [x+lon_extent/2, y+lat_extent/2], - [x+lon_extent/2, y-lat_extent/2], - ]) + + return Polygon( + [ + [x - lon_extent / 2, y - lat_extent / 2], + [x - lon_extent / 2, y + lat_extent / 2], + [x + lon_extent / 2, y + lat_extent / 2], + [x + lon_extent / 2, y - lat_extent / 2], + ] + ) years = [2015, 2020, 2025, 2030, 2035, 2040, 2045, 2050] lcoes = ["LCOE50", "LCOE100", "LCOE150"] @@ -54,11 +55,12 @@ def prepare_egs_data(egs_file): df = pd.DataFrame(columns=["Lon", "Lat", "CAPEX", "HeatSust", "PowerSust"]) for lcoe in lcoes: - for country_data in jsondata[lcoe]: try: - country_df = pd.DataFrame(columns=df.columns, - index=range(len(country_data[0][years.index(year)]["Lon"]))) + country_df = pd.DataFrame( + columns=df.columns, + index=range(len(country_data[0][years.index(year)]["Lon"])), + ) except TypeError: country_df = pd.DataFrame(columns=df.columns, index=range(0)) @@ -68,17 +70,13 @@ def prepare_egs_data(egs_file): df = pd.concat((df, country_df.dropna()), axis=0, ignore_index=True) gdf = gpd.GeoDataFrame( - df.drop( - columns=["Lon", "Lat"] - ), - geometry=gpd.points_from_xy(df.Lon, df.Lat) - ).reset_index(drop=True) - + df.drop(columns=["Lon", "Lat"]), geometry=gpd.points_from_xy(df.Lon, df.Lat) + ).reset_index(drop=True) + gdf["geometry"] = gdf.geometry.apply(lambda geom: point_to_square(geom)) egs_data[year] = gdf - - return egs_data + return egs_data if __name__ == "__main__": @@ -90,43 +88,44 @@ if __name__ == "__main__": simpl="", clusters=37, ) - - sustainability_factor = 0.0025 # factor sustainable p_nom vs p_nom + + sustainability_factor = 0.0025 # factor sustainable p_nom vs p_nom config = snakemake.config egs_data = prepare_egs_data(snakemake.input.egs_cost) if config["sector"]["enhanced_geothermal_optimism"]: - egs_data = egs_data[(year := config["costs"]["year"])] - logger.info(f"EGS optimism! Builing EGS potentials with costs estimated for {year}.") + logger.info( + f"EGS optimism! Builing EGS potentials with costs estimated for {year}." + ) else: egs_data = egs_data[(default_year := 2020)] - logger.info(f"No EGS optimism! Building EGS potentials with {default_year} costs.") + logger.info( + f"No EGS optimism! Building EGS potentials with {default_year} costs." + ) egs_data.index = egs_data.geometry.astype(str) egs_shapes = egs_data.geometry - + network_shapes = ( gpd.read_file(snakemake.input.shapes) .set_index("name", drop=True) .set_crs(epsg=4326) ) - overlap_matrix = ( - pd.DataFrame( - index=network_shapes.index, - columns=(egs_shapes := egs_data.geometry).astype(str).values) + overlap_matrix = pd.DataFrame( + index=network_shapes.index, + columns=(egs_shapes := egs_data.geometry).astype(str).values, ) for name, polygon in network_shapes.geometry.items(): overlap_matrix.loc[name] = ( - egs_shapes - .intersection(polygon).area + egs_shapes.intersection(polygon).area ) / egs_shapes.area overlap_matrix.to_csv(snakemake.output["egs_overlap"]) - egs_data["p_nom_max"] = egs_data["PowerSust"] / sustainability_factor + egs_data["p_nom_max"] = egs_data["PowerSust"] / sustainability_factor egs_data[["p_nom_max", "CAPEX"]].to_csv(snakemake.output["egs_potentials"]) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index b1695f16..1660aae8 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -3304,7 +3304,7 @@ def add_enhanced_geothermal( overlap = pd.read_csv(egs_overlap, index_col=0) egs_potentials = pd.read_csv(egs_potentials, index_col=0) - + Nyears = n.snapshot_weightings.generators.sum() / 8760 dr = config["costs"]["fill_values"]["discount rate"] lt = costs.at["geothermal", "lifetime"] @@ -3312,9 +3312,7 @@ def add_enhanced_geothermal( egs_annuity = calculate_annuity(lt, dr) egs_potentials["capital_cost"] = ( - (egs_annuity + 0.02 / 1.02) * - egs_potentials["CAPEX"] * - Nyears + (egs_annuity + 0.02 / 1.02) * egs_potentials["CAPEX"] * Nyears ) # Uncommented for causing a crash for runs with default config. @@ -3352,15 +3350,15 @@ def add_enhanced_geothermal( if not bus_overlap.sum(): continue - overlap = bus_overlap.loc[bus_overlap > 0.] + overlap = bus_overlap.loc[bus_overlap > 0.0] - bus_egs = egs_potentials.loc[bus_overlap.loc[bus_overlap > 0.].index] + bus_egs = egs_potentials.loc[bus_overlap.loc[bus_overlap > 0.0].index] if not len(bus_egs): continue - + bus_egs["p_nom_max"] = bus_egs["p_nom_max"].multiply(bus_overlap) - bus_egs = bus_egs.loc[bus_egs.p_nom_max > 0.] + bus_egs = bus_egs.loc[bus_egs.p_nom_max > 0.0] if config["sector"]["enhanced_geothermal_best_only"]: bus_egs = bus_egs.sort_values(by="capital_cost").iloc[:1] @@ -3391,7 +3389,6 @@ def add_enhanced_geothermal( ) - if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -3567,7 +3564,6 @@ if __name__ == "__main__": if options.get("enhanced_geothermal"): logger.info("Adding Enhanced Geothermal Potential.") - """ add_enhanced_geothermal( n,