def test_WaspGridSiteDistanceClass(site): wgs = WaspGridSite( site._ds, distance=TerrainFollowingDistance(distance_resolution=2000)) assert wgs.distance.distance_resolution == 2000 assert wgs.distance.__call__.__func__ == TerrainFollowingDistance( ).__call__.__func__ wgs = WaspGridSite(site._ds, distance=StraightDistance()) assert wgs.distance.__call__.__func__ == StraightDistance( ).__call__.__func__
def __init__(self, ds, distance=TerrainFollowingDistance(), mode='valid'): """ Parameters ---------- ds : xarray dataset as returned by load_wasp_grd distance : Distance object, optional Alternatives are StraightDistance and TerrainFollowingDistance2 mode : {'valid', 'extrapolate'}, optional if valid, terrain elevation outside grid area is NAN if extrapolate, the terrain elevation at the grid border is returned outside the grid area """ self.use_WS_bins = True ds = ds.rename(A="Weibull_A", k="Weibull_k", f="Sector_frequency", spd='Speedup', orog_trn='Turning', elev='Elevation', sec='wd', z='h') ds = ds.assign_coords(wd=(ds.wd - 1) * (360 / len(ds.wd))) ds = ds.isel(x=np.where(~np.all(np.isnan(ds.Elevation), 1))[0], y=np.where(~np.all(np.isnan(ds.Elevation), 0))[0]) super().__init__(ds, distance=distance)
def __init__(self, ds, distance=TerrainFollowingDistance(), mode='valid'): """ Parameters ---------- ds : xarray dataset as returned by load_wasp_grd distance : Distance object, optional Alternatives are StraightDistance and TerrainFollowingDistance2 mode : {'valid', 'extrapolate'}, optional if valid, terrain elevation outside grid area is NAN if extrapolate, the terrain elevation at the grid border is returned outside the grid area """ self._ds = ds self.mode = mode self.interp_funcs = {} self.interp_funcs_initialization() self.elevation_interpolator = EqDistRegGrid2DInterpolator(self._ds.coords['x'].data, self._ds.coords['y'].data, self._ds['elev'].data) self.TI_data_exist = 'tke' in self.interp_funcs.keys() super().__init__(p_wd=np.nanmean(self._ds['f'].data, (0, 1, 2)), a=np.nanmean(self._ds['A'].data, (0, 1, 2)), k=np.nanmean(self._ds['k'].data, (0, 1, 2)), ti=0) self.distance = distance
def from_wasp_grd(cls, path, globstr='*.grd', speedup_using_pickle=True, distance=TerrainFollowingDistance(), mode='valid'): ds = load_wasp_grd(path, globstr, speedup_using_pickle) return WaspGridSite(ds, distance, mode)
def WaspGridSite(ds, distance=TerrainFollowingDistance(), mode='valid'): if distance.__class__ == StraightDistance: cls = type("WaspGridSiteStraightDistance", (WaspGridSiteBase, ), {}) wgs = cls(ds=ds, mode=mode) else: cls = type("WaspGridSite" + type(distance).__name__, (type(distance), WaspGridSiteBase), {}) wgs = cls(ds=ds, mode=mode) wgs.__dict__.update(distance.__dict__) return wgs
def ParqueFicticioSite(distance=TerrainFollowingDistance(distance_resolution=2000)): site = WaspGridSiteBase.from_wasp_grd(ParqueFicticio_path, speedup_using_pickle=True, distance=distance) site.distance_type = 'terrain_following' site.initial_position = np.array([ [263655.0, 6506601.0], [263891.1, 6506394.0], [264022.2, 6506124.0], [264058.9, 6505891.0], [264095.6, 6505585.0], [264022.2, 6505365.0], [264022.2, 6505145.0], [263936.5, 6504802.0], ]) return site
def __init__(self, distance=TerrainFollowingDistance(distance_resolution=2000), mode='valid'): ds = load_wasp_grd(ParqueFicticio_path, speedup_using_pickle=True) WaspGridSite.__init__(self, ds, distance, mode) self.initial_position = np.array([ [263655.0, 6506601.0], [263891.1, 6506394.0], [264022.2, 6506124.0], [264058.9, 6505891.0], [264095.6, 6505585.0], [264022.2, 6505365.0], [264022.2, 6505145.0], [263936.5, 6504802.0], ])
def test_additional_input(): site = ParqueFicticioSite() wgs = WaspGridSite(site._ds, distance=TerrainFollowingDistance(distance_resolution=2000)) wgs.interp_funcs_initialization(['ws_mean']) x, y = site.initial_position.T h = 70 * np.ones_like(x) ws_mean, = wgs.interpolate(['ws_mean'], x, y, h) npt.assert_array_almost_equal(ws_mean[0, :50], np.array([4.77080802, 4.77216214, 4.77351626, 4.77487037, 4.77622449, 4.77757861, 4.77893273, 4.78028685, 4.78164097, 4.78299508, 4.7843492, 4.78570332, 4.78705744, 4.78841156, 4.78976567, 4.79111979, 4.79247391, 4.79382803, 4.79518215, 4.79653626, 4.79789038, 4.7992445, 4.80059862, 4.80195274, 4.80330685, 4.80466097, 4.80601509, 4.80736921, 4.80872333, 4.81007744, 4.81143156, 4.87114138, 4.9308512, 4.99056102, 5.05027084, 5.10998066, 5.16969047, 5.22940029, 5.28911011, 5.34881993, 5.40852975, 5.46823957, 5.52794939, 5.5876592, 5.64736902, 5.70707884, 5.76678866, 5.82649848, 5.8862083, 5.94591812]))
plt.legend() plt.show() npt.assert_array_less( np.abs(wasp_aep_no_density_correction - AEP_ilk.sum((0, 2)) * 1e6), 300) npt.assert_almost_equal(AEP_ilk.sum(), wasp_aep_no_density_correction_total, 3) @pytest.mark.parametrize( 'site,dw_ref', [(ParqueFicticioSite(distance=TerrainFollowingDistance2()), [ 0., 207.3842238, 484.3998264, 726.7130743, 1039.148129, 1263.1335982, 1490.3841602, 1840.6508086 ]), (ParqueFicticioSite(distance=TerrainFollowingDistance()), [ 0, 209.803579, 480.8335365, 715.6003233, 1026.9476322, 1249.5510034, 1475.1467251, 1824.1317343 ]), (ParqueFicticioSite(distance=StraightDistance()), [-0, 207, 477, 710, 1016, 1236, 1456, 1799])]) def test_distances(site, dw_ref): x, y = site.initial_position.T dw_ijl, cw_ijl, dh_ijl, _ = site.distances(src_x_i=x, src_y_i=y, src_h_i=np.array([70]), dst_x_j=x, dst_y_j=y, dst_h_j=np.array([70]), wd_il=np.array([[0]])) npt.assert_almost_equal(dw_ijl[0, :, 0], dw_ref)
def __init__(self, height, width, distance_resolution): self.height = height self.width = width super().__init__(p_wd=[1], ti=0) self.distance = TerrainFollowingDistance( distance_resolution=distance_resolution)
class Rectangle(TerrainFollowingDistance, UniformSite): def __init__(self, height, width, distance_resolution): self.height = height self.width = width super().__init__(p_wd=[1], ti=0) self.distance = TerrainFollowingDistance( distance_resolution=distance_resolution) def elevation(self, x_i, y_i): return np.where(np.abs(x_i) < self.width / 2, self.height, 0) @pytest.mark.parametrize( 'distance', [StraightDistance(), TerrainFollowingDistance()]) def test_flat_distances(distance): x = [0, 50, 100, 100] y = [100, 100, 100, 0] h = [0, 10, 20, 30] wdirs = [0, 30, 90] dw_ijl, hcw_ijl, dh_ijl, dw_indices_l = distance(FlatSite(), src_x_i=x, src_y_i=y, src_h_i=h, dst_x_j=[0], dst_y_j=[0], dst_h_j=[0], wd_il=np.array(wdirs)[na])
def from_wasp_grd(cls, path, globstr='*.grd', distance=TerrainFollowingDistance(), speedup_using_pickle=True, mode='valid'): ''' Reader for WAsP .grd resource grid files. Parameters ---------- path: str path to file or directory containing goldwind excel files globstr: str string that is used to glob files if path is a directory. Returns ------- WindResourceGrid: :any:`WindResourceGrid`: Examples -------- >>> from mowflot.wind_resource import WindResourceGrid >>> path = '../mowflot/tests/data/WAsP_grd/' >>> wrg = WindResourceGrid.from_wasp_grd(path) >>> print(wrg) <xarray.Dataset> Dimensions: (sec: 12, x: 20, y: 20, z: 3) Coordinates: * sec (sec) int64 1 2 3 4 5 6 7 8 9 10 11 12 * x (x) float64 5.347e+05 5.348e+05 5.349e+05 5.35e+05 ... * y (y) float64 6.149e+06 6.149e+06 6.149e+06 6.149e+06 ... * z (z) float64 10.0 40.0 80.0 Data variables: flow_inc (x, y, z, sec) float64 1.701e+38 1.701e+38 1.701e+38 ... ws_mean (x, y, z, sec) float64 3.824 3.489 5.137 5.287 5.271 ... meso_rgh (x, y, z, sec) float64 0.06429 0.03008 0.003926 ... obst_spd (x, y, z, sec) float64 1.701e+38 1.701e+38 1.701e+38 ... orog_spd (x, y, z, sec) float64 1.035 1.039 1.049 1.069 1.078 ... orog_trn (x, y, z, sec) float64 -0.1285 0.6421 0.7579 0.5855 ... power_density (x, y, z, sec) float64 77.98 76.96 193.5 201.5 183.9 ... rix (x, y, z, sec) float64 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... rgh_change (x, y, z, sec) float64 6.0 10.0 10.0 10.0 6.0 4.0 0.0 ... rgh_spd (x, y, z, sec) float64 1.008 0.9452 0.8578 0.9037 ... f (x, y, z, sec) float64 0.04021 0.04215 0.06284 ... tke (x, y, z, sec) float64 1.701e+38 1.701e+38 1.701e+38 ... A (x, y, z, sec) float64 4.287 3.837 5.752 5.934 5.937 ... k (x, y, z, sec) float64 1.709 1.42 1.678 1.74 1.869 ... flow_inc_tot (x, y, z) float64 1.701e+38 1.701e+38 1.701e+38 ... ws_mean_tot (x, y, z) float64 5.16 6.876 7.788 5.069 6.85 7.785 ... power_density_tot (x, y, z) float64 189.5 408.1 547.8 178.7 402.2 546.6 ... rix_tot (x, y, z) float64 0.0 0.0 0.0 9.904e-05 9.904e-05 ... tke_tot (x, y, z) float64 1.701e+38 1.701e+38 1.701e+38 ... A_tot (x, y, z) float64 5.788 7.745 8.789 5.688 7.716 8.786 ... k_tot (x, y, z) float64 1.725 1.869 2.018 1.732 1.877 2.018 ... elev (x, y) float64 37.81 37.42 37.99 37.75 37.46 37.06 ... ''' var_name_dict = { 'Flow inclination': 'flow_inc', 'Mean speed': 'ws_mean', 'Meso roughness': 'meso_rgh', 'Obstacles speed': 'obst_spd', 'Orographic speed': 'orog_spd', 'Orographic turn': 'orog_trn', 'Power density': 'power_density', 'RIX': 'rix', 'Roughness changes': 'rgh_change', 'Roughness speed': 'rgh_spd', 'Sector frequency': 'f', 'Turbulence intensity': 'tke', 'Weibull-A': 'A', 'Weibull-k': 'k', 'Elevation': 'elev', 'AEP': 'aep' } def _read_grd(filename): def _parse_line_floats(f): return [float(i) for i in f.readline().strip().split()] def _parse_line_ints(f): return [int(i) for i in f.readline().strip().split()] with open(filename, 'rb') as f: file_id = f.readline().strip().decode() nx, ny = _parse_line_ints(f) xl, xu = _parse_line_floats(f) yl, yu = _parse_line_floats(f) zl, zu = _parse_line_floats(f) values = np.array( [l.split() for l in f.readlines() if l.strip() != b""], dtype=np.float) # around 8 times faster xarr = np.linspace(xl, xu, nx) yarr = np.linspace(yl, yu, ny) # note that the indexing of WAsP grd file is 'xy' type, i.e., # values.shape == (xarr.shape[0], yarr.shape[0]) # we need to transpose values to match the 'ij' indexing values = values.T ############# # note WAsP denotes unavailable values using very large numbers, here # we change them into np.nan, to avoid strange results. values[values > 1e20] = np.nan return xarr, yarr, values if speedup_using_pickle: if os.path.isdir(path): pkl_fn = os.path.join( path, os.path.split(os.path.dirname(path))[1] + '.pkl') if os.path.isfile(pkl_fn): return WaspGridSiteBase.from_pickle(pkl_fn, distance=distance) else: site_conditions = WaspGridSiteBase.from_wasp_grd( path, globstr, distance=distance, speedup_using_pickle=False) site_conditions.to_pickle(pkl_fn) return site_conditions else: raise NotImplementedError if os.path.isdir(path): files = sorted(glob.glob(os.path.join(path, globstr))) else: raise Exception('Path was not a directory...') file_height_dict = defaultdict(list) pattern = re.compile( r'Sector (\w+|\d+) \s+ Height (\d+)m \s+ ([a-zA-Z0-9- ]+)') for f in files: sector, height, var_name = re.findall(pattern, f)[0] # print(sector, height, var_name) name = var_name_dict.get(var_name, var_name) file_height_dict[height].append((f, sector, name)) elev_avail = False first = True for height, files_subset in file_height_dict.items(): first_at_height = True for file, sector, var_name in files_subset: xarr, yarr, values = _read_grd(file) if sector == 'All': # Only 'All' sector has the elevation files. # So here we make sure that, when the elevation file # is read, it gets the right (x,y) coords/dims. if var_name == 'elev': elev_avail = True elev_vals = values elev_coords = {'x': xarr, 'y': yarr} elev_dims = ('x', 'y') continue else: var_name += '_tot' coords = { 'x': xarr, 'y': yarr, 'z': np.array([float(height)]) } dims = ('x', 'y', 'z') da = xr.DataArray(values[..., np.newaxis], coords=coords, dims=dims) else: coords = { 'x': xarr, 'y': yarr, 'z': np.array([float(height)]), 'sec': np.array([int(sector)]) } dims = ('x', 'y', 'z', 'sec') da = xr.DataArray(values[..., np.newaxis, np.newaxis], coords=coords, dims=dims) if first_at_height: ds_tmp = xr.Dataset({var_name: da}) first_at_height = False else: ds_tmp = xr.merge([ds_tmp, xr.Dataset({var_name: da})]) if first: ds = ds_tmp first = False else: ds = xr.concat([ds, ds_tmp], dim='z') if elev_avail: ds['elev'] = xr.DataArray(elev_vals, coords=elev_coords, dims=elev_dims) ############ # Calculate the compund speed-up factor based on orog_spd, rgh_spd # and obst_spd spd = 1 for dr in ds.data_vars: if dr in ['orog_spd', 'obst_spd', 'rgh_spd']: # spd *= np.where(ds.data_vars[dr].data > 1e20, 1, ds.data_vars[dr].data) spd *= np.where(np.isnan(ds.data_vars[dr].data), 1, ds.data_vars[dr].data) ds['spd'] = copy.deepcopy(ds['orog_spd']) ds['spd'].data = spd ############# # change the frequency from per sector to per deg ds['f'].data = ds['f'].data * len(ds['f']['sec'].data) / 360.0 # ############# # # note WAsP denotes unavailable values using very large numbers, here # # we change them into np.nan, to avoid strange results. # for var in ds.data_vars: # ds[var].data = np.where(ds[var].data > 1e20, np.nan, ds[var].data) # make sure coords along z is asending order ds = ds.loc[{'z': sorted(ds.coords['z'].values)}] ###################################################################### if 'tke' in ds and np.mean(ds['tke']) > 1: ds['tke'] *= 0.01 return WaspGridSite(ds, distance, mode)
return np.sqrt(np.maximum(self.height**2 - x_i**2, 0)) class Rectangle(TerrainFollowingDistance, UniformSite): def __init__(self, height, width, distance_resolution): self.height = height self.width = width super().__init__(p_wd=[1], ti=0) self.distance = TerrainFollowingDistance(distance_resolution=distance_resolution) def elevation(self, x_i, y_i): return np.where(np.abs(x_i) < self.width / 2, self.height, 0) @pytest.mark.parametrize('distance', [StraightDistance(), TerrainFollowingDistance() ]) def test_flat_distances(distance): x = [0, 50, 100, 100, 0] y = [100, 100, 100, 0, 0] h = [0, 10, 20, 30, 0] wdirs = [0, 30, 90] site = FlatSite(distance=distance) site.distance.setup(src_x_i=x, src_y_i=y, src_h_i=h) dw_ijl, hcw_ijl, dh_ijl = site.distance(wd_il=np.array(wdirs)[na], src_idx=[0, 1, 2, 3], dst_idx=[4]) dw_indices_l = site.distance.dw_order_indices(np.array(wdirs)) if 0: distance.plot(wd_il=np.array(wdirs)[na], src_i=[0, 1, 2, 3], dst_i=[4]) plt.show()