Skip to content
Snippets Groups Projects
test_wasp_grid_site.py 15.5 KiB
Newer Older
Mads M. Pedersen's avatar
Mads M. Pedersen committed
import numpy as np
Mads M. Pedersen's avatar
Mads M. Pedersen committed
from numpy import newaxis as na
Mads M. Pedersen's avatar
Mads M. Pedersen committed
from py_wake.tests import npt
import pytest
from py_wake.examples.data.ParqueFicticio import ParqueFicticio_path
from py_wake.examples.data.ParqueFicticio.parque_ficticio import ParqueFicticioSite
from py_wake.site.wasp_grid_site import WaspGridSite, WaspGridSiteBase
Mads M. Pedersen's avatar
Mads M. Pedersen committed
import os
import time
from py_wake.tests.test_files.wasp_grid_site import one_layer
from py_wake.site.distance import TerrainFollowingDistance, StraightDistance, TerrainFollowingDistance2
Mads M. Pedersen's avatar
Mads M. Pedersen committed
import math
from py_wake.aep_calculator import AEPCalculator
from py_wake.wake_models.noj import NOJ
from py_wake.wind_turbines import OneTypeWindTurbines
Mads M. Pedersen's avatar
Mads M. Pedersen committed


@pytest.fixture
def site():
    return ParqueFicticioSite()


@pytest.fixture
def site2():
    site = ParqueFicticioSite(distance=TerrainFollowingDistance2())
    x, y = site.initial_position.T
    return site, x, y


def test_WaspGridSiteDistanceClass(site):
    wgs = WaspGridSite(site._ds, distance=TerrainFollowingDistance(distance_resolution=2000))
    assert wgs.distance_resolution == 2000
    assert wgs.distances.__func__ == TerrainFollowingDistance.distances
    wgs = WaspGridSite(site._ds, distance=StraightDistance())
    assert wgs.distances.__func__ == StraightDistance.distances


Mads M. Pedersen's avatar
Mads M. Pedersen committed
def test_local_wind(site):
    x_i, y_i = site.initial_position.T
    h_i = x_i * 0 + 70
    wdir_lst = np.arange(0, 360, 90)
    wsp_lst = np.arange(3, 6)
    WD_ilk, WS_ilk, TI_ilk, P_ilk = site.local_wind(x_i=x_i, y_i=y_i, h_i=h_i, wd=wdir_lst, ws=wsp_lst)
    npt.assert_array_equal(WS_ilk.shape, (8, 4, 3))

    WD_ilk, WS_ilk, TI_ilk, P_ilk = site.local_wind(x_i=x_i, y_i=y_i, h_i=h_i)
    npt.assert_array_equal(WS_ilk.shape, (8, 360, 23))

    # check probability local_wind()[-1]
    npt.assert_almost_equal(site.local_wind(x_i=x_i, y_i=y_i, h_i=h_i, wd=[0], ws=[10])[-1],
                            site.local_wind(x_i=x_i, y_i=y_i, h_i=h_i, wd=[0], ws=[10], wd_bin_size=2)[-1] * 180, 6)


Mikkel Friis-Møller's avatar
Mikkel Friis-Møller committed
def test_shear(site):
    x = [262878]
    y = [6504714]
    npt.assert_array_almost_equal(site._ds['spd'].sel(x=262878, y=6504714, sec=1), [.6240589, .8932919])
    z = [30, 115, 200]
    ws = site.local_wind(x_i=x, y_i=y, h_i=z, wd=[0], ws=[10])[1][:, 0, 0]
Mads M. Pedersen's avatar
Mads M. Pedersen committed

    if 0:
        import matplotlib.pyplot as plt
Mikkel Friis-Møller's avatar
Mikkel Friis-Møller committed
        plt.plot(ws, z, '.-')
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        plt.show()
Mikkel Friis-Møller's avatar
Mikkel Friis-Møller committed

    # linear interpolation
    npt.assert_array_almost_equal(ws, [6.240589, np.mean([6.240589, 8.932919]), 8.932919])
