示例#1
0
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)
示例#2
0
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)
示例#4
0
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')
示例#5
0
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)
示例#6
0
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)
示例#7
0
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)
示例#8
0
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()
示例#9
0
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))
示例#10
0
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)
示例#11
0
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))
示例#12
0
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)
示例#13
0
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)
示例#14
0
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)
示例#15
0
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))