def get_legacy_capacity_in_countries(tech: str, countries: List[str], raise_error: bool = True) -> pd.Series: """ Return the total existing capacity (in GW) for the given tech for a set of countries. If there is not data for a certain country, returns a capacity of 0. Parameters ---------- tech: str Name of technology for which we want to retrieve legacy data. countries: List[str] List of ISO codes of countries raise_error: bool (default: True) Whether to raise an error if no legacy data is available for this technology. Returns ------- capacities: pd.Series Legacy capacities (in GW) of technology 'tech' for each country. """ assert len(countries) != 0, "Error: List of countries is empty." # Read per grid cell capacity file legacy_dir = f"{data_path}/generation/vres/legacy/generated/" capacities_df = pd.read_csv(f"{legacy_dir}aggregated_capacity.csv", index_col=[0, 1]) plant, plant_type = get_config_values(tech, ["plant", "type"]) available_plant_types = set(capacities_df.index) if (plant, plant_type) not in available_plant_types: if raise_error: raise ValueError( f"Error: no legacy data exists for tech {tech} with plant {plant} and type {plant_type}." ) else: warnings.warn(f"Warning: No legacy data exists for tech {tech}.") return pd.Series(0., name="Legacy capacity (GW)", index=countries, dtype=float) # Get only capacity for the desired technology and aggregated per country capacities_df = capacities_df.loc[(plant, plant_type), ("ISO2", "Capacity (GW)")] capacities_ds = capacities_df.groupby("ISO2").sum().squeeze() capacities_ds = capacities_ds.reindex(countries).fillna(0.) capacities_ds.name = "Legacy capacity (GW)" return capacities_ds
def plot_diff(tech: str, show: bool = True): plant, plant_type = get_config_values(tech, ["plant", "type"]) capacities_df = pd.read_csv( f"{data_path}generation/vres/legacy/generated/aggregated_capacity.csv", index_col=[0, 1]).loc[plant].loc[plant_type] capacities_df = capacities_df[capacities_df["ISO2"] != 'IS'] capacities_df = capacities_df[capacities_df["Capacity (GW)"] != 0.0] capacities_df_h = pd.read_csv( f"{data_path}generation/vres/legacy/generated/aggregated_capacity_harmonized.csv", index_col=[0, 1]).loc[plant].loc[plant_type] capacities_df_h = capacities_df_h[capacities_df_h["ISO2"] != 'IS'] capacities_df_h = capacities_df_h[capacities_df_h["Capacity (GW)"] != 0.0] capacities_df["Difference (GW)"] = capacities_df[ "Capacity (GW)"] - capacities_df_h["Capacity (GW)"] land_50m = cf.NaturalEarthFeature('physical', 'land', '50m', edgecolor='darkgrey', facecolor=cf.COLORS['land_alt1']) fig = plt.figure(figsize=(13, 13)) ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) ax.add_feature(land_50m, linewidth=0.5, zorder=-1) ax.add_feature(cf.BORDERS.with_scale('50m'), edgecolor='darkgrey', linewidth=0.5, zorder=-1) ax.set_extent([-15, 42.5, 30, 72.5]) map = ax.scatter(capacities_df["Longitude"], capacities_df["Latitude"], c=capacities_df["Difference (GW)"], s=1, vmax=1.2, vmin=0.0) fig.colorbar(map) if show: plt.show() else: return ax
def build_data(self, use_ex_cap: bool, min_cap_pot: List[float] = None, compute_load: bool = True, regions_shapes: pd.DataFrame = None): """Preprocess data. Parameters: ----------- use_ex_cap: bool Whether to compute or not existing capacity and use it in optimization. min_cap_pot: List[float] (default: None) List of thresholds per technology. Points with capacity potential under this threshold will be removed. """ # TODO: this function needs to take as argument a vector data specifying which data it must compute # Compute total load (in GWh) for each region load_df = pd.DataFrame(0., index=self.timestamps, columns=self.regions) if compute_load: load_df = get_load(timestamps=self.timestamps, regions=self.regions, missing_data='interpolate') # Get shape of regions and list of subregions onshore_technologies = [ get_config_values(tech, ["onshore"]) for tech in self.technologies ] if regions_shapes is None: regions_shapes = pd.DataFrame(columns=["onshore", "offshore"], index=self.regions) all_subregions = [] for region in self.regions: subregions = get_subregions(region) all_subregions.extend(subregions) shapes = get_shapes(subregions, save=True) if any(onshore_technologies): regions_shapes.loc[region, "onshore"] = unary_union( shapes[~shapes['offshore']]['geometry']) if not all(onshore_technologies): regions_shapes.loc[region, "offshore"] = unary_union( shapes[shapes['offshore']]['geometry']) else: all_subregions = self.regions # Divide the union of all regions shapes into grid cells of a given spatial resolution # TODO: this is shitty because you cannot add different technologies in separate regions grid_cells_ds = get_grid_cells(self.technologies, self.spatial_res, regions_shapes["onshore"].dropna(), regions_shapes["offshore"].dropna()) # Compute capacities potential tech_config = get_config_dict(self.technologies, ['filters', 'power_density']) cap_potential_ds = pd.Series(index=grid_cells_ds.index) for tech in self.technologies: cap_potential_ds[tech] = \ get_capacity_potential_for_shapes(grid_cells_ds[tech].values, tech_config[tech]["filters"], tech_config[tech]["power_density"]) # Compute legacy capacity existing_cap_ds = pd.Series(0., index=cap_potential_ds.index) if use_ex_cap: for tech in self.technologies: tech_existing_cap_ds = \ get_legacy_capacity_in_regions(tech, grid_cells_ds.loc[tech].reset_index(drop=True), all_subregions, raise_error=False) existing_cap_ds[tech] = tech_existing_cap_ds.values # Update capacity potential if existing capacity is bigger underestimated_capacity_indexes = existing_cap_ds > cap_potential_ds cap_potential_ds[underestimated_capacity_indexes] = existing_cap_ds[ underestimated_capacity_indexes] # Remove sites that have a potential capacity under the desired value or equal to 0 if min_cap_pot is None: min_cap_pot = [0] * len(self.technologies) assert len(min_cap_pot) == len(self.technologies), \ "Error: If you specify threshold on capacity potentials, you need to specify it for each technology." min_cap_pot_dict = dict(zip(self.technologies, min_cap_pot)) sites_to_drop = pd.DataFrame(cap_potential_ds).apply( lambda x: x[0] < min_cap_pot_dict[x.name[0]] or x[0] == 0, axis=1) # Don't drop sites with existing capacity # TODO: this is probably a shitty way to do it sites_to_drop = pd.DataFrame(sites_to_drop).apply( lambda x: (existing_cap_ds[x.name] == 0 and x[0]), axis=1) cap_potential_ds = cap_potential_ds[~sites_to_drop] existing_cap_ds = existing_cap_ds[~sites_to_drop] grid_cells_ds = grid_cells_ds[~sites_to_drop] # Compute capacity factors for each site tech_points_dict = {} techs = set(grid_cells_ds.index.get_level_values(0)) for tech in techs: tech_points_dict[tech] = list(grid_cells_ds[tech].index) cap_factor_df = compute_capacity_factors(tech_points_dict, self.spatial_res, self.timestamps) # Associating coordinates to regions tech_points_regions_ds = pd.Series(index=grid_cells_ds.index) sites_index = tech_points_regions_ds.index for tech in set(sites_index.get_level_values(0)): on_off = 'onshore' if get_config_values( tech, ['onshore']) else 'offshore' tech_sites_index = sites_index[sites_index.get_level_values(0) == tech] points = list( zip(tech_sites_index.get_level_values(1), tech_sites_index.get_level_values(2))) tech_points_regions_ds[tech] = match_points_to_regions( points, regions_shapes[on_off].dropna()).values cap_credit_ds = compute_capacity_credit_from_potential( load_df, cap_factor_df, tech_points_regions_ds) # Save all data in object self.use_ex_cap = use_ex_cap self.min_cap_pot_dict = min_cap_pot_dict self.tech_points_tuples = grid_cells_ds.index.values self.tech_points_dict = tech_points_dict self.initial_sites_ds = grid_cells_ds self.tech_points_regions_ds = tech_points_regions_ds self.data_dict["load"] = load_df self.data_dict["cap_potential_ds"] = cap_potential_ds.round(3) self.data_dict["existing_cap_ds"] = existing_cap_ds.round(3) self.data_dict["cap_factor_df"] = cap_factor_df.round(3) self.data_dict["capacity_credit_ds"] = cap_credit_ds.round(3)
def aggregate_legacy_capacity(spatial_resolution: float): """ Aggregate legacy data at a given spatial resolution. Parameters ---------- spatial_resolution: float Spatial resolution at which we want to aggregate. """ countries = [ "AL", "AT", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FO", "FR", "GB", "GR", "HR", "HU", "IE", "IS", "IT", "LT", "LU", "LV", "ME", "MK", "NL", "NO", "PL", "PT", "RO", "RS", "SE", "SI", "SK", "UA" ] technologies = [ "wind_onshore", "wind_offshore", "pv_utility", "pv_residential" ] capacities_df_ls = [] for country in countries: print(f"Country: {country}") shapes = get_shapes([country]) onshore_shape = shapes[~shapes["offshore"]]["geometry"].values[0] offshore_shape = shapes[shapes["offshore"]]["geometry"].values # If not offshore shape for country, remove offshore technologies from set offshore_shape = None if len( offshore_shape) == 0 else offshore_shape[0] technologies_in_country = technologies if offshore_shape is None: technologies_in_country = [ tech for tech in technologies if get_config_values(tech, ['onshore']) ] # Divide shapes into grid cells grid_cells_ds = get_grid_cells(technologies_in_country, spatial_resolution, onshore_shape, offshore_shape) technologies_in_country = set(grid_cells_ds.index.get_level_values(0)) # Get capacity in each grid cell capacities_per_country_ds = pd.Series(index=grid_cells_ds.index, name="Capacity (GW)") for tech in technologies_in_country: capacities_per_country_ds[tech] = \ get_legacy_capacity_in_regions_from_non_open(tech, grid_cells_ds.loc[tech].reset_index()[0], [country], match_distance=100) capacities_per_country_df = capacities_per_country_ds.to_frame() capacities_per_country_df.loc[:, "ISO2"] = country capacities_df_ls += [capacities_per_country_df] # Aggregate dataframe from each country capacities_df = pd.concat(capacities_df_ls).sort_index() # Replace technology name by plant and type tech_to_plant_type = { tech: get_config_values(tech, ["plant", "type"]) for tech in technologies } capacities_df = capacities_df.reset_index() capacities_df["Plant"] = capacities_df["Technology Name"].apply( lambda x: tech_to_plant_type[x][0]) capacities_df["Type"] = capacities_df["Technology Name"].apply( lambda x: tech_to_plant_type[x][1]) capacities_df = capacities_df.drop("Technology Name", axis=1) capacities_df = capacities_df.set_index( ["Plant", "Type", "Longitude", "Latitude"]) legacy_dir = f"{data_path}generation/vres/legacy/generated/" capacities_df.round(4).to_csv(f"{legacy_dir}aggregated_capacity.csv", header=True, columns=["ISO2", "Capacity (GW)"])
def get_legacy_capacity_in_regions_from_non_open( tech: str, regions_shapes: pd.Series, countries: List[str], match_distance: float = 50., raise_error: bool = True) -> pd.Series: """ Return the total existing capacity (in GW) for the given tech for a set of geographical regions. This function is using proprietary data. Parameters ---------- tech: str Technology name. regions_shapes: pd.Series [Union[Polygon, MultiPolygon]] Geographical regions countries: List[str] List of ISO codes of countries in which the regions are situated match_distance: float (default: 50) Distance threshold (in km) used when associating points to shape. raise_error: bool (default: True) Whether to raise an error if no legacy data is available for this technology. Returns ------- capacities: pd.Series Legacy capacities (in GW) of technology 'tech' for each region """ path_legacy_data = f"{data_path}generation/vres/legacy/source/" capacities = pd.Series(0., index=regions_shapes.index) plant, plant_type = get_config_values(tech, ["plant", "type"]) if (plant, plant_type) in [("Wind", "Onshore"), ("Wind", "Offshore"), ("PV", "Utility")]: if plant == "Wind": data = pd.read_excel( f"{path_legacy_data}Windfarms_Europe_20200127.xls", sheet_name='Windfarms', header=0, usecols=[2, 5, 9, 10, 18, 23], skiprows=[1], na_values='#ND') data = data.dropna(subset=['Latitude', 'Longitude', 'Total power']) data = data[data['Status'] != 'Dismantled'] if countries is not None: data = data[data['ISO code'].isin(countries)] if len(data) == 0: return capacities # Converting from kW to GW data['Total power'] *= 1e-6 data["Location"] = data[["Longitude", "Latitude" ]].apply(lambda x: (x.Longitude, x.Latitude), axis=1) # Keep only onshore or offshore point depending on technology if plant_type == 'Onshore': data = data[data['Area'] != 'Offshore'] else: # Offshore data = data[data['Area'] == 'Offshore'] if len(data) == 0: return capacities else: # plant == "PV": data = pd.read_excel( f"{path_legacy_data}Solarfarms_Europe_20200208.xlsx", sheet_name='ProjReg_rpt', header=0, usecols=[0, 4, 8]) data = data[pd.notnull(data['Coords'])] data["Location"] = data["Coords"].apply( lambda x: (float(x.split(',')[1]), float(x.split(',')[0]))) if countries is not None: data['Country'] = convert_country_codes( data['Country'].values, 'name', 'alpha_2') data = data[data['Country'].isin(countries)] if len(data) == 0: return capacities # Converting from MW to GW data['Total power'] = data['MWac'] * 1e-3 data = data[["Location", "Total power"]] points_region = match_points_to_regions( data["Location"].values, regions_shapes, distance_threshold=match_distance).dropna() for region in regions_shapes.index: points_in_region = points_region[points_region == region].index.values capacities[region] = data[data["Location"].isin( points_in_region)]["Total power"].sum() elif (plant, plant_type) == ("PV", "Residential"): legacy_capacity_fn = join(path_legacy_data, 'SolarEurope_Residential_deployment.xlsx') data = pd.read_excel(legacy_capacity_fn, header=0, index_col=0, usecols=[0, 4], squeeze=True).sort_index() data = data[data.index.isin(countries)] if len(data) == 0: return capacities # Get countries shapes countries_shapes = get_shapes(data.index.values, which='onshore', save=True)["geometry"] for region_id, region_shape in regions_shapes.items(): for country_id, country_shape in countries_shapes.items(): capacities[region_id] += \ (region_shape.intersection(country_shape).area/country_shape.area) * data[country_id] else: if raise_error: raise ValueError( f"Error: No legacy data exists for tech {tech} with plant {plant} and type {plant_type}." ) else: warnings.warn(f"Warning: No legacy data exists for tech {tech}.") return capacities
def get_legacy_capacity_in_regions(tech: str, regions_shapes: pd.Series, countries: List[str], match_distance: float = 50., raise_error: bool = True) -> pd.Series: """ Return the total existing capacity (in GW) for the given tech for a set of geographical regions. Parameters ---------- tech: str Technology name. regions_shapes: pd.Series [Union[Polygon, MultiPolygon]] Geographical regions countries: List[str] List of ISO codes of countries in which the regions are situated. match_distance: float (default: 50) Distance threshold (in km) used when associating points to shape. raise_error: bool (default: True) Whether to raise an error if no legacy data is available for this technology. Returns ------- capacities: pd.Series Legacy capacities (in GW) of technology 'tech' for each region """ # Read per grid cell capacity file legacy_dir = f"{data_path}generation/vres/legacy/generated/" capacities_df = pd.read_csv(f"{legacy_dir}aggregated_capacity.csv", index_col=[0, 1]) plant, plant_type = get_config_values(tech, ["plant", "type"]) available_plant_types = set(capacities_df.index) if (plant, plant_type) not in available_plant_types: if raise_error: raise ValueError( f"Error: no legacy data exists for tech {tech} with plant {plant} and type {plant_type}." ) else: warnings.warn(f"Warning: No legacy data exists for tech {tech}.") return pd.Series(0., name="Legacy capacity (GW)", index=regions_shapes.index, dtype=float) # Get only capacity for the desired technology and desired countries capacities_df = capacities_df.loc[(plant, plant_type)] capacities_df = capacities_df[capacities_df.ISO2.isin(countries)] if len(capacities_df) == 0: return pd.Series(0., name="Legacy capacity (GW)", index=regions_shapes.index, dtype=float) # Aggregate capacity per region by adding capacity of points falling in those regions capacities_df["Location"] = capacities_df[["Longitude", "Latitude"]].apply(lambda x: (x[0], x[1]), axis=1) points_region = match_points_to_regions( capacities_df["Location"].values, regions_shapes, distance_threshold=match_distance).dropna() capacities_ds = pd.Series(0., name="Legacy capacity (GW)", index=regions_shapes.index, dtype=float) for region in regions_shapes.index: points_in_region = points_region[points_region == region].index.values capacities_ds[region] = capacities_df[capacities_df["Location"].isin( points_in_region)]["Capacity (GW)"].sum() return capacities_ds
def compute_capacity_factors(tech_points_dict: Dict[str, List[Tuple[float, float]]], spatial_res: float, timestamps: pd.DatetimeIndex, smooth_wind_power_curve: bool = True) -> pd.DataFrame: """ Compute capacity factors for a list of points associated to a list of technologies. Parameters ---------- tech_points_dict : Dict[str, List[Tuple[float, float]]] Dictionary associating to each tech a list of points. spatial_res: float Spatial resolution of coordinates timestamps: pd.DatetimeIndex Time stamps for which we want capacity factors smooth_wind_power_curve : boolean (default True) If "True", the transfer function of wind assets replicates the one of a wind farm, rather than one of a wind turbine. Returns ------- cap_factor_df : pd.DataFrame DataFrame storing capacity factors for each technology and each point """ for tech, points in tech_points_dict.items(): assert len(points) != 0, f"Error: No points were defined for tech {tech}" assert len(timestamps) != 0, f"Error: No timestamps were defined." # Get the converters corresponding to the input technologies # Dictionary indicating for each technology which converter(s) to use. # For each technology in the dictionary: # - if it is pv-based, the name of the converter must be specified as a string # - if it is wind, a dictionary must be defined associated for the four wind regimes # defined below (I, II, III, IV), the name of the converter as a string converters_dict = get_config_dict(list(tech_points_dict.keys()), ["converter"]) vres_profiles_dir = f"{data_path}generation/vres/profiles/source/" transfer_function_dir = f"{vres_profiles_dir}transfer_functions/" data_converter_wind = pd.read_csv(f"{transfer_function_dir}data_wind_turbines.csv", sep=';', index_col=0) data_converter_pv = pd.read_csv(f"{transfer_function_dir}data_pv_modules.csv", sep=';', index_col=0) dataset = read_resource_database(spatial_res).sel(time=timestamps) # Create output dataframe with MultiIndex (tech, coords) tech_points_tuples = sorted([(tech, point[0], point[1]) for tech, points in tech_points_dict.items() for point in points]) cap_factor_df = pd.DataFrame(index=timestamps, columns=pd.MultiIndex.from_tuples(tech_points_tuples, names=['technologies', 'lon', 'lat']), dtype=float) for tech in tech_points_dict.keys(): resource = get_config_values(tech, ["plant"]) sub_dataset = dataset.sel(locations=sorted(tech_points_dict[tech])) if resource == 'Wind': wind_speed_reference_height = 100. roughness = sub_dataset.fsr # Compute wind speed for the all the coordinates wind = xu.sqrt(sub_dataset.u100 ** 2 + sub_dataset.v100 ** 2) wind_mean = wind.mean(dim='time') # Split according to the IEC 61400 WTG classes wind_classes = {'IV': [0., 6.5], 'III': [6.5, 8.], 'II': [8., 9.5], 'I': [9.5, 99.]} for cls in wind_classes: filtered_wind_data = wind_mean.where((wind_mean.data >= wind_classes[cls][0]) & (wind_mean.data < wind_classes[cls][1]), 0) coords_classes = filtered_wind_data[da.nonzero(filtered_wind_data)].locations.values.tolist() if len(coords_classes) > 0: wind_filtered = wind.sel(locations=coords_classes) roughness_filtered = roughness.sel(locations=coords_classes) # Get the transfer function curve # literal_eval converts a string to an array (in this case) converter = converters_dict[tech]["converter"][cls] power_curve_array = literal_eval(data_converter_wind.loc['Power curve', converter]) wind_speed_references = np.asarray([i[0] for i in power_curve_array]) capacity_factor_references = np.asarray([i[1] for i in power_curve_array]) capacity_factor_references_pu = capacity_factor_references / max(capacity_factor_references) wind_log = windpowerlib.wind_speed.logarithmic_profile( wind_filtered.values, wind_speed_reference_height, float(data_converter_wind.loc['Hub height [m]', converter]), roughness_filtered.values) wind_data = da.from_array(wind_log, chunks='auto', asarray=True) # The transfer function of wind assets replicates the one of a # wind farm rather than one of a wind turbine. if smooth_wind_power_curve: turbulence_intensity = wind_filtered.std(dim='time') / wind_filtered.mean(dim='time') capacity_factor_farm = windpowerlib.power_curves.smooth_power_curve( pd.Series(wind_speed_references), pd.Series(capacity_factor_references_pu), standard_deviation_method='turbulence_intensity', turbulence_intensity=float(turbulence_intensity.min().values), wind_speed_range=10.0) power_output = da.map_blocks(np.interp, wind_data, capacity_factor_farm['wind_speed'].values, capacity_factor_farm['value'].values).compute() else: power_output = da.map_blocks(np.interp, wind_data, wind_speed_references, capacity_factor_references_pu).compute() tech_points_tuples = [(tech, lon, lat) for lon, lat in coords_classes] cap_factor_df.loc[:, tech_points_tuples] = np.array(power_output) else: continue elif resource == 'PV': converter = converters_dict[tech]["converter"] # Get irradiance in W from J # TODO: getting NANs here... and not always the same number irradiance = sub_dataset.ssrd / 3600. # Get temperature in C from K temperature = sub_dataset.t2m - 273.15 # Homer equation here: # https://www.homerenergy.com/products/pro/docs/latest/how_homer_calculates_the_pv_array_power_output.html # https://enphase.com/sites/default/files/Enphase_PVWatts_Derate_Guide_ModSolar_06-2014.pdf power_output = (float(data_converter_pv.loc['f', converter]) * (irradiance/float(data_converter_pv.loc['G_ref', converter])) * (1. + float(data_converter_pv.loc['k_P [%/C]', converter])/100. * (temperature - float(data_converter_pv.loc['t_ref', converter])))) power_output = np.array(power_output) cap_factor_df[tech] = power_output else: raise ValueError(' Profiles for the specified resource is not available yet.') # Check that we do not have NANs assert cap_factor_df.isna().to_numpy().sum() == 0, "Error: Some capacity factors are not available." # Decrease precision of capacity factors cap_factor_df = cap_factor_df.round(3) return cap_factor_df
def get_cap_factor_for_countries(tech: str, countries: List[str], timestamps: pd.DatetimeIndex, throw_error: bool = True) -> pd.DataFrame: """ Return capacity factors time-series for a set of countries over a given timestamps, for a given technology. Parameters ---------- tech: str One of the technology associated to plant 'PV' or 'Wind' (with type 'Onshore', 'Offshore' or 'Floating'). countries: List[str] List of ISO codes of countries. timestamps: pd.DatetimeIndex List of time stamps. throw_error: bool (default True) Whether to throw an error when capacity factors are not available for a given country or compute capacity factors from another method. Returns ------- pd.DataFrame Capacity factors dataframe indexed by timestamps and with columns corresponding to countries. """ plant, plant_type = get_config_values(tech, ["plant", "type"]) profiles_dir = f"{data_path}generation/vres/profiles/generated/" if plant == 'PV': capacity_factors_df = pd.read_csv(f"{profiles_dir}pv_cap_factors.csv", index_col=0) elif plant == "Wind" and plant_type == "Onshore": capacity_factors_df = pd.read_csv(f"{profiles_dir}onshore_wind_cap_factors.csv", index_col=0) elif plant == "Wind" and plant_type in ["Offshore", "Floating"]: capacity_factors_df = pd.read_csv(f"{profiles_dir}offshore_wind_cap_factors.csv", index_col=0) else: raise ValueError(f"Error: No capacity factors for technology {tech} of plant {plant} and type {type}.") capacity_factors_df.index = pd.DatetimeIndex(capacity_factors_df.index) # Slicing on time missing_timestamps = set(timestamps) - set(capacity_factors_df.index) assert not missing_timestamps, f"Error: {tech} data for timestamps {missing_timestamps} is not available." capacity_factors_df = capacity_factors_df.loc[timestamps] # Slicing on country missing_countries = set(countries) - set(capacity_factors_df.columns) if missing_countries: if throw_error: raise ValueError(f"Error: {tech} data for countries {missing_countries} is not available.") else: # Compute capacity factors from centroid of country (onshore/offshore) shape spatial_res = 0.5 missing_countries = sorted(list(missing_countries)) which = 'onshore' if get_config_values(tech, ["onshore"]) else 'offshore' shapes_df = get_shapes(missing_countries, which=which) centroids = shapes_df["geometry"].centroid points = [(round(p.x / spatial_res) * spatial_res, round(p.y / spatial_res) * spatial_res) for p in centroids] cap_factor_df = compute_capacity_factors({tech: points}, spatial_res, timestamps)[tech] cap_factor_df.columns = missing_countries capacity_factors_df = pd.concat([capacity_factors_df, cap_factor_df], axis=1) return capacity_factors_df[countries].round(3)
power_density: float Power density in MW/km2 processes: int (default: None) Number of parallel processes Returns ------- pd.Series Series containing the capacity potentials (GW) for each code. """ which = 'onshore' if is_onshore else 'offshore' shapes = get_shapes(countries, which=which, save=True)["geometry"] land_availability = get_land_availability_for_shapes( shapes, filters, processes) return pd.Series(land_availability * power_density / 1e3, index=shapes.index) if __name__ == '__main__': from iepy.geographics import get_shapes from iepy.technologies import get_config_values filters_ = get_config_values("wind_onshore_national", ["filters"]) print(filters_) # filters_ = {"depth_thresholds": {"high": -200, "low": None}} full_gl_shape = get_shapes(["DE"], "onshore")["geometry"][0] filters_ = {"glaes_priors": {"": (None, 500)}} # trunc_gl_shape = full_gl_shape.intersection(Polygon([(11.5, 52.5), (11.5, 53.5), (12.5, 53.5), (12.5, 52.5)])) print(get_capacity_potential_for_shapes([full_gl_shape], filters_, 5))