Mads M. Pedersen's avatar
Mads M. Pedersen committed
def test_wasp_resources_grid_point(site):
    #     x = np.array([l.split() for l in """0.6010665    -10.02692    32.71442    -6.746912
    # 0.5007213    -4.591617    37.10247    -11.0699
    # 0.3104101    -1.821247    59.18301    -12.56743
    # 0.4674515    16.14293    44.84665    -9.693183
    # 0.8710347    5.291974    26.01634    -6.154611
    # 0.9998786    -2.777032    15.72486    1.029988
    # 0.9079611    -7.882853    16.33216    6.42329
    # 0.759553    -5.082487    17.23354    10.18187
    # 0.7221162    4.606324    17.96417    11.45838
    # 0.8088576    8.196074    16.16308    9.277925
    # 0.8800673    3.932325    14.82337    5.380589
    # 0.8726974    -3.199536    19.99724    -1.433086""".split("\n")], dtype=np.float)
    #     for x_ in x.T:
    #         print(list(x_))
    x = [262978]
    y = [6504814]
    npt.assert_almost_equal(site.elevation(x, y), 227.8, 1)

    # Data from WAsP:
    # - add turbine (262878,6504814,30)
    # - Turbine (right click) - reports - Turbine Site Report full precision
    wasp_A = [2.197305, 1.664085, 1.353185, 2.651781, 5.28438, 5.038289,
              4.174325, 4.604496, 5.043066, 6.108261, 6.082033, 3.659798]
    wasp_k = [1.771484, 2.103516, 2.642578, 2.400391, 2.357422, 2.306641,
              2.232422, 2.357422, 2.400391, 2.177734, 1.845703, 1.513672]
    wasp_f = [5.188083, 2.509297, 2.869334, 4.966141, 13.16969, 9.514355,
              4.80275, 6.038354, 9.828702, 14.44174, 16.60567, 10.0659]
    wasp_spd = [0.6010665, 0.5007213, 0.3104101, 0.4674515, 0.8710347, 0.9998786,
                0.9079611, 0.759553, 0.7221162, 0.8088576, 0.8800673, 0.8726974]
    wasp_trn = [-10.02692, -4.591617, -1.821247, 16.14293, 5.291974, -
                2.777032, -7.882853, -5.082487, 4.606324, 8.196074, 3.932325, -3.199536]
    wasp_inc = [-6.746912, -11.0699, -12.56743, -9.693183, -6.154611,
                1.029988, 6.42329, 10.18187, 11.45838, 9.277925, 5.380589, -1.433086]
    wasp_ti = [32.71442, 37.10247, 59.18301, 44.84665, 26.01634, 15.72486,
               16.33216, 17.23354, 17.96417, 16.16308, 14.82337, 19.99724]
    rho = 1.179558

    wasp_u_mean = [1.955629, 1.473854, 1.202513, 2.350761, 4.683075,
                   4.463644, 3.697135, 4.080554, 4.470596, 5.409509, 5.402648, 3.300305]
    wasp_p_air = [9.615095, 3.434769, 1.556282, 12.45899, 99.90289,
                  88.03519, 51.41135, 66.09097, 85.69466, 164.5592, 193.3779, 56.86945]
    wasp_aep = np.array([3725293.0, 33722.71, 0.3093564, 3577990.0, 302099600.0, 188784100.0,
                         48915640.0, 84636210.0, 189009800.0, 549195100.0, 691258600.0, 120013000.0]) / 1000
    wasp_aep_no_density_correction = np.array([3937022.0, 36046.93, 0.33592, 3796496.0, 314595600.0,
                                               196765700.0, 51195440.0, 88451200.0, 197132700.0, 568584400.0, 712938400.0, 124804600.0]) / 1000
    wasp_aep_total = 2.181249024
    wasp_aep_no_density_correction_total = 2.26224
    wt_u = np.array([3.99, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25])
    wt_p = np.array([0, 55., 185., 369., 619., 941., 1326., 1741., 2133., 2436., 2617., 2702., 2734.,
                     2744., 2747., 2748., 2748., 2750., 2750., 2750., 2750., 2750., 2750.])
    wt_ct = np.array([0, 0.871, 0.853, 0.841, 0.841, 0.833, 0.797, 0.743, 0.635, 0.543, 0.424,
                      0.324, 0.258, 0.21, 0.175, 0.147, 0.126, 0.109, 0.095, 0.083, 0.074, 0.065, 0.059])
    wt = OneTypeWindTurbines.from_tabular(name="NEG-Micon 2750/92 (2750 kW)", diameter=92, hub_height=70,
                                          ws=wt_u, ct=wt_ct, power=wt_p, power_unit='kw')

    A_lst, k_lst, f_lst, spd_lst, orog_trn_lst, flow_inc_lst, tke_lst = [site.interp_funcs[n](
        (x, y, 30, range(0, 360, 30))) for n in ['A', 'k', 'f', 'spd', 'orog_trn', 'flow_inc', 'tke']]
    f_lst = f_lst * 360 / 12
    pdf_lst = [lambda x, A=A, k=k: k / A * (x / A)**(k - 1) * np.exp(-(x / A)**k) * (x[1] - x[0])
               for A, k in zip(A_lst, k_lst)]
    cdf_lst = [lambda x, A=A, k=k: 1 - np.exp(-(x / A) ** k) for A, k in zip(A_lst, k_lst)]
    dx = .1
    ws = np.arange(dx / 2, 35, dx)

    # compare to wasp data
    npt.assert_array_equal(A_lst, wasp_A)
    npt.assert_array_equal(k_lst, wasp_k)
    npt.assert_array_almost_equal(f_lst, np.array(wasp_f) / 100)
    npt.assert_array_almost_equal(spd_lst, wasp_spd)
    npt.assert_array_almost_equal(orog_trn_lst, wasp_trn)
    npt.assert_array_almost_equal(flow_inc_lst, wasp_inc)
    npt.assert_array_almost_equal(tke_lst, np.array(wasp_ti) / 100)

    # compare pdf, u_mean and aep to wasp
    WD, WS, TI, P = site.local_wind(x, np.array(y) + 1e-6, 30, wd=np.arange(0, 360, 30), ws=ws)
    P = P / f_lst[na, :, na]  # only wind speed probablity (not wdir)

    # pdf
    for i in range(12):
        npt.assert_array_almost_equal(np.interp(ws, WS[0, i], np.cumsum(P[0, i])),
                                      np.cumsum(pdf_lst[i](ws)), 1)

    # u_mean
    npt.assert_almost_equal([A * math.gamma(1 + 1 / k) for A, k in zip(A_lst, k_lst)], wasp_u_mean, 5)
    npt.assert_almost_equal([(pdf(ws) * ws).sum() for pdf in pdf_lst], wasp_u_mean, 5)
    npt.assert_almost_equal((P * WS).sum((0, 2)), wasp_u_mean, 5)

    # air power
    p_air = [(pdf(ws) * 1 / 2 * rho * ws**3).sum() for pdf in pdf_lst]
    npt.assert_array_almost_equal(p_air, wasp_p_air, 3)
    npt.assert_array_almost_equal((P * 1 / 2 * rho * WS**3).sum((0, 2)), wasp_p_air, 2)

    # AEP
    AEP_ilk = AEPCalculator(wake_model=NOJ(site, wt)).calculate_AEP_no_wake_loss(
        x_i=x, y_i=y, h_i=30, wd=np.arange(0, 360, 30), ws=ws)

