def test_spline(): wt_tab = V80() wt_spline = V80() wt_spline.spline_ct_power(err_tol_factor=1e-2) ws_lst = np.arange(3, 25, .001) # mean and max error assert (wt_tab.power(ws_lst) - wt_spline.power(ws_lst)).mean() < 1 assert ((wt_tab.power(ws_lst) - wt_spline.power(ws_lst)).max()) < 1400 # max change of gradient 80 times lower assert np.diff(np.diff(wt_spline.power(ws_lst))).max() * 80 < np.diff(np.diff(wt_tab.power(ws_lst))).max() ws_pts = [6.99, 7.01] dpdu_tab_pts = np.diag(fd(wt_tab.power)(np.array(ws_pts))) with use_autograd_in(): dpdu_spline_pts = np.diag(autograd(wt_spline.power)(np.array(ws_pts))) npt.assert_array_almost_equal(dpdu_spline_pts, [205555.17794162, 211859.45965873]) if 0: plt.plot(ws_lst, wt_tab.power(ws_lst)) plt.plot(ws_lst, wt_spline.power(ws_lst)) for wt, dpdu_pts, label in [(wt_tab, dpdu_tab_pts, 'V80 tabular'), (wt_spline, dpdu_spline_pts, 'V80 spline')]: for ws, dpdu in zip(ws_pts, dpdu_pts): plot_gradients(wt.power(ws), dpdu, ws, label, 1) ax = plt.gca().twinx() ax.plot(ws_lst, wt.power(ws_lst) - wt_spline.power(ws_lst)) plt.figure() plt.plot(np.diff(np.diff(wt_tab.power(ws_lst)))) plt.plot(np.diff(np.diff(wt_spline.power(ws_lst)))) plt.show()
def test_Mirror_NOJ(): # Compare points in flow map with ws of WT at same position site = UniformSite([1], ti=0.1) V80_D0 = V80() V80_D0._diameters = [0] wt = WindTurbines.from_WindTurbines([V80(), V80_D0]) wfm = NOJ(site, wt, k=.5, groundModel=Mirror()) sim_res = wfm([0], [0], h=[50], wd=0) fm_ref = sim_res.flow_map(YZGrid(x=0, y=np.arange(-70, 0, 20), z=10)) ref = fm_ref.WS_eff_xylk[:, 0, 0, 0].values res = np.array([ wfm([0, 0], [0, y], [50, 10], type=[0, 1], wd=0).WS_eff.sel(wt=1).item() for y in fm_ref.X[0] ]) if 0: fm_res = sim_res.flow_map(YZGrid(x=0, y=np.arange(-100, 10, 1))) fm_res.plot_wake_map() plt.plot(fm_ref.X[0], fm_ref.Y[0], '.') plt.plot(fm_ref.X[0], ref * 10, label='ref, WS*10') plt.plot(fm_ref.X[0], res * 10, label='Res, WS*10') plt.legend() plt.show() plt.close() npt.assert_array_equal(res, ref)
def test_method(): wt_linear = V80() wt_pchip = V80(method='pchip') wt_spline = V80(method='spline') ws_lst = np.arange(3, 25, .001) for wt in [wt_linear, wt_pchip, wt_spline]: wt.enable_autograd() ws_pts = [6.99, 7.01] with use_autograd_in(): dpdu_linear_pts = autograd(wt_linear.power)(np.array(ws_pts)) dpdu_pchip_pts = autograd(wt_pchip.power)(np.array(ws_pts)) dpdu_spline_pts = autograd(wt_spline.power)(np.array(ws_pts)) if 0: wt_dp_label_lst = [(wt_linear, dpdu_linear_pts, 'linear'), (wt_pchip, dpdu_pchip_pts, 'pchip'), (wt_spline, dpdu_spline_pts, 'spline')] for wt, dpdu_pts, label in wt_dp_label_lst: c = plt.plot(ws_lst, wt.power(ws_lst), label=label)[0].get_color() gradients.color_dict[label] = c for ws, dpdu in zip(ws_pts, dpdu_pts): plot_gradients(wt.power(ws), dpdu, ws, label) plt.legend() plt.figure() for wt, dpdu_pts, label in wt_dp_label_lst: plt.plot(ws_lst, wt_linear.power(ws_lst) - wt.power(ws_lst), label=label) plt.legend() plt.ylabel('Power difference wrt. linear') plt.figure() for wt, dpdu_pts, label in wt_dp_label_lst: plt.plot(np.diff(np.diff(wt.power(ws_lst))), label=label) plt.ylabel('Change of gradient') plt.legend() plt.show() # mean and max error for wt, mean_tol, absmean_tol, max_tol in [(wt_pchip, 213, 2323, 15632), (wt_spline, 1, 1, 1380)]: assert np.abs((wt_linear.power(ws_lst) - wt.power(ws_lst)).mean()) < mean_tol assert np.abs((wt_linear.power(ws_lst) - wt.power(ws_lst)).mean()) < absmean_tol assert np.abs((wt_linear.power(ws_lst) - wt.power(ws_lst)).max()) < max_tol for wt, diff_grad_max, dpdu_pts, ref_dpdu_pts in [(wt_linear, 64, dpdu_linear_pts, [178000.00007264, 236000.00003353]), (wt_pchip, 0.2, dpdu_pchip_pts, [ 202520.16516056, 203694.66294614]), (wt_spline, 0.8, dpdu_spline_pts, [205555.17794162, 211859.45965873])]: assert np.diff(np.diff(wt.power(ws_lst))).max() < diff_grad_max npt.assert_array_almost_equal(dpdu_pts, ref_dpdu_pts)
def test_from_flow_box_2wt(): site = Hornsrev1Site() windTurbines = V80() # simulate current and neighbour wt wfm = BastankhahGaussian(site, windTurbines) wd = np.arange(30) sim_res = wfm([0, 0], [0, 500], wd=wd) ref_aep = sim_res.aep().sel(wt=0) wt_x, wt_y = [0], [0] neighbour_x, neighbour_y = [0], [500] # make site with effects of neighbour wt sim_res = wfm(neighbour_x, neighbour_y, wd=wd) e = 100 box = sim_res.flow_box(x=np.linspace(min(wt_x) - e, max(wt_x) + e, 21), y=np.linspace(min(wt_y) - e, max(wt_y) + e, 21), h=windTurbines.hub_height(windTurbines.types())) site = XRSite.from_flow_box(box) # Simujlate current wt and compare aep wfm = BastankhahGaussian(site, windTurbines) sim_res = wfm(wt_x, wt_y, wd=wd) aep = sim_res.aep() if 0: site.ds.WS.sel(ws=10, wd=3).plot() windTurbines.plot(wt_x, wt_y) windTurbines.plot(neighbour_x, neighbour_y) plt.show() npt.assert_array_almost_equal(ref_aep, aep.sel(wt=0))
def test_Mirror(wfm_cls): # Compare points in flow map with ws of WT at same position. All2Alliterative failing with NOJ and WT.diameter=0 # and therefore this cannot be tested above site = UniformSite([1], ti=0.1) wt = V80() wfm = wfm_cls(site, wt, ZongGaussianDeficit(a=[0, 1]), turbulenceModel=STF2017TurbulenceModel(), groundModel=Mirror()) sim_res = wfm( [0], [0], h=[50], wd=0, ) fm_ref = sim_res.flow_map(YZGrid(x=0, y=np.arange(-70, 0, 20), z=10)) ref = fm_ref.WS_eff_xylk[:, 0, 0, 0].values res = np.array([ wfm([0, 0], [0, y], [50, 10], wd=0).WS_eff.sel(wt=1).item() for y in fm_ref.X[0] ]) if 0: fm_res = sim_res.flow_map(YZGrid(x=0, y=np.arange(-100, 10, 1))) fm_res.plot_wake_map() plt.plot(fm_ref.X[0], fm_ref.Y[0], '.') plt.plot(fm_ref.X[0], ref * 10, label='ref, WS*10') plt.plot(fm_ref.X[0], res * 10, label='Res, WS*10') plt.legend() plt.show() plt.close() npt.assert_array_equal(res, ref)
def test_Mirror_flow_map(wfm_cls, groundModel, superpositionModel): site = UniformSite([1], ti=0.1) wt = V80() wfm = NOJ(site, wt, k=.5, superpositionModel=superpositionModel) fm_ref = wfm([0, 0 + 1e-20], [0, 0 + 1e-20], wd=0, h=[50, -50]).flow_map( YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100))) fm_ref.plot_wake_map() plt.title("Underground WT added manually") plt.figure() wfm = wfm_cls(site, wt, NOJDeficit(k=.5), groundModel=groundModel, superpositionModel=superpositionModel) fm_res = wfm([0], [0], wd=0, h=[50]).flow_map( YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100))) fm_res.plot_wake_map() plt.title("With Mirror GroundModel") if 0: plt.show() plt.close() npt.assert_array_equal(fm_ref.WS_eff, fm_res.WS_eff)
def test_time_series_operating_wrong_shape(): from py_wake.wind_turbines.power_ct_functions import PowerCtFunctionList, PowerCtTabular d = np.load(os.path.dirname(examples.__file__) + "/data/time_series.npz") wd, ws, ws_std = [d[k][:6 * 24] for k in ['wd', 'ws', 'ws_std']] ws += 3 t = np.arange(6 * 24) wt = V80() site = Hornsrev1Site() # replace powerCtFunction wt.powerCtFunction = PowerCtFunctionList( key='operating', powerCtFunction_lst=[ PowerCtTabular(ws=[0, 100], power=[0, 0], power_unit='w', ct=[0, 0]), # 0=No power and ct wt.powerCtFunction ], # 1=Normal operation default_value=1) wfm = NOJ(site, wt) x, y = site.initial_position.T operating = (t < 48) | (t > 72) with pytest.raises( ValueError, match= r"Argument, operating\(shape=\(1, 144\)\), has unsupported shape." ): wfm(x, y, ws=ws, wd=wd, time=t, operating=[operating])
def test_GenericWindTurbine_cut_in_out(power_idle, ct_idle): ref = V80() power_norm = ref.power(15) wt = GenericWindTurbine('Generic', ref.diameter(), ref.hub_height(), power_norm / 1e3, turbulence_intensity=0, ws_cutin=3, ws_cutout=25, power_idle=power_idle, ct_idle=ct_idle) if 0: u = np.arange(0, 30, .1) p, ct = wt.power_ct(u) plt.plot(u, p / 1e6, label='Generic') plt.plot(u, ref.power(u) / 1e6, label=ref.name()) plt.ylabel('Power [MW]') plt.legend() ax = plt.twinx() ax.plot(u, ct, '--') ax.plot(u, ref.ct(u), '--') plt.ylabel('Ct') plt.show() assert wt.ct(2.9) == ct_idle assert wt.power(2.9) == power_idle assert wt.ct(25.1) == ct_idle assert wt.power(25.1) == power_idle
def test_time_series_operating(): from py_wake.wind_turbines.power_ct_functions import PowerCtFunctionList, PowerCtTabular d = np.load(os.path.dirname(examples.__file__) + "/data/time_series.npz") wd, ws, ws_std = [d[k][:6 * 24] for k in ['wd', 'ws', 'ws_std']] ws += 3 t = np.arange(6 * 24) wt = V80() site = Hornsrev1Site() # replace powerCtFunction wt.powerCtFunction = PowerCtFunctionList( key='operating', powerCtFunction_lst=[ PowerCtTabular(ws=[0, 100], power=[0, 0], power_unit='w', ct=[0, 0]), # 0=No power and ct wt.powerCtFunction ], # 1=Normal operation default_value=1) wfm = NOJ(site, wt) x, y = site.initial_position.T operating = (t < 48) | (t > 72) sim_res = wfm(x, y, ws=ws, wd=wd, time=t, operating=operating) npt.assert_array_equal(sim_res.operating[0], operating) npt.assert_array_equal(sim_res.Power[:, operating == 0], 0) npt.assert_array_equal(sim_res.Power[:, operating != 0] > 0, True) operating = np.ones((80, 6 * 24)) operating[1] = (t < 48) | (t > 72) sim_res = wfm(x, y, ws=ws, wd=wd, time=t, operating=operating) npt.assert_array_equal(sim_res.operating, operating) npt.assert_array_equal(sim_res.Power.values[operating == 0], 0) npt.assert_array_equal(sim_res.Power.values[operating != 0] > 0, True)
def test_yaw_tilt(yaw, tilt, cx, cz): site = IEA37Site(16) x, y = [0], [0] windTurbines = V80() D = windTurbines.diameter() wfm = IEA37SimpleBastankhahGaussian( site, windTurbines, deflectionModel=JimenezWakeDeflection()) x_lst = np.linspace(-200, 1000, 100) y_lst = np.linspace(-100, 100, 201) z_lst = np.arange(10, 200, 1) fm_yz = wfm(x, y, wd=270, ws=10, yaw=yaw, tilt=tilt).flow_map(YZGrid(x=5 * D, y=y_lst, z=z_lst)) fm_xz = wfm(x, y, wd=180, ws=10, yaw=yaw, tilt=tilt).flow_map(YZGrid(x=0, y=x_lst, z=z_lst)) fm_xy = wfm(x, y, wd=270, ws=10, yaw=yaw, tilt=tilt).flow_map(XYGrid(x=x_lst)) if 0: axes = plt.subplots(3, 1)[1].flatten() fm_xy.plot_wake_map(ax=axes[0]) axes[0].axvline(5 * D) fm_xz.plot_wake_map(ax=axes[1]) axes[1].axvline(5 * D) fm_yz.plot_wake_map(ax=axes[2]) plt.show() wake_center = fm_yz.WS_eff.where(fm_yz.WS_eff == fm_yz.WS_eff.min(), drop=True).squeeze() npt.assert_allclose(wake_center.y, cx, atol=.1) npt.assert_allclose(wake_center.h, cz, atol=.24)
def test_time_series_aep(): d = np.load(os.path.dirname(examples.__file__) + "/data/time_series.npz") wd, ws = [d[k][::100] for k in ['wd', 'ws']] wt = V80() site = Hornsrev1Site() x, y = site.initial_position.T wfm = NOJ(site, wt) sim_res = wfm(x, y, ws=ws, wd=wd, time=True, verbose=False) npt.assert_allclose(sim_res.aep().sum(), 545, atol=1)
def test_i_time_dependent_WS(): t = np.arange(4) WS_it = t[na] / 10 + np.array([9, 10])[:, na] ds = xr.Dataset( data_vars={'WS': (('i', 'time'), WS_it), 'P': ('wd', f), 'TI': 0.1}, coords={'wd': np.linspace(0, 360, len(f), endpoint=False)}) site = XRSite(ds) wfm = NOJ(site, V80()) sim_res = wfm([0, 200], [0, 0], ws=WS_it.mean(0), wd=np.zeros(4), time=t) npt.assert_array_equal(sim_res.WS, WS_it)
def test_yaw(): v80 = V80() yaw = np.deg2rad(np.arange(-30, 31)) ws = np.zeros_like(yaw) + 8 P0 = v80.power(ws[0]) if 0: plt.plot(yaw, v80.power(ws, 0, yaw) / P0) plt.plot(yaw, np.cos(yaw)**3) plt.grid() plt.show() npt.assert_array_almost_equal(v80.power(ws, 0, yaw) / P0, np.cos(yaw)**3, 2)
def test_plot_yz2_types(): wt = WindTurbines.from_WindTurbines([IEA37_WindTurbines(), V80()]) yaw_lst = np.array([-30, 0, 30]) for wd in 0, 45, 90: plt.figure() wt.plot_yz(yaw_lst * 20, types=[0, 1, 0], wd=wd, yaw=yaw_lst) for i, yaw in enumerate(yaw_lst): plt.plot([], 'gray', label="WT %d yaw: %d deg" % (i, yaw)) plt.legend() plt.title("WD: %s" % wd) if 0: plt.show() plt.close()
def test_time_series_override_WD(): d = np.load(os.path.dirname(examples.__file__) + "/data/time_series.npz") wd, ws = [d[k][:6 * 24] for k in ['wd', 'ws']] t = pd.date_range("2000-01-01", freq="10T", periods=24 * 6) WD_it = (np.arange(80) / 100)[:, na] + wd[na] wt = V80() site = Hornsrev1Site() x, y = site.initial_position.T wfm = NOJ(site, wt) sim_res = wfm(x, y, ws=ws, wd=wd, time=t, WD=WD_it, verbose=False) npt.assert_array_equal(sim_res.WS, ws) npt.assert_array_equal(sim_res.WD, WD_it) npt.assert_array_equal(sim_res.time, t)
def test_time_series_override_TI(): d = np.load(os.path.dirname(examples.__file__) + "/data/time_series.npz") wd, ws, ws_std = [d[k][:6 * 24] for k in ['wd', 'ws', 'ws_std']] ti = np.minimum(ws_std / ws, .5) t = pd.date_range("2000-01-01", freq="10T", periods=24 * 6) wt = V80() site = Hornsrev1Site() x, y = site.initial_position.T wfm = NOJ(site, wt) sim_res = wfm(x, y, ws=ws, wd=wd, time=t, TI=ti, verbose=False) npt.assert_array_equal(sim_res.WS, ws) npt.assert_array_equal(sim_res.WD, wd) npt.assert_array_equal(sim_res.time, t) npt.assert_array_equal(sim_res.TI[0], ti)
def test_time_series_values(): wt = V80() site = Hornsrev1Site() x, y = site.initial_position.T wfm = NOJ(site, wt) wd = np.arange(350, 360) ws = np.arange(5, 10) wd_t, ws_t = [v.flatten() for v in np.meshgrid(wd, ws)] sim_res_t = wfm(x, y, ws=ws_t, wd=wd_t, time=True, verbose=False) sim_res = wfm(x, y, wd=wd, ws=ws) for k in ['WS_eff', 'TI_eff', 'Power', 'CT']: npt.assert_array_equal( np.moveaxis(sim_res_t[k].values.reshape((80, 5, 10)), 1, 2), sim_res[k].values)
def test_yaw(): v80 = V80() yaw = np.arange(-30, 31) ws = np.zeros_like(yaw) + 8 P0 = v80.power(ws[0]) if 0: plt.plot(yaw, v80.power(ws, yaw=yaw) / P0) plt.plot(yaw, np.cos(np.deg2rad(yaw))**3) plt.grid() plt.figure() plt.plot(yaw, v80.ct(ws, yaw=yaw)) plt.plot(yaw, v80.ct(ws) * np.cos(np.deg2rad(yaw))**2) plt.grid() plt.show() # Power in cube region npt.assert_array_almost_equal(v80.power(ws, yaw=yaw) / P0, np.cos(np.deg2rad(yaw))**3, 2) # ct in constant region npt.assert_array_almost_equal(v80.ct(ws, yaw=yaw), v80.ct(ws) * np.cos(np.deg2rad(yaw))**2, 3)
def test_turning_mean(complex_grid_site, wfm): ds = xr.Dataset( data_vars={'Turning': (['x', 'y'], np.arange(-2, 4, 1).reshape((2, 3)).T), 'Sector_frequency': ('wd', f), 'Weibull_A': ('wd', A), 'Weibull_k': ('wd', k), 'TI': .1}, coords={'x': [0, 500, 1000], 'y': [0, 500], 'wd': np.linspace(0, 360, len(f), endpoint=False)}) site = XRSite(ds) wt = V80() wfm = wfm(site, wt, NOJDeficit()) sim_res = wfm([500, 500], [100, 400], wd=0, ws=10) print(sim_res.Power) if 0: sim_res.flow_map(XYGrid(y=np.linspace(0, 500, 100))).plot_wake_map() plt.show() assert sim_res.WS_eff.sel(wt=0).item() < sim_res.WS_eff.sel(wt=1).item() fm = sim_res.flow_map(Points([500, 500], [100, 400], [70, 70])) assert fm.WS_eff.sel(i=0).item() < fm.WS_eff.sel(i=1).item()
def test_twotype_windturbines(): v80 = V80() v88 = WindTurbine('V88', 88, 77, powerCtFunction=PowerCtTabular( hornsrev1.power_curve[:, 0], hornsrev1.power_curve[:, 1] * 1.1, 'w', hornsrev1.ct_curve[:, 1])) wts = WindTurbines.from_WindTurbines([v80, v88]) types0 = [0] * 9 types1 = [0, 0, 0, 1, 1, 1, 0, 0, 0] types2 = [1] * 9 for wfm in get_wfms(wts): npt.assert_array_equal(wts.types(), [0, 1]) npt.assert_almost_equal(wfm.aep(wt9_x, wt9_y, type=types0), 81.2066072392765) npt.assert_almost_equal(wfm.aep(wt9_x, wt9_y, type=types1), 83.72420504573488) npt.assert_almost_equal(wfm.aep(wt9_x, wt9_y, type=types2), 88.87227386796884)
def test_deflection_model(deflectionModel, dy10d): site = IEA37Site(16) x, y = [0], [0] windTurbines = V80() D = windTurbines.diameter() wfm = IEA37SimpleBastankhahGaussian(site, windTurbines, deflectionModel=deflectionModel()) yaw_ilk = np.reshape([-30], (1, 1, 1)) sim_res = wfm(x, y, yaw=yaw_ilk, wd=270, ws=10) fm = sim_res.flow_map(XYGrid(x=np.arange(-D, 10 * D + 10, 10))) min_WS_line = fm.min_WS_eff() if 0: plt.figure(figsize=(14, 3)) fm.plot_wake_map() min_WS_line.plot() plt.plot(10 * D, dy10d * D, '.', label="Ref, 10D") plt.legend() plt.show() npt.assert_almost_equal(min_WS_line.interp(x=10 * D).item() / D, dy10d)
def test_plot_deflection_grid(deflectionModel): site = IEA37Site(16) x, y = [0], [0] windTurbines = V80() D = windTurbines.diameter() wfm = IEA37SimpleBastankhahGaussian(site, windTurbines, deflectionModel=deflectionModel()) yaw_ilk = np.reshape([-30], (1, 1, 1)) sim_res = wfm(x, y, yaw=yaw_ilk, wd=270, ws=10) fm = sim_res.flow_map(XYGrid(x=np.arange(-D, 10 * D + 10, 10))) plt.figure(figsize=(14, 3)) fm.plot_wake_map() fm.plot_deflection_grid() min_WS_line = fm.min_WS_eff() min_WS_line.plot() plt.legend() plt.title(wfm.deflectionModel) if 0: plt.show() plt.close('all')