def test_IEA37_ex16(deficitModel, aep_ref): site = IEA37Site(16) x, y = site.initial_position.T windTurbines = IEA37_WindTurbines() wf_model = PropagateDownwind(site, windTurbines, wake_deficitModel=deficitModel, superpositionModel=SquaredSum(), turbulenceModel=GCLTurbulence()) aep_ilk = wf_model(x, y, wd=np.arange(0, 360, 22.5), ws=[9.8]).aep_ilk(normalize_probabilities=True) aep_MW_l = aep_ilk.sum((0, 2)) * 1000 # check if ref is reasonable aep_est = 16 * 3.35 * 24 * 365 * .8 # n_wt * P_rated * hours_pr_year - 20% wake loss = 375628.8 npt.assert_allclose(aep_ref[0], aep_est, rtol=.11) npt.assert_allclose(aep_ref[1], [ 9500, 8700, 11500, 14300, 21300, 25900, 39600, 44300, 23900, 13900, 15200, 33000, 72100, 18300, 12500, 8000 ], rtol=.15) npt.assert_almost_equal(aep_MW_l.sum(), aep_ref[0], 5) npt.assert_array_almost_equal(aep_MW_l, aep_ref[1], 5)
def test_fuga_downwind_vs_notebook(): powerCtFunction = PowerCtTabular([0, 100], [0, 0], 'w', [0.850877, 0.850877]) wt = WindTurbine(name='', diameter=80, hub_height=70, powerCtFunction=powerCtFunction) path = tfp + 'fuga/2MW/Z0=0.00001000Zi=00400Zeta0=0.00E+00' site = UniformSite([1, 0, 0, 0], ti=0.075) wfm_ULT = PropagateDownwind(site, wt, FugaYawDeficit(path)) WS = 10 p = Path(tfp) / "fuga/v80_wake_4d_y_no_deflection.csv" y, notebook_deficit_4d = np.array( [v.split(",") for v in p.read_text().strip().split("\n")], dtype=float).T sim_res = wfm_ULT([0], [0], wd=270, ws=WS, yaw=[[[17.4493]]]) fm = sim_res.flow_map(XYGrid(4 * wt.diameter(), y=y)) npt.assert_allclose(fm.WS_eff.squeeze() - WS, notebook_deficit_4d, atol=1e-6) if 0: plt.plot(y, notebook_deficit_4d, label='Notebook deficit 4d') plt.plot(y, fm.WS_eff.squeeze() - WS) plt.show() plt.close('all')
def test_GenericWindTurbine(): for ref, ti, cut_in, cut_out, p_tol, ct_tol in [(V80(), .1, 4, None, 0.03, .14), (WindTurbine.from_WAsP_wtg(wtg_path + "Vestas V112-3.0 MW.wtg"), .05, 3, 25, 0.035, .07), (DTU10MW(), .05, 4, 25, 0.06, .12)]: power_norm = ref.power(np.arange(10, 20)).max() wt = GenericWindTurbine('Generic', ref.diameter(), ref.hub_height(), power_norm / 1e3, turbulence_intensity=ti, ws_cutin=cut_in, ws_cutout=cut_out) 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(loc='center left') ax = plt.twinx() ax.plot(u, ct, '--') ax.plot(u, ref.ct(u), '--') ax.set_ylim([0, 1]) plt.ylabel('Ct') plt.show() u = np.arange(5, 25) p, ct = wt.power_ct(u) p_ref, ct_ref = ref.power_ct(u) # print(np.abs(p_ref - p).max() / power_norm) npt.assert_allclose(p, p_ref, atol=power_norm * p_tol) # print(np.abs(ct_ref - ct).max()) npt.assert_allclose(ct, ct_ref, atol=ct_tol)
def test_iea37_distances(): from py_wake.examples.data.iea37 import IEA37Site n_wt = 16 # must be 9, 16, 36, 64 site = IEA37Site(n_wt) x, y = site.initial_position.T lw = site.local_wind(x_i=x, y_i=y, wd=site.default_wd, ws=site.default_ws) dw_iil, hcw_iil, _, _ = site.wt2wt_distances( x_i=x, y_i=y, h_i=np.zeros_like(x), wd_il=lw.WD_ilk.mean(2)) # Wind direction. wdir = np.rad2deg(np.arctan2(hcw_iil, dw_iil)) npt.assert_allclose( wdir[:, 0, 0], [180, -90, -18, 54, 126, -162, -90, -54, -18, 18, 54, 90, 126, 162, -162, -126], atol=1e-4) if 0: import matplotlib.pyplot as plt fig, ax = plt.subplots() ax.scatter(x, y) for i, txt in enumerate(np.arange(len(x))): ax.annotate(txt, (x[i], y[i]), fontsize='large')
def test_deficitModel_wake_map_convection(deficitModel, ref): site = IEA37Site(16) x, y = site.initial_position.T windTurbines = IEA37_WindTurbines() wf_model = PropagateDownwind(site, windTurbines, wake_deficitModel=deficitModel, superpositionModel=WeightedSum(), turbulenceModel=GCLTurbulence()) x_j = np.linspace(-1500, 1500, 200) y_j = np.linspace(-1500, 1500, 100) flow_map = wf_model(x, y, wd=0, ws=9).flow_map(HorizontalGrid(x_j, y_j)) X, Y = flow_map.X, flow_map.Y Z = flow_map.WS_eff_xylk[:, :, 0, 0] mean_ref = [3.2, 4.9, 8., 8.2, 7.9, 7.4, 7., 7., 7.4, 7.9, 8.1, 8.1, 8., 7.8, 7.9, 8.1, 8.4] if 0: flow_map.plot_wake_map() plt.plot(X[49, 100:133:2], Y[49, 100:133:2], '.-') windTurbines.plot(x, y) plt.figure() plt.plot(Z[49, 100:133:2], label='Actual') plt.plot(ref, label='Reference') plt.plot(mean_ref, label='Mean ref') plt.legend() plt.show() # check that ref is reasonable npt.assert_allclose(ref[2:], mean_ref[2:], atol=2.6) npt.assert_array_almost_equal(Z[49, 100:133:2], ref, 2)
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_fuga_wake_center_vs_notebook(): p = Path(tfp) / "fuga/v80_wake_center_x.csv" x, notebook_wake_center = np.array([v.split(",") for v in p.read_text().strip().split("\n")], dtype=float).T powerCtFunction = PowerCtTabular([0, 100], [0, 0], 'w', [0.850877, 0.850877]) wt = WindTurbine(name='', diameter=80, hub_height=70, powerCtFunction=powerCtFunction) path = tfp + 'fuga/2MW/Z0=0.00001000Zi=00400Zeta0=0.00E+00' site = UniformSite([1, 0, 0, 0], ti=0.075) wfm = PropagateDownwind( site, wt, wake_deficitModel=FugaYawDeficit(path), deflectionModel=FugaDeflection(path, 'input_par') ) WS = 10 sim_res = wfm([0], [0], yaw=[17.4493], wd=270, ws=[WS]) y = wfm.wake_deficitModel.mirror(wfm.wake_deficitModel.y, anti_symmetric=True) fm = sim_res.flow_map(XYGrid(x=x[1:], y=y[240:271])) fuga_wake_center = [np.interp(0, InterpolatedUnivariateSpline(ws.y, ws.values).derivative()(ws.y), ws.y) for ws in fm.WS_eff.squeeze().T] if 0: plt.plot(x, notebook_wake_center, label='Notebook deflection') plt.plot(x[1:], fuga_wake_center) plt.show() plt.close('all') npt.assert_allclose(fuga_wake_center, notebook_wake_center[1:], atol=.14)
def test_wake_radius(deficitModel, wake_radius_ref): mean_ref = [105, 68, 135, 93, 123] # check that ref is reasonable npt.assert_allclose(wake_radius_ref, mean_ref, rtol=.5) npt.assert_array_almost_equal(deficitModel.wake_radius( D_src_il=np.reshape([100, 50, 100, 100, 100], (5, 1)), dw_ijlk=np.reshape([500, 500, 1000, 500, 500], (5, 1, 1, 1)), ct_ilk=np.reshape([.8, .8, .8, .4, .8], (5, 1, 1)), TI_ilk=np.reshape([.1, .1, .1, .1, .05], (5, 1, 1)), TI_eff_ilk=np.reshape([.1, .1, .1, .1, .05], (5, 1, 1)))[:, 0, 0, 0], wake_radius_ref) # Check that it works when called from WindFarmModel site = IEA37Site(16) windTurbines = IEA37_WindTurbines() wfm = PropagateDownwind(site, windTurbines, wake_deficitModel=deficitModel, turbulenceModel=GCLTurbulence()) wfm(x=[0, 500], y=[0, 0], wd=[30], ws=[10]) if 0: sim_res = wfm([0], [0], wd=[270], ws=10) sim_res.flow_map(HorizontalGrid(x=np.arange(-100, 1500, 10))).WS_eff.plot() x = np.arange(0, 1500, 10) wr = deficitModel.wake_radius( D_src_il=np.reshape([130], (1, 1)), dw_ijlk=np.reshape(x, (1, len(x), 1, 1)), ct_ilk=sim_res.CT.values, TI_ilk=np.reshape(sim_res.TI.values, (1, 1, 1)), TI_eff_ilk=sim_res.TI_eff.values)[0, :, 0, 0] plt.title(deficitModel.__class__.__name__) plt.plot(x, wr) plt.plot(x, -wr) plt.axis('equal') plt.show()
def test_two_turbine_case0_time_series(): # same as test_two_turbine_case0 ws, ti, shear, wdir, dist = [10.9785338191, 0.2623204277, 0.4092031776, -38.4114616871 % 360, 5.123719529] # ref from simulation statistic (not updated yet) ws_ref = 1.103937e+01 thrust_ref = 4.211741e+02 power_ref = 3.399746e+06 ref_dels = [4546, 5931, 11902, 7599, 2407] wt = IEA34_130_2WT_Surrogate() site = UniformSite(p_wd=[1], ti=ti, ws=ws) wfm = NOJ(site, wt, turbulenceModel=STF2017TurbulenceModel()) sim_res = wfm([0, 0], [0, dist * 130], wd=wdir, time=True, Alpha=shear) assert sim_res.dw_ijl.dims == ('wt', 'wt', 'time') npt.assert_allclose(ws, ws_ref, rtol=.006) # npt.assert_allclose(ti, ws_std_ref / ws_ref, atol=.19) npt.assert_allclose(sim_res.Power.sel(wt=0), power_ref, rtol=0.002) npt.assert_allclose(sim_res.CT.sel(wt=0), thrust_ref * 1e3 / (1 / 2 * 1.225 * (65**2 * np.pi) * ws_ref**2), rtol=0.03) sim_res['duration'] = ('time', [3600 * 24 * 365 * 20]) loads = sim_res.loads(method='TwoWT') npt.assert_allclose(loads.DEL.sel(wt=0).squeeze(), ref_dels, rtol=.05) f = 20 * 365 * 24 * 3600 / 1e7 m = loads.m.values npt.assert_array_almost_equal(loads.LDEL.sel(wt=0).squeeze(), (loads.DEL.sel(wt=0).squeeze()**m * f)**(1 / m)) loads = sim_res.loads(method='TwoWT', softmax_base=100) npt.assert_allclose(loads.DEL.sel(wt=0).squeeze(), ref_dels, rtol=.05) npt.assert_array_almost_equal(loads.LDEL.sel(wt=0).squeeze(), (loads.DEL.sel(wt=0).squeeze()**m * f)**(1 / m))
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_two_turbine_case0(): if 0: i = 0 f = r'C:\mmpe\programming\python\Topfarm\iea-3_4-130-rwt\turbine_model\res/' print(list(pd.DataFrame(eval(Path(f + 'input_two_turbines_dist.json').read_text())).iloc[i])) # [10.9785338191, 0.2623204277, 0.4092031776, -38.4114616871, 5.123719529] print(pd.concat([pd.read_csv(f + 'stats_two_turbines_mean.csv').iloc[i, [12, 14, 322]], pd.read_csv(f + 'stats_two_turbines_std.csv').iloc[i, [12, 14, 322]]], axis=1)) # Free wind speed Abs_vhor, gl. coo, of gl. pos ... 1.103937e+01 0.914252 # Aero rotor thrust 4.211741e+02 41.015962 # generator_servo inpvec 2 2: pelec [w] 3.399746e+06 3430.717100 print(pd.read_csv(f + 'stats_two_turbines_del.csv').iloc[i, [28, 29, 1, 2, 9]]) # MomentMx Mbdy:blade1 nodenr: 1 coo: blade1 blade root moment blade1 4546.998501 # MomentMy Mbdy:blade1 nodenr: 1 coo: blade1 blade root moment blade1 5931.157693 # MomentMx Mbdy:tower nodenr: 1 coo: tower tower bottom moment 11902.153031 # MomentMy Mbdy:tower nodenr: 1 coo: tower tower bottom moment 7599.336676 # MomentMz Mbdy:tower nodenr: 11 coo: tower tower top/yaw bearing moment 2407.279074 ws, ti, shear, wdir, dist = [10.9785338191, 0.2623204277, 0.4092031776, -38.4114616871 % 360, 5.123719529] # ref from simulation statistic (not updated yet) ws_ref = 1.103937e+01 ws_std_ref = 0.914252 thrust_ref = 4.211741e+02 power_ref = 3.399746e+06 ref_dels = [4546, 5931, 11902, 7599, 2407] wt = IEA34_130_2WT_Surrogate() site = UniformSite(p_wd=[1], ti=ti, ws=ws) sim_res = NOJ(site, wt, turbulenceModel=STF2017TurbulenceModel())([0, 0], [0, dist * 130], wd=wdir, Alpha=shear) npt.assert_allclose(ws, ws_ref, rtol=.006) # npt.assert_allclose(ti, ws_std_ref / ws_ref, atol=.19) npt.assert_allclose(sim_res.Power.sel(wt=0), power_ref, rtol=0.002) npt.assert_allclose(sim_res.CT.sel(wt=0), thrust_ref * 1e3 / (1 / 2 * 1.225 * (65**2 * np.pi) * ws_ref**2), rtol=0.03) loads = sim_res.loads(method='TwoWT') npt.assert_allclose(loads.DEL.sel(wt=0).squeeze(), ref_dels, rtol=.05) f = 20 * 365 * 24 * 3600 / 1e7 m = loads.m.values npt.assert_array_almost_equal(loads.LDEL.sel(wt=0).squeeze(), (loads.DEL.sel(wt=0).squeeze()**m * f)**(1 / m)) loads = sim_res.loads(method='TwoWT', softmax_base=100) npt.assert_allclose(loads.DEL.sel(wt=0).squeeze(), ref_dels, rtol=.05) npt.assert_array_almost_equal(loads.LDEL.sel(wt=0).squeeze(), (loads.DEL.sel(wt=0).squeeze()**m * f)**(1 / m))
def test_neighbour_farm_speed(): # import and setup site and windTurbines site = IEA37Site(16) # setup current, neighbour and all positions wt_x, wt_y = site.initial_position.T neighbour_x, neighbour_y = wt_x - 4000, wt_y all_x, all_y = np.r_[wt_x, neighbour_x], np.r_[wt_y, neighbour_y] windTurbines = WindTurbines.from_WindTurbines([IEA37_WindTurbines(), IEA37_WindTurbines()]) windTurbines._names = ["Current wind farm", "Neighbour wind farm"] types = [0] * len(wt_x) + [1] * len(neighbour_x) wf_model = PropagateDownwind(site, windTurbines, wake_deficitModel=BastankhahGaussianDeficit(use_effective_ws=True), superpositionModel=LinearSum()) # Consider wd=270 +/- 30 deg only wd_lst = np.arange(240, 301) sim_res, t = timeit(wf_model, verbose=False)(all_x, all_y, type=types, ws=9.8, wd=wd_lst) if 1: ext = 100 flow_box = wf_model(neighbour_x, neighbour_y, wd=wd_lst).flow_box( x=np.linspace(min(wt_x) - ext, max(wt_x) + ext, 53), y=np.linspace(min(wt_y) - ext, max(wt_y) + ext, 51), h=[100, 110, 120]) wake_site = XRSite.from_flow_box(flow_box) wake_site.save('tmp.nc') else: wake_site = XRSite.load('tmp.nc') wf_model_wake_site = PropagateDownwind(wake_site, windTurbines, wake_deficitModel=BastankhahGaussianDeficit(use_effective_ws=True), superpositionModel=LinearSum()) sim_res_wake_site, _ = timeit(wf_model_wake_site, verbose=False)(wt_x, wt_y, ws=9.8, wd=wd_lst) npt.assert_allclose(sim_res.aep().sel(wt=np.arange(len(wt_x))).sum(), sim_res_wake_site.aep().sum(), rtol=0.0005) npt.assert_array_almost_equal(sim_res.aep().sel(wt=np.arange(len(wt_x))), sim_res_wake_site.aep(), 2)
def test_fuga_deflection_vs_notebook(): p = Path(tfp) / "fuga/v80_deflection_x.csv" x, notebook_deflection = np.array([v.split(",") for v in p.read_text().strip().split("\n")], dtype=float).T path = tfp + 'fuga/2MW/Z0=0.00001000Zi=00400Zeta0=0.00E+00' fuga_deflection = -FugaDeflection(path).calc_deflection(dw_ijl=np.reshape(x, (1, 41, 1)), hcw_ijl=np.reshape(x * 0, (1, 41, 1)), dh_ijl=np.reshape(x * 0, (1, 41, 1)), WS_ilk=np.array([[[9.5]]]), WS_eff_ilk=np.array([[[9.5]]]), yaw_ilk=np.array([[[17.4493]]]), ct_ilk=np.array([[[0.850877]]]) * np.cos(0.30454774)**2, D_src_il=np.array([[80]]))[1].squeeze() if 0: plt.plot(x, notebook_deflection, label='Notebook deflection') plt.plot(x, fuga_deflection) plt.show() plt.close('all') npt.assert_allclose(fuga_deflection, notebook_deflection, atol=1e-5)
def test_GlobalWindAtlasSite(): ref = Hornsrev1Site() lat, long = 55.52972, 7.906111 # hornsrev site = GlobalWindAtlasSite(lat, long, height=70, roughness=0.001, ti=0.075) ref_mean = weibull.mean(ref.ds.Weibull_A, ref.ds.Weibull_k) gwa_mean = weibull.mean(site.ds.Weibull_A, site.ds.Weibull_k) if 0: plt.figure() plt.plot(ref.ds.wd, ref_mean, label='HornsrevSite') plt.plot(site.ds.wd, gwa_mean, label='HornsrevSite') for r in [0, 1.5]: for h in [10, 200]: A, k = [site.gwc_ds[v].sel(roughness=r, height=h) for v in ['Weibull_A', 'Weibull_k']] plt.plot(site.gwc_ds.wd, weibull.mean(A, k), label=f'{h}, {r}') plt.legend() plt.show() npt.assert_allclose(gwa_mean, ref_mean, atol=1.4) for var, atol in [('Sector_frequency', 0.03), ('Weibull_A', 1.6), ('Weibull_k', 0.4)]: npt.assert_allclose(site.ds[var], ref.ds[var], atol=atol)
def test_one_turbine_case0(): ws, ti, shear = 9.2984459862, 0.0597870198, 0.2 if 0: f = r'C:\mmpe\programming\python\Topfarm\iea-3_4-130-rwt\turbine_model\res/' print(pd.concat([pd.read_csv(f + 'stats_one_turbine_mean.csv').iloc[0, [10, 14, 322]], pd.read_csv(f + 'stats_one_turbine_std.csv').iloc[0, [10, 14, 322]]], axis=1)) # Free wind speed Vy, gl. coo, of gl. pos 0.00... 9.309756e+00 0.401308 # Aero rotor thrust 5.408776e+02 11.489005 # generator_servo inpvec 2 2: pelec [w] 2.931442e+06 116491.192548 print(pd.read_csv(f + 'stats_one_turbine_del.csv').iloc[0, [28, 29, 1, 2, 9]]) # MomentMx Mbdy:blade1 nodenr: 1 coo: blade1 blade root moment blade1 1822.247387 # MomentMy Mbdy:blade1 nodenr: 1 coo: blade1 blade root moment blade1 5795.166623 # MomentMx Mbdy:tower nodenr: 1 coo: tower tower bottom moment 4385.405881 # MomentMy Mbdy:tower nodenr: 1 coo: tower tower bottom moment 2468.357017 # MomentMz Mbdy:tower nodenr: 11 coo: tower tower top/yaw bearing moment 1183.884786 ws_ref = 9.309756e+00 ws_std_ref = 0.401308 power_ref = 2.931442e+06 thrust_ref = 5.408776e+02 ref_dels = [1822, 5795, 4385, 2468, 1183] wt = IEA34_130_1WT_Surrogate() assert wt.loadFunction.output_keys[1] == 'del_blade_edge' assert wt.loadFunction.wohler_exponents == [10, 10, 4, 4, 7] site = UniformSite(p_wd=[1], ti=ti, ws=ws) sim_res = NOJ(site, wt, turbulenceModel=STF2017TurbulenceModel())([0], [0], wd=0, Alpha=shear) npt.assert_allclose(ws, ws_ref, rtol=.0013) npt.assert_allclose(ti, ws_std_ref / ws_ref, atol=.02) npt.assert_allclose(sim_res.Power, power_ref, rtol=0.003) npt.assert_allclose(sim_res.CT, thrust_ref * 1e3 / (1 / 2 * 1.225 * (65**2 * np.pi) * ws_ref**2), rtol=0.011) loads = sim_res.loads(method='OneWT') npt.assert_allclose(loads.DEL.squeeze(), ref_dels, rtol=.11) f = 20 * 365 * 24 * 3600 / 1e7 m = np.array([10, 10, 4, 4, 7]) npt.assert_array_almost_equal(loads.LDEL.squeeze(), (loads.DEL.squeeze()**m * f)**(1 / m)) loads = sim_res.loads(method='OneWT_WDAvg') npt.assert_allclose(loads.DEL.squeeze(), ref_dels, rtol=.11) npt.assert_array_almost_equal(loads.LDEL.squeeze(), (loads.DEL.squeeze()**m * f)**(1 / m))