#     import matplotlib.pyplot as plt
#     #plt.plot(wasp_aep_no_density_correction, '.-')
#     #plt.plot(AEP_ilk.sum((0, 2)) * 1e6)
#     plt.plot(wasp_aep_no_density_correction - AEP_ilk.sum((0, 2)) * 1e6)
#     plt.plot(np.array(wasp_inc) * 100)
#     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)


def test_probability(site):
    x, y = site.initial_position[:1].T

    ws = site.local_wind(x_i=x, y_i=y, h_i=[70], wd=[0], ws=[10])[1][:, 0, 0]

    if 0:
        import matplotlib.pyplot as plt
        # plt.plot(ws, z, '.-')
        # plt.show()


@pytest.mark.parametrize('site,dw_ref', [
    (ParqueFicticioSite(distance=TerrainFollowingDistance2()),
Mikkel Friis-Møller's avatar
Mikkel Friis-Møller committed
     [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):
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    x, y = site.initial_position.T
    dw_ijl, cw_ijl, dh_ijl, dwo = 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)

    cw_ref = [236.1, 0., -131.1, -167.8, -204.5, -131.1, -131.1, -45.4]
    npt.assert_almost_equal(cw_ijl[:, 1, 0], cw_ref)
    npt.assert_almost_equal(dh_ijl, np.zeros_like(dh_ijl))


def test_distances_different_points(site2):
    site, x, y = site2
    with pytest.raises(NotImplementedError):
        site.distances(src_x_i=x, src_y_i=y, src_h_i=np.array([70]),
                       dst_x_j=x[1:], dst_y_j=y[1:], dst_h_j=np.array([70]),
                       wd_il=np.array([[0]]))


# def test_distances_wd_shape():
#     site = ParqueFicticioSite(distance=TerrainFollowingDistance2())
#     x, y = site.initial_position.T
#     dw_ijl, cw_ijl, dh_ijl, dwo = 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.ones((len(x), 1)) * 180)
#     npt.assert_almost_equal(dw_ijl[0, :, 0], np.array([0., -207., -477., -710., -1016., -1236., -1456., -1799.]))
#     npt.assert_almost_equal(cw_ijl[:, 1, 0], np.array([-236.1, 0., 131.1, 167.8, 204.5, 131.1, 131.1, 45.4]))
#     npt.assert_almost_equal(dh_ijl, np.zeros_like(dh_ijl))
Mads M. Pedersen's avatar
Mads M. Pedersen committed


def test_speed_up_using_pickle():
    pkl_fn = ParqueFicticio_path + "ParqueFicticio.pkl"
    if os.path.exists(pkl_fn):
        os.remove(pkl_fn)
    start = time.time()
    site = WaspGridSiteBase.from_wasp_grd(ParqueFicticio_path, speedup_using_pickle=False)
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    time_wo_pkl = time.time() - start
    site = WaspGridSiteBase.from_wasp_grd(ParqueFicticio_path, speedup_using_pickle=True)
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    assert os.path.exists(pkl_fn)
    start = time.time()
    site = WaspGridSiteBase.from_wasp_grd(ParqueFicticio_path, speedup_using_pickle=True)
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    time_w_pkl = time.time() - start
    npt.assert_array_less(time_w_pkl * 10, time_wo_pkl)


def test_interp_funcs_initialization_missing_key(site):
    site = ParqueFicticioSite(distance=TerrainFollowingDistance2())
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    site.interp_funcs_initialization(['missing'])


def test_one_layer():
    site = WaspGridSiteBase.from_wasp_grd(os.path.dirname(one_layer.__file__) + "/", speedup_using_pickle=False)
Mads M. Pedersen's avatar
Mads M. Pedersen committed


def test_missing_path():
    with pytest.raises(NotImplementedError):
        WaspGridSiteBase.from_wasp_grd("missing_path/", speedup_using_pickle=True)
Mads M. Pedersen's avatar
Mads M. Pedersen committed

    with pytest.raises(Exception, match='Path was not a directory'):
        WaspGridSiteBase.from_wasp_grd("missing_path/", speedup_using_pickle=False)
Mads M. Pedersen's avatar
Mads M. Pedersen committed


def test_elevation(site):
    x_i, y_i = site.initial_position.T
    npt.assert_array_less(np.abs(site.elevation(x_i=x_i, y_i=y_i) -
                                 [519.4, 567.7, 583.6, 600, 574.8, 559.9, 517.7, 474.5]  # ref from wasp
                                 ), 5)


def test_plot_map(site):
    import matplotlib.pyplot as plt
Mads M. Pedersen's avatar
Mads M. Pedersen committed
    with pytest.raises(AttributeError, match="missing not found in dataset. Available data variables are:\nflow_inc,"):
        site.plot_map('missing')

    with pytest.raises(AttributeError, match=r"Sector None not found. Available sectors are: \[ 1"):
        site.plot_map('ws_mean')
    with pytest.raises(AttributeError, match="Height missing for 'ws_mean'"):
        site.plot_map('ws_mean', sector=1)

    site.plot_map('elev')
    plt.figure()
    site.plot_map('ws_mean', 80, sector=1)
    if 0:
        plt.show()


def test_elevation_outside_map(site):
    import matplotlib.pyplot as plt

    site.plot_map('elev')
    x = np.linspace(262500, 265500, 500)
    y = x * 0 + 6505450
    plt.plot(x, y, '--', label='Terrain line')
    plt.plot(x, y + site.elevation(x, y), label='Elevation')
    npt.assert_array_equal(np.round(site.elevation(x, y)[::50]),
                           [np.nan, np.nan, 303, 390, 491, 566, 486, 524, np.nan, np.nan])
    if 0:
        plt.legend()
        plt.show()


Mads M. Pedersen's avatar
Mads M. Pedersen committed
def test_plot_ws_distribution(site):
    x, y = site.initial_position[0]
    p1 = site.plot_ws_distribution(x=x, y=y, h=70, wd=[0, 90, 180, 270])
    p2 = site.plot_ws_distribution(x=x, y=y, h=70, wd=[0, 90, 180, 270], include_wd_distribution=True)
    if 0:
        import matplotlib.pyplot as plt
        plt.show()

    # print(np.round(p1[::30], 4).tolist())
    npt.assert_array_almost_equal(p1[::30], [0.0001, 0.0042, 0.0072, 0.0077, 0.0063,
                                             0.0041, 0.0021, 0.0009, 0.0003, 0.0001], 4)
    # print(np.round(p2[::30], 4).tolist())
    npt.assert_array_almost_equal(p2[::30], [0.0001, 0.0021, 0.0033, 0.0033, 0.0025,
                                             0.0014, 0.0007, 0.0002, 0.0001, 0.0], 4)


def test_plot_wd_distribution(site):
    x, y = site.initial_position[0]
    import matplotlib.pyplot as plt
    p = site.plot_wd_distribution(x=x, y=y, h=70, n_wd=12, ax=plt)
    # print(np.round(p, 3).tolist())
    npt.assert_array_almost_equal(p, [0.052, 0.043, 0.058, 0.085, 0.089, 0.061,
                                      0.047, 0.083, 0.153, 0.152, 0.108, 0.068], 3)

    if 0:
        plt.show()


def test_plot_wd_distribution_with_ws_levels(site):
    x, y = site.initial_position[0]
    p = site.plot_wd_distribution(x=x, y=y, n_wd=12, ws_bins=[0, 5, 10, 15, 20, 25])
    # print(np.round(p, 3).tolist())
    npt.assert_array_almost_equal(p, [[0.031, 0.019, 0.003, 0.0, 0.0],
                                      [0.023, 0.018, 0.002, 0.0, 0.0],
                                      [0.018, 0.032, 0.007, 0.0, 0.0],
                                      [0.018, 0.048, 0.018, 0.001, 0.0],
                                      [0.024, 0.052, 0.014, 0.0, 0.0],
                                      [0.029, 0.031, 0.003, 0.0, 0.0],
                                      [0.023, 0.022, 0.002, 0.0, 0.0],
                                      [0.022, 0.041, 0.016, 0.002, 0.0],
                                      [0.023, 0.062, 0.048, 0.016, 0.003],
                                      [0.027, 0.058, 0.044, 0.018, 0.004],
                                      [0.034, 0.044, 0.023, 0.007, 0.001],
                                      [0.036, 0.026, 0.006, 0.001, 0.0]], 3)

    if 0:
        import matplotlib.pyplot as plt
        plt.show()
Mads M. Pedersen's avatar
Mads M. Pedersen committed


if __name__ == '__main__':
    test_wasp_resources_grid_point(ParqueFicticioSite())