コード例 #1
0
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()
コード例 #2
0
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)
コード例 #3
0
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)
コード例 #4
0
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))
コード例 #5
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)
コード例 #6
0
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)
コード例 #7
0
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])
コード例 #8
0
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
コード例 #9
0
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)
コード例 #10
0
ファイル: test_jimenez.py プロジェクト: knutss/PyWake
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)
コード例 #11
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)
コード例 #12
0
ファイル: test_xrsite.py プロジェクト: knutss/PyWake
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)
コード例 #13
0
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)
コード例 #14
0
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()
コード例 #15
0
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)
コード例 #16
0
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)
コード例 #17
0
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)
コード例 #18
0
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)
コード例 #19
0
ファイル: test_xrsite.py プロジェクト: knutss/PyWake
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()
コード例 #20
0
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)
コード例 #21
0
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)
コード例 #22
0
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')