def test_NOJ_Nibe_result(): # Replicate result from: Jensen, Niels Otto. "A note on wind generator interaction." (1983). site = UniformSite([1], 0.1) wake_model = NOJ(site, NibeA0) x_i = [0, 0, 0] y_i = [0, -40, -100] h_i = [50, 50, 50] WS_eff_ilk = wake_model.calc_wake(x_i, y_i, h_i, [0, 1, 1], 0.0, 8.1)[0] npt.assert_array_almost_equal(WS_eff_ilk[:, 0, 0], [8.1, 4.35, 5.7])
def test_NOJ_Nibe_result(): # Replicate result from: Jensen, Niels Otto. "A note on wind generator interaction." (1983). wake_model = NOJ(NibeA0) WS_ilk = np.array([[[8.1]], [[8.1]], [[8.1]]]) TI_ilk = np.zeros_like(WS_ilk) site = UniformSite([1], 0.1) dw_iil, cw_iil, dh_iil, dw_order_indices_l = site.wt2wt_distances( x_i=[0, 0, 0], y_i=[0, -40, -100], h_i=[50, 50, 50], wd_il=[[0]]) WS_eff_ilk = wake_model.calc_wake(WS_ilk, TI_ilk, dw_iil, cw_iil, dh_iil, dw_order_indices_l, [0, 1, 1])[0] npt.assert_array_almost_equal(WS_eff_ilk[:, 0, 0], [8.1, 4.35, 5.7])
def test_NOJ_two_turbines_in_row(wdir, x, y): # Two turbines in a row, North-South # Replicate result from: Jensen, Niels Otto. "A note on wind generator interaction." (1983). windTurbines = NibeA0 site = UniformSite([1], 0.1) wake_model = NOJ(site, windTurbines) h_i = [50, 50, 50] WS_eff_ilk = wake_model.calc_wake(x, y, h_i, [0, 0, 0], wdir, 8.1)[0] ws_wt3 = 8.1 - np.hypot(8.1 * 2 / 3 * (20 / 26)**2, 8.1 * 2 / 3 * (20 / 30)**2) npt.assert_array_almost_equal(WS_eff_ilk[:, 0, 0], [8.1, 4.35, ws_wt3])
def test_NOJ_6_turbines_in_row(): n_wt = 6 x = [0] * n_wt y = -np.arange(n_wt) * 40 * 2 site = UniformSite([1], 0.1) wake_model = NOJ(site, NibeA0) WS_eff_ilk = wake_model.calc_wake(x, y, [50] * n_wt, [0.0] * n_wt, 0.0, 11.0)[0] np.testing.assert_array_almost_equal( WS_eff_ilk[1:, 0, 0], 11 - np.sqrt( np.cumsum( ((11 * 2 / 3 * 20**2)**2) / (20 + 8 * np.arange(1, 6))**4)))
def test_NOJ_two_turbines_in_row(wdir, x, y): # Two turbines in a row, North-South # Replicate result from: Jensen, Niels Otto. "A note on wind generator interaction." (1983). windTurbines = NibeA0 wake_model = NOJ(windTurbines) WS_ilk = np.array([[[8.1]], [[8.1]], [[8.1]]]) TI_ilk = np.zeros_like(WS_ilk) site = UniformSite([1], 0.1) dw_iil, cw_iil, dh_iil, dw_order_indices_l = site.wt2wt_distances(x_i=x, y_i=y, h_i=[50, 50, 50], wd_il=[[wdir]]) WS_eff_ilk = wake_model.calc_wake(WS_ilk, TI_ilk, dw_iil, cw_iil, dh_iil, dw_order_indices_l, [0, 0, 0])[0] ws_wt3 = 8.1 - np.sqrt((8.1 * 2 / 3 * (20 / 26)**2)**2 + (8.1 * 2 / 3 * (20 / 30)**2)**2) npt.assert_array_almost_equal(WS_eff_ilk[:, 0, 0], [8.1, 4.35, ws_wt3])
def test_wake_map(): site = IEA37Site(16) x, y = site.initial_position.T windTurbines = IEA37_WindTurbines(iea37_path + 'iea37-335mw.yaml') wake_model = NOJ(site, windTurbines) aep = AEPCalculator(wake_model) x_j = np.linspace(-1500, 1500, 200) y_j = np.linspace(-1500, 1500, 100) X, Y, Z = aep.wake_map(x_j, y_j, 110, x, y, wd=[0], ws=[9]) if 0: import matplotlib.pyplot as plt c = plt.contourf(X, Y, Z) # , np.arange(2, 10, .01)) plt.colorbar(c) windTurbines.plot(x, y) plt.show() ref = [ 3.27, 3.27, 9.0, 7.46, 7.46, 7.46, 7.46, 7.31, 7.31, 7.31, 7.31, 8.3, 8.3, 8.3, 8.3, 8.3, 8.3 ] npt.assert_array_almost_equal(Z[49, 100:133:2], ref, 2)
def test_NOJ_6_turbines_in_row(): n_wt = 6 x = [0] * n_wt y = - np.arange(n_wt) * 40 * 2 wake_model = NOJ(NibeA0) site = UniformSite([1], .1) WD_ilk, WS_ilk, _, _ = site.local_wind(x_i=x, y_i=y, wd=[0], ws=[11]) TI_ilk = np.zeros_like(WS_ilk) site = UniformSite([1], 0.1) dw_iil, cw_iil, dh_iil, dw_order_indices_l = site.wt2wt_distances( x_i=x, y_i=y, h_i=[50] * n_wt, wd_il=WD_ilk.mean(2)) WS_eff_ilk = wake_model.calc_wake(WS_ilk, TI_ilk, dw_iil, cw_iil, dh_iil, dw_order_indices_l, [0] * n_wt)[0] np.testing.assert_array_almost_equal( WS_eff_ilk[1:, 0, 0], 11 - np.sqrt(np.cumsum(((11 * 2 / 3 * 20**2)**2) / (20 + 8 * np.arange(1, 6))**4)))
def test_distance_over_rectangle(): x, y = [-100, 50], [200, -100] windTurbines = IEA37_WindTurbines() site = Rectangle(height=200, width=100, distance_resolution=100) wake_model = NOJ(site, windTurbines) aep = AEPCalculator(wake_model) x_j = np.linspace(-100, 500, 100) y_j = np.linspace(-200, 300, 100) X, Y, Z = aep.wake_map(x_j, y_j, 110, x, y, wd=[270], ws=[9]) my = np.argmin(np.abs(Y[:, 0] - 200)) my2 = np.argmin(np.abs(Y[:, 0] + 100)) if 0: import matplotlib.pyplot as plt c = plt.contourf(X, Y, Z, cmap='Blues_r', levels=100) # , np.arange(2, 10, .01)) plt.colorbar(c) windTurbines.plot(x, y) H = site.elevation(X, Y) plt.plot(X[my], Z[my] * 10, label='wsp*10') plt.plot(X[my2], Z[my2] * 10, label='wsp*10') plt.contour(X, Y, H) plt.plot(X[my, :50:4], Z[my, :50:4] * 10, '.') plt.plot(x_j, site.elevation(x_j, x_j * 0), label='terrain level') plt.legend() plt.show() ref = [ 9., 3.42, 3.8, 6.02, 6.17, 6.31, 6.43, 7.29, 7.35, 7.41, 7.47, 7.53, 7.58 ] npt.assert_array_almost_equal(Z[my, :50:4], ref, 2)
def test_twotype_windturbines(): from py_wake.wind_turbines import WindTurbines v80 = V80() def power(ws, types): power = v80.power(ws) # add 10% type 1 turbines power[types == 1] *= 1.1 return power wts = WindTurbines(names=['V80', 'V88'], diameters=[80, 88], hub_heights=[70, 77], ct_funcs=[v80.ct_funcs[0], v80.ct_funcs[0]], power_funcs=[v80.power, lambda ws: v80.power(ws) * 1.1], power_unit='w') import matplotlib.pyplot as plt types0 = [0] * 9 types1 = [0, 0, 0, 1, 1, 1, 0, 0, 0] types2 = [1] * 9 wts.plot(wt9_x, wt9_y, types1) aep_calculator = AEPCalculator(NOJ(Hornsrev1Site(), wts)) npt.assert_almost_equal( aep_calculator.calculate_AEP(wt9_x, wt9_y, type_i=types0).sum(), 81.2066072392765) npt.assert_almost_equal( aep_calculator.calculate_AEP(wt9_x, wt9_y, type_i=types1).sum(), 83.72420504573488) npt.assert_almost_equal( aep_calculator.calculate_AEP(wt9_x, wt9_y, type_i=types2).sum(), 88.87227386796884) if 0: plt.show()
def run_NOJ(): windTurbines = IEA37_WindTurbines() site = IEA37Site(64) wake_model = NOJ(windTurbines) aep_calculator = AEPCalculator(site, windTurbines, wake_model) x, y = site.initial_position.T print(aep_calculator.calculate_AEP(x, y).sum())
def main(): if __name__ == '__main__': import matplotlib.pyplot as plt wt = HornsrevV80() wt.plot(wt_x, wt_y) aep_calculator = AEPCalculator(Hornsrev1Site(), wt, NOJ(wt)) print('AEP', aep_calculator.calculate_AEP(wt_x, wt_y)[0].sum()) plt.show()
def test_wake_model(): _, _, freq = read_iea37_windrose(iea37_path + "iea37-windrose.yaml") site = UniformSite(freq, ti=0.75) windTurbines = IEA37_WindTurbines(iea37_path + 'iea37-335mw.yaml') wake_model = NOJ(windTurbines) aep = AEPCalculator(site, windTurbines, wake_model) with pytest.raises(ValueError, match="Turbines 0 and 1 are at the same position"): aep.calculate_AEP([0, 0], [0, 0], wd=np.arange(0, 360, 22.5), ws=[9.8])
def test_smart_start_aep_map(): site = IEA37Site(16) n_wt = 4 np.random.seed(1) x, y = site.initial_position[:n_wt].T wd_lst = np.arange(0, 360, 45) ws_lst = [10] turbines = hornsrev1.HornsrevV80() site = UniformSite([1], .75) site.default_ws = ws_lst site.default_wd = wd_lst aep = PyWakeAEP(site=site, windTurbines=turbines, wake_model=NOJ(turbines)) aep_1wt = aep.calculate_AEP([0], [0]).sum() tf = TopFarmProblem(design_vars={ 'x': x, 'y': y }, cost_comp=aep.get_TopFarm_cost_component(n_wt), driver=EasyScipyOptimizeDriver(), constraints=[ SpacingConstraint(160), CircleBoundaryConstraint((0, 0), 500) ]) x = np.arange(-500, 500, 10) y = np.arange(-500, 500, 10) XX, YY = np.meshgrid(x, y) tf.smart_start(XX, YY, aep.get_aep4smart_start(wd=wd_lst, ws=ws_lst), radius=40) tf.evaluate() if 0: wt_x, wt_y = tf['x'], tf['y'] for i, _ in enumerate(wt_x, 1): print(aep.calculate_AEP(wt_x[:i], wt_y[:i]).sum((1, 2))) X_j, Y_j, aep_map = aep.aep_map(x, y, 0, wt_x, wt_y, ws=ws_lst, wd=wd_lst) print(tf.evaluate()) import matplotlib.pyplot as plt c = plt.contourf(X_j, Y_j, aep_map, 100) plt.colorbar(c) plt.plot(wt_x, wt_y, '2r') for c in tf.model.constraint_components: c.plot() plt.axis('equal') plt.show() npt.assert_almost_equal(aep_1wt * n_wt, tf['AEP'], 5)
def test_aep_no_wake_loss_hornsrev(): wt = hornsrev1.V80() x, y = hornsrev1.wt_x, hornsrev1.wt_y site = UniformWeibullSite([1], [10], [2], .75) site.default_ws = np.arange(3, 25) aep = AEPCalculator(site, wt, NOJ(wt)) npt.assert_almost_equal(aep.calculate_AEP_no_wake_loss(x, y).sum() / 80, 8.260757098) cap_factor = aep.calculate_AEP(x, y).sum() / aep.calculate_AEP_no_wake_loss(x, y).sum() # print(cap_factor) npt.assert_almost_equal(cap_factor, 0.947175839142014)
def test_NOJ_Nibe_result_wake_map(): # Replicate result from: Jensen, Niels Otto. "A note on wind generator interaction." (1983). def ct_func(_): return 8 / 9 def power_func(*_): return 0 windTurbines = NibeA0 wake_model = NOJ(windTurbines) site = UniformSite([1], 0.1) aep = AEPCalculator(site, windTurbines, wake_model) _, _, WS_eff_yx = aep.wake_map(x_j=[0], y_j=[0, -40, -100], h=50, wt_x=[0], wt_y=[0], wd=[0], ws=[8.1]) npt.assert_array_almost_equal(WS_eff_yx[:, 0], [8.1, 4.35, 5.7])
def main(): if __name__ == '__main__': site = WaspGridSiteBase.from_wasp_grd(ParqueFicticio_path, speedup_using_pickle=False) site.initial_position = np.array([ [263655.0, 6506601.0], [263891.1, 6506394.0], [264022.2, 6506124.0], [264058.9, 6505891.0], [264095.6, 6505585.0], [264022.2, 6505365.0], [264022.2, 6505145.0], [263936.5, 6504802.0], ]) windTurbines = IEA37_WindTurbines() wake_model = NOJ(site, windTurbines) x, y = site.initial_position.T aep_calculator = AEPCalculator(wake_model) print(aep_calculator.calculate_AEP(x, y).sum())
def test_wake_map(): _, _, freq = read_iea37_windrose(iea37_path + "iea37-windrose.yaml") n_wt = 16 x, y, _ = read_iea37_windfarm(iea37_path + 'iea37-ex%d.yaml' % n_wt) site = UniformSite(freq, ti=0.75) windTurbines = IEA37_WindTurbines(iea37_path + 'iea37-335mw.yaml') wake_model = NOJ(windTurbines) aep = AEPCalculator(site, windTurbines, wake_model) x_j = np.linspace(-1500, 1500, 200) y_j = np.linspace(-1500, 1500, 100) X, Y, Z = aep.wake_map(x_j, y_j, 110, x, y, wd=[0], ws=[9]) if 0: import matplotlib.pyplot as plt c = plt.contourf(X, Y, Z) # , np.arange(2, 10, .01)) plt.colorbar(c) site.plot_windturbines(x, y) plt.show() ref = [3.27, 3.27, 9.0, 7.46, 7.46, 7.46, 7.46, 7.31, 7.31, 7.31, 7.31, 8.3, 8.3, 8.3, 8.3, 8.3, 8.3] npt.assert_array_almost_equal(Z[49, 100:133:2], ref, 2)
def test_wake_map(): site = IEA37Site(16) x, y = site.initial_position.T windTurbines = IEA37_WindTurbines() wake_model = NOJ(site, windTurbines) aep = AEPCalculator(wake_model) x_j = np.linspace(-1500, 1500, 200) y_j = np.linspace(-1500, 1500, 100) X, Y, Z = aep.wake_map(x_j, y_j, 110, x, y, wd=[0], ws=[9]) m = 49, slice(100, 133, 2) # print(np.round(Z[m], 2).tolist()) # ref if 0: import matplotlib.pyplot as plt c = plt.contourf(X, Y, Z) # , np.arange(2, 10, .01)) plt.colorbar(c) windTurbines.plot(x, y) plt.plot(X[m], Y[m], '.-r') plt.show() ref = [ 3.27, 3.27, 9.0, 7.46, 7.46, 7.46, 7.46, 7.31, 7.31, 7.31, 7.31, 8.3, 8.3, 8.3, 8.3, 8.3, 8.3 ] npt.assert_array_almost_equal(Z[m], ref, 2)
def test_aep_no_wake(): site = UniformWeibullSite([1], [10], [2], .75) V80 = hornsrev1.V80() aep = AEPCalculator(NOJ(site, V80)) npt.assert_almost_equal( aep.calculate_AEP([0], [0], ws=np.arange(3, 25)).sum(), 8.260757098, 9)
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) if 0: import matplotlib.pyplot as plt plt.plot(wasp_aep_no_density_correction / 1000, '.-', label='WAsP') plt.plot(AEP_ilk.sum((0, 2)) * 1e3, label='PyWake') plt.xlabel('Sector') plt.ylabel('AEP [MWh]') plt.legend() 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 setup_prob(differentiable): ##################################### ## Setup Floris run with gradients ## ##################################### topfarm.x_key = 'turbineX' topfarm.y_key = 'turbineY' turbineX = np.array( [1164.7, 947.2, 1682.4, 1464.9, 1982.6, 2200.1]) turbineY = np.array( [1024.7, 1335.3, 1387.2, 1697.8, 2060.3, 1749.7]) f = np.array([ 3.597152, 3.948682, 5.167395, 7.000154, 8.364547, 6.43485, 8.643194, 11.77051, 15.15757, 14.73792, 10.01205, 5.165975 ]) wind_speed = 8 site = Amalia1Site(f, mean_wsp=wind_speed) site.initial_position = np.array([turbineX, turbineY]).T wt = NREL5MWREF() wake_model = NOJ(site, wt) aep_calculator = AEPCalculator(wake_model) n_wt = len(turbineX) differentiable = differentiable wake_model_options = { 'nSamples': 0, 'nRotorPoints': 1, 'use_ct_curve': True, 'ct_curve': ct_curve, 'interp_type': 1, 'differentiable': differentiable, 'use_rotor_components': False } aep_comp = AEPGroup( n_wt, differentiable=differentiable, use_rotor_components=False, wake_model=floris_wrapper, params_IdepVar_func=add_floris_params_IndepVarComps, wake_model_options=wake_model_options, datasize=len(power_curve), nDirections=len(f), cp_points=len(power_curve)) # , cp_curve_spline=None) def cost_func(AEP, **kwargs): return AEP cost_comp = CostModelComponent(input_keys=[('AEP', [0])], n_wt=n_wt, cost_function=cost_func, output_key="aep", output_unit="kWh", objective=True, income_model=True, input_units=['kW*h']) group = TopFarmGroup([aep_comp, cost_comp]) boundary = np.array([(900, 1000), (2300, 1000), (2300, 2100), (900, 2100)]) # turbine boundaries prob = TopFarmProblem( design_vars={ 'turbineX': (turbineX, 'm'), 'turbineY': (turbineY, 'm') }, cost_comp=group, driver=EasyRandomSearchDriver( randomize_func=RandomizeTurbinePosition_Square(), max_iter=500), # driver=EasyScipyOptimizeDriver(optimizer='SLSQP',tol=10**-12), # driver=EasyScipyOptimizeDriver(optimizer='COBYLA'), constraints=[ SpacingConstraint(200, units='m'), XYBoundaryConstraint(boundary, units='m') ], plot_comp=plot_comp, expected_cost=-100e2, ) turbineZ = np.array([90.0, 100.0, 90.0, 80.0, 70.0, 90.0]) air_density = 1.1716 # kg/m^3 rotorDiameter = np.zeros(n_wt) hubHeight = np.zeros(n_wt) axialInduction = np.zeros(n_wt) generatorEfficiency = np.zeros(n_wt) yaw = np.zeros(n_wt) for turbI in range(0, n_wt): rotorDiameter[turbI] = wt.diameter() # m hubHeight[turbI] = wt.hub_height() # m axialInduction[turbI] = 1.0 / 3.0 generatorEfficiency[turbI] = 1.0 # 0.944 yaw[turbI] = 0. # deg. prob['turbineX'] = turbineX prob['turbineY'] = turbineY prob['hubHeight'] = turbineZ prob['yaw0'] = yaw prob['rotorDiameter'] = rotorDiameter prob['hubHeight'] = hubHeight prob['axialInduction'] = axialInduction prob['generatorEfficiency'] = generatorEfficiency prob['windSpeeds'] = np.ones(len(f)) * wind_speed prob['air_density'] = air_density prob['windDirections'] = np.arange(0, 360, 360 / len(f)) prob['windFrequencies'] = f / 100 # turns off cosine spread (just needs to be very large) prob['model_params:cos_spread'] = 1E12 prob['model_params:shearExp'] = 0.25 prob['model_params:z_ref'] = 80. prob['model_params:z0'] = 0. prob['rated_power'] = np.ones(n_wt) * 5000. prob['cut_in_speed'] = np.ones(n_wt) * 3 prob['cp_curve_wind_speed'] = cp_curve[:, 0] prob['cp_curve_cp'] = cp_curve[:, 1] prob['rated_wind_speed'] = np.ones(n_wt) * 11.4 prob['cut_out_speed'] = np.ones(n_wt) * 25.0 # if 0: # prob.check_partials(compact_print=True,includes='*direction_group0*') # else: return prob
def main(obj=False, max_con_on=True): # ------ DEFINE WIND TURBINE TYPES, LOCATIONS & STORE METADATA ------- windTurbines = WindTurbines( names=['Ghost_T1', 'T2'], diameters=[40, 84], hub_heights=[70, hornsrev1.HornsrevV80().hub_height()], ct_funcs=[dummy_thrust(ct_rated=0), hornsrev1.HornsrevV80()._ct], power_funcs=[cube_power(power_rated=0), cube_power(power_rated=3000)], # hornsrev1.HornsrevV80()._power], power_unit='kW') Drotor_vector = windTurbines._diameters power_rated_vec = np.array( [pcurv(25) / 1000 for pcurv in windTurbines.power_funcs]) hub_height_vector = windTurbines._hub_heights x, y = np.meshgrid(range(-840, 840, 420), range(-840, 840, 420)) n_wt = len(x.flatten()) # initial turbine positions and other independent variables ext_vars = {'x': x.flatten(), 'y': y.flatten(), 'obj': obj * 1} capconst = [] if max_con_on: capconst = [ CapacityConstraint(max_capacity=30.01, rated_power_array=power_rated_vec) ] # ---------------- DEFINE SITE & SELECT WAKE MODEL ------------------- # site = UniformWeibullSite(p_wd=[50, 50], a=[9, 9], k=[2.3, 2.3], ti=.1, alpha=0, h_ref=100) site = UniformWeibullSite(p_wd=[100], a=[9], k=[2.3], ti=.1) site.default_ws = [9] # reduce the number of calculations site.default_wd = [0] # reduce the number of calculations wake_model = NOJ(site, windTurbines) AEPCalc = AEPCalculator(wake_model) # ------------- OUTPUTS AEP PER TURBINE & FARM IRR ------------------- def aep_func( x, y, type, obj, **kwargs): # TODO fix type as input change to topfarm turbinetype out = AEPCalc.calculate_AEP(x_i=x, y_i=y, type_i=type).sum((1, 2)) if obj: # if objective is AEP; output the total Farm_AEP out = np.sum(out) return out * 10**6 def irr_func(aep, type, **kwargs): idx = type.astype(int) return economic_evaluation(Drotor_vector[idx], power_rated_vec[idx], hub_height_vector[idx], aep).calculate_irr() # ----- WRAP AEP AND IRR INTO TOPFARM COMPONENTS AND THEN GROUP ----- aep_comp = CostModelComponent(input_keys=[ topfarm.x_key, topfarm.y_key, topfarm.type_key, ('obj', obj) ], n_wt=n_wt, cost_function=aep_func, output_key="aep", output_unit="GWh", objective=obj, output_val=np.zeros(n_wt), income_model=True) comps = [aep_comp] # AEP component is always in the group if not obj: # if objective is IRR initiate/add irr_comp irr_comp = CostModelComponent(input_keys=[topfarm.type_key, 'aep'], n_wt=n_wt, cost_function=irr_func, output_key="irr", output_unit="%", objective=True) comps.append(irr_comp) group = TopFarmGroup(comps) # - INITIATE THE PROBLEM WITH ONLY TURBINE TYPE AS DESIGN VARIABLES - tf = TopFarmProblem( design_vars={ topfarm.type_key: ([0] * n_wt, 0, len(windTurbines._names) - 1) }, cost_comp=group, driver=EasyRandomSearchDriver(randomize_func=RandomizeAllUniform( [topfarm.type_key]), max_iter=1), # driver=EasySimpleGADriver(max_gen=2, random_state=1), constraints=capconst, # plot_comp=TurbineTypePlotComponent(windTurbines._names), plot_comp=NoPlot(), ext_vars=ext_vars) cost, state, rec = tf.optimize() # view_model(problem, outfile='ex5_n2.html', show_browser=False) end = time.time() print(end - start) # %% # ------------------- OPTIONAL VISUALIZATION OF WAKES ---------------- post_visual, save = False, False if post_visual: # import matplotlib.pyplot as plt for cou, (i, j, k, co, ae) in enumerate( zip(rec['x'], rec['y'], rec['type'], rec['cost'], rec['aep'])): AEPCalc.calculate_AEP(x_i=i, y_i=j, type_i=k) AEPCalc.plot_wake_map(wt_x=i, wt_y=j, wt_type=k, wd=site.default_wd[0], ws=site.default_ws[0], levels=np.arange(2.5, 12, .1)) windTurbines.plot(i, j, types=k) title = f'IRR: {-np.round(co,2)} %, AEP : {round(np.sum(ae))} GWh, ' if "totalcapacity" in rec.keys(): title += f'Total Capacity: {rec["totalcapacity"][cou]} MW' plt.title(title) if save: plt.savefig( r'..\..\..\ima2\obj_AEP_{}_MaxConstraint_{}_{}.png'.format( obj, max_con_on, cou)) plt.show()