def test_local_wind(site): x_i = y_i = np.arange(5) wdir_lst = np.arange(0, 360, 90) wsp_lst = np.arange(3, 6) lw = site.local_wind(x_i=x_i, y_i=y_i, wd=wdir_lst, ws=wsp_lst) npt.assert_array_equal(lw.WS_ilk.shape, (5, 4, 3)) lw = site.local_wind(x_i=x_i, y_i=y_i) npt.assert_array_equal(lw.WS_ilk.shape, (5, 360, 23)) # check probability local_wind()[-1] npt.assert_equal(site.local_wind(x_i=x_i, y_i=y_i, wd=[0], ws=[10], wd_bin_size=1).P_ilk, site.local_wind(x_i=x_i, y_i=y_i, wd=[0], ws=[10], wd_bin_size=2).P_ilk / 2) npt.assert_almost_equal(site.local_wind(x_i=x_i, y_i=y_i, wd=[0], ws=[9, 10, 11]).P_ilk.sum((1, 2)), site.local_wind(x_i=x_i, y_i=y_i, wd=[0], ws=[10], ws_bins=3).P_ilk[:, 0, 0], 5) z = np.arange(1, 100) zero = [0] * len(z) ws = site.local_wind(x_i=zero, y_i=zero, h_i=z, wd=[0], ws=[10]).WS_ilk[:, 0, 0] site2 = UniformWeibullSite(f, A, k, ti, shear=PowerShear(70, alpha=np.zeros_like(f) + .3)) ws70 = site2.local_wind(x_i=zero, y_i=zero, h_i=z, wd=[0], ws=[10]).WS_ilk[:, 0, 0] if 0: import matplotlib.pyplot as plt plt.plot(ws, z) plt.plot(ws70, z) plt.show() npt.assert_array_equal(10 * (z / 50)**.3, ws) npt.assert_array_equal(10 * (z / 70)**.3, ws70)
def __init__(self): f = [3.597152, 3.948682, 5.167395, 7.000154, 8.364547, 6.43485, 8.643194, 11.77051, 15.15757, 14.73792, 10.01205, 5.165975] a = [9.176929, 9.782334, 9.531809, 9.909545, 10.04269, 9.593921, 9.584007, 10.51499, 11.39895, 11.68746, 11.63732, 10.08803] k = [2.392578, 2.447266, 2.412109, 2.591797, 2.755859, 2.595703, 2.583984, 2.548828, 2.470703, 2.607422, 2.626953, 2.326172] UniformWeibullSite.__init__(self, f, a, k, .1) self.initial_position = np.array([wt_x, wt_y]).T
def __init__(self): f = [ 5.55, 5.13, 5.32, 7.63, 9.39, 7.14, 8.93, 12.22, 14.44, 13.66, 5.87, 4.72 ] a = [9.42] * 12 k = [2.41] * 12 UniformWeibullSite.__init__(self, f, a, k, .1) self.initial_position = np.array([wt_x, wt_y]).T
def __init__(self): f = [3.8, 4.5, 0.4, 2.8, 8.3, 7.5, 9.9, 14.8, 14.3, 17.0, 12.6, 4.1] a = [4.5, 4.7, 3.0, 7.2, 8.8, 8.2, 8.4, 9.5, 9.2, 9.9, 10.3, 6.7] k = [ 1.69, 1.78, 1.82, 1.70, 1.97, 2.49, 2.72, 2.70, 2.88, 3.34, 2.84, 2.23 ] UniformWeibullSite.__init__(self, f, a, k, .1) self.initial_position = np.array([wt_x, wt_y]).T
def test_plot_wd_distribution(site): import matplotlib.pyplot as plt site.plot_wd_distribution(n_wd=12, ax=plt) plt.figure() site.plot_wd_distribution(n_wd=12, ax=plt.gca()) plt.figure() site.plot_wd_distribution(n_wd=360) UniformWeibullSite(f, A, k, ti, 'spline').plot_wd_distribution(n_wd=360) UniformWeibullSite(f, A, k, ti, 'linear').plot_wd_distribution(n_wd=360) if 0: plt.show()
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_plot_wd_distribution(site): import matplotlib.pyplot as plt p1 = site.plot_wd_distribution(n_wd=12, ax=plt) npt.assert_array_almost_equal(p1, f, 4) plt.figure() site.plot_wd_distribution(n_wd=12, ax=plt.gca()) plt.figure() p2 = site.plot_wd_distribution(n_wd=360) npt.assert_array_almost_equal(np.array(p2)[::30] * 30, f, 4) UniformWeibullSite(f, A, k, ti, 'spline').plot_wd_distribution(n_wd=360) UniformWeibullSite(f, A, k, ti, 'linear').plot_wd_distribution(n_wd=360) if 0: plt.show()
def site(): return UniformWeibullSite(f, A, k, ti, shear=PowerShear(50, alpha=np.zeros_like(f) + .3))
def test_site(): with pytest.raises( NotImplementedError, match="interp_method=missing_method not implemeted yet."): site = UniformWeibullSite([1], [10], [2], .75, interp_method='missing_method')
def test_missing_interp_method(): with pytest.raises( AssertionError, match= 'interp_method "missing_method" not implemented. Must be "linear" or "nearest"' ): site = UniformWeibullSite([1], [10], [2], .75, interp_method='missing_method')
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 site(): return UniformWeibullSite(f, A, k, ti, h_ref=50, alpha=.3)
def main(obj=False, max_con_on=True): if __name__ == '__main__': start = time.time() try: import matplotlib.pyplot as plt plt.gcf() plot = True except RuntimeError: plot = False # ------ 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.astype(int)).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()
def main(): if __name__ == '__main__': try: import matplotlib.pyplot as plt plt.gcf() plot_comp = XYPlotComp plot = True except RuntimeError: plot_comp = NoPlot plot = False # ------------------------ INPUTS ------------------------ # ------------------------ DEFINE WIND RESOURCE ------------------------ # wind resource info (wdir frequency, weibull a and k) f = [ 3.597152, 3.948682, 5.167395, 7.000154, 8.364547, 6.43485, 8.643194, 11.77051, 15.15757, 14.73792, 10.01205, 5.165975 ] a = [ 9.176929, 9.782334, 9.531809, 9.909545, 10.04269, 9.593921, 9.584007, 10.51499, 11.39895, 11.68746, 11.63732, 10.08803 ] k = [ 2.392578, 2.447266, 2.412109, 2.591797, 2.755859, 2.595703, 2.583984, 2.548828, 2.470703, 2.607422, 2.626953, 2.326172 ] site = UniformWeibullSite(p_wd=f, a=a, k=k, ti=0.075) wt = V80() # ------------------------ setup problem ____--------------------------- rot_diam = 80.0 # rotor diameter [m] init_pos = np.array([(0, 2 * rot_diam), (0, 0), (0, -2 * rot_diam)]) # initial turbine positions b = 2 * rot_diam + 10 # boundary size boundary = [(-b, -b), (-b, b), (b, b), (b, -b)] # corners of wind farm boundary min_spacing = 2.0 * rot_diam # minimum spacing between turbines [m] # ------------------------ OPTIMIZATION ------------------------ def get_tf(windFarmModel): return TopFarmProblem(design_vars=dict(zip('xy', init_pos.T)), cost_comp=PyWakeAEPCostModelComponent( windFarmModel, n_wt=3, ws=10, wd=np.arange(0, 360, 12)), constraints=[ SpacingConstraint(min_spacing), XYBoundaryConstraint(boundary) ], driver=EasyScipyOptimizeDriver(), plot_comp=plot_comp()) # GCL: define the wake model and optimization problem tf_gcl = get_tf(GCL(site, wt)) # NOJ: define the wake model and optimization problem tf_noj = get_tf(NOJ(site, wt)) # run the optimization cost_gcl, state_gcl, recorder_gcl = tf_gcl.optimize() cost_noj, state_noj, recorder_noj = tf_noj.optimize() # ------------------------ POST-PROCESS ------------------------ # get the optimized locations opt_gcl = tf_gcl.turbine_positions opt_noj = tf_noj.turbine_positions # create the array of costs for easier printing costs = np.diag([cost_gcl, cost_noj]) costs[0, 1] = tf_noj.evaluate(state_gcl)[0] # noj cost of gcl locs costs[1, 0] = tf_gcl.evaluate(state_noj)[0] # gcl cost of noj locs # ------------------------ PRINT STATS ------------------------ aep_diffs = 200 * (costs[:, 0] - costs[:, 1]) / (costs[:, 0] + costs[:, 1]) loc_diffs = 200 * (costs[0, :] - costs[1, :]) / (costs[0, :] + costs[1, :]) print('\nComparison of cost models vs. optimized locations:') print('\nCost | GCL_aep NOJ_aep') print('---------------------------------') print(f'GCL_loc |{costs[0,0]:11.2f} {costs[0,1]:11.2f}' + f' ({aep_diffs[0]:.2f}%)') print(f'NOJ_loc |{costs[1,0]:11.2f} {costs[1,1]:11.2f}' + f' ({aep_diffs[1]:.2f}%)') print(f' ({loc_diffs[0]:.2f}%) ({loc_diffs[1]:.2f}%)') # ------------------------ PLOT (if possible) ------------------------ if plot: # initialize the figure and axes fig = plt.figure(1, figsize=(7, 5)) plt.clf() ax = plt.axes() # plot the boundary and desired locations ax.add_patch(Polygon(boundary, fill=False, label='Boundary')) # boundary ax.plot(init_pos[:, 0], init_pos[:, 1], 'xk', label='Initial') ax.plot(opt_gcl[:, 0], opt_gcl[:, 1], 'o', label='GCL') ax.plot(opt_noj[:, 0], opt_noj[:, 1], '^', label='NOJ') # make a few adjustments to the plot ax.autoscale_view() # autoscale the boundary plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=4, mode='expand', borderaxespad=0.) # add a legend plt.tight_layout() # zoom the plot in plt.axis('off') # remove the axis # save the png folder, file = os.path.split(__file__) fig.savefig(folder + "/figures/" + file.replace('.py', '.png'))