def test_nonzero(): for shape, chunks in [(0, ()), ((0, 0), (0, 0)), ((15, 16), (4, 5))]: x = np.random.randint(10, size=shape) d = da.from_array(x, chunks=chunks) x_nz = np.nonzero(x) d_nz = da.nonzero(d) assert isinstance(d_nz, type(x_nz)) assert len(d_nz) == len(x_nz) for i in range(len(x_nz)): assert_eq(d_nz[i], x_nz[i])
def test_nonzero(): for shape, chunks in [(0, ()), ((0, 0), (0, 0)), ((15, 16), (4, 5))]: x = np.random.randint(10, size=shape) d = da.from_array(x, chunks=chunks) x_nz = np.nonzero(x) d_nz = da.nonzero(d) assert isinstance(d_nz, type(x_nz)) assert len(d_nz) == len(x_nz) for i in range(len(x_nz)): assert_eq(d_nz[i], x_nz[i])
def _get_high_intensity_peaks(image, mask, num_peaks): """ Helper function to return the num_peaks highest intensity peak coordinates. Adapted to dask from skimage.feature.peak._get_high_intensity_peaks """ # get coordinates of peaks coord = tuple([c.compute() for c in da.nonzero(mask)]) # sort by peak intensity intensities = image.vindex[coord].compute() idx_maxsort = np.argsort(intensities) coord = np.vstack(coord).T[idx_maxsort] # select num_peaks peaks if coord.shape[0] > num_peaks: coord = coord[-num_peaks:] # return highest peak first return coord[::-1]
def compute_capacity_factors(tech_points_dict: Dict[str, List[Tuple[float, float]]], spatial_res: float, timestamps: pd.DatetimeIndex, precision: int = 3, 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 precision: int (default: 3) Indicates at which decimal capacity factors should be rounded 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"]) # Round points at the given resolution non_rounded_points = tech_points_dict[tech] rounded_points = [(round(point[0] / spatial_res) * spatial_res, round(point[1] / spatial_res) * spatial_res) for point in non_rounded_points] non_rounded_to_rounded_dict = dict(zip(non_rounded_points, rounded_points)) sub_dataset = dataset.sel(locations=sorted(list(set(rounded_points)))) 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.]} list_df_per_wind_class = [] 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() # Convert rounded point back into non-rounded points power_output_df = pd.DataFrame(power_output, columns=coords_classes) coords_classes_rounded = [non_rounded_to_rounded_dict[point] for point in non_rounded_points] power_output_corrected = [power_output_df[point].values for point in coords_classes_rounded if point in power_output_df.columns] coords_classes_non_rounded = [point for point in non_rounded_to_rounded_dict if non_rounded_to_rounded_dict[point] in power_output_df.columns] tech_points_tuples = [(lon, lat) for lon, lat in coords_classes_non_rounded] df_per_wind_class = pd.DataFrame(np.array(power_output_corrected).T, index=timestamps, columns=tech_points_tuples) list_df_per_wind_class.append(df_per_wind_class) else: continue cap_factor_df_concat = pd.concat(list_df_per_wind_class, axis=1) cap_factor_df[tech] = cap_factor_df_concat.reindex(sorted(cap_factor_df_concat.columns), axis=1) elif resource == 'PV': converter = converters_dict[tech]["converter"] # Get irradiance in W from J 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) # Convert rounded point back into non rounded points power_output_df = pd.DataFrame(power_output, columns=sub_dataset.locations.values.tolist()) coords_classes_rounded = [non_rounded_to_rounded_dict[point] for point in non_rounded_points] power_output_corrected = [power_output_df[point].values for point in coords_classes_rounded if point in power_output_df.columns] cap_factor_df[tech] = np.array(power_output_corrected).T 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, "Some capacity factors are not available." # Decrease precision of capacity factors cap_factor_df = cap_factor_df.round(precision) return cap_factor_df