Source code for floris.optimization.other.boundary_grid


import numpy as np
from shapely.geometry import Point, Polygon


[docs] def discontinuous_grid( nrows, ncols, farm_width, farm_height, shear, rotation, center_x, center_y, shrink_boundary, boundary_x, boundary_y, eps=1e-3, ): """ Map from grid design variables to turbine x and y locations. Includes integer design variables and the formulation results in a discontinous design space. TODO: shrink_boundary doesn't work well with concave boundaries, or with boundary angles less than 90 deg Args: nrows (Int): number of rows in the grid. ncols (Int): number of columns in the grid. farm_width (Float): total grid width (before shear). farm_height (Float): total grid height. shear (Float): grid shear (rad). rotation (Float): rotation about grid center (rad). center_x (Float): location of grid x center. center_y (Float): location of grid y center. shrink_boundary (Float): how much to shrink the boundary that the grid can occupy. boundary_x (Array(Float)): x boundary points. boundary_y (Array(Float)): y boundary points. Returns: grid_x (Array(Float)): turbine x locations. grid_y (Array(Float)): turbine y locations. """ # create grid nrows = int(nrows) ncols = int(ncols) xlocs = np.linspace(0.0, farm_width, ncols) ylocs = np.linspace(0.0, farm_height, nrows) y_spacing = ylocs[1] - ylocs[0] nturbs = nrows * ncols grid_x = np.zeros(nturbs) grid_y = np.zeros(nturbs) turb = 0 for i in range(nrows): for j in range(ncols): grid_x[turb] = xlocs[j] + float(i) * y_spacing * np.tan(shear) grid_y[turb] = ylocs[i] turb += 1 # rotate grid_x, grid_y = ( np.cos(rotation) * grid_x - np.sin(rotation) * grid_y, np.sin(rotation) * grid_x + np.cos(rotation) * grid_y, ) # move center of grid grid_x = (grid_x - np.mean(grid_x)) + center_x grid_y = (grid_y - np.mean(grid_y)) + center_y # arrange the boundary # boundary = np.zeros((len(boundary_x),2)) # boundary[:,0] = boundary_x[:] # boundary[:,1] = boundary_y[:] # poly = Polygon(boundary) # centroid = poly.centroid # boundary[:,0] = (boundary_x[:]-centroid.x)*boundary_mult + centroid.x # boundary[:,1] = (boundary_y[:]-centroid.y)*boundary_mult + centroid.y # poly = Polygon(boundary) boundary = np.zeros((len(boundary_x), 2)) boundary[:, 0] = boundary_x[:] boundary[:, 1] = boundary_y[:] poly = Polygon(boundary) if shrink_boundary != 0.0: nBounds = len(boundary_x) for i in range(nBounds): point = Point(boundary_x[i] + eps, boundary_y[i]) if poly.contains(point) is True or poly.touches(point) is True: boundary[i, 0] = boundary_x[i] + shrink_boundary else: boundary[i, 0] = boundary_x[i] - shrink_boundary point = Point(boundary_x[i], boundary_y[i] + eps) if poly.contains(point) is True or poly.touches(point) is True: boundary[i, 1] = boundary_y[i] + shrink_boundary else: boundary[i, 1] = boundary_y[i] - shrink_boundary poly = Polygon(boundary) # get rid of points outside of boundary index = 0 for i in range(len(grid_x)): point = Point(grid_x[index], grid_y[index]) if poly.contains(point) is False and poly.touches(point) is False: grid_x = np.delete(grid_x, index) grid_y = np.delete(grid_y, index) else: index += 1 return grid_x, grid_y
[docs] def place_boundary_turbines(n_boundary_turbs, start, boundary_x, boundary_y): """ Place turbines equally spaced traversing the perimiter if the wind farm along the boundary Args: n_boundary_turbs (Int): number of turbines to be placed on the boundary start (Float): where the first turbine should be placed boundary_x (Array(Float)): x boundary points boundary_y (Array(Float)): y boundary points Returns layout_x (Array(Float)): turbine x locations layout_y (Array(Float)): turbine y locations """ # check if the boundary is closed, correct if not if boundary_x[-1] != boundary_x[0] or boundary_y[-1] != boundary_y[0]: boundary_x = np.append(boundary_x, boundary_x[0]) boundary_y = np.append(boundary_y, boundary_y[0]) # make the boundary boundary = np.zeros((len(boundary_x), 2)) boundary[:, 0] = boundary_x[:] boundary[:, 1] = boundary_y[:] poly = Polygon(boundary) perimeter = poly.length # get the flattened turbine locations spacing = perimeter / float(n_boundary_turbs) flattened_locs = np.linspace(start, perimeter + start - spacing, n_boundary_turbs) # set all of the flattened values between 0 and the perimeter for i in range(n_boundary_turbs): while flattened_locs[i] < 0.0: flattened_locs[i] += perimeter if flattened_locs[i] > perimeter: flattened_locs[i] = flattened_locs[i] % perimeter # place the turbines around the perimeter nBounds = len(boundary_x) layout_x = np.zeros(n_boundary_turbs) layout_y = np.zeros(n_boundary_turbs) lenBound = np.zeros(nBounds - 1) for i in range(nBounds - 1): lenBound[i] = Point(boundary[i]).distance(Point(boundary[i + 1])) for i in range(n_boundary_turbs): for j in range(nBounds - 1): if flattened_locs[i] < sum(lenBound[0 : j + 1]): layout_x[i] = ( boundary_x[j] + (boundary_x[j + 1] - boundary_x[j]) * (flattened_locs[i] - sum(lenBound[0:j])) / lenBound[j] ) layout_y[i] = ( boundary_y[j] + (boundary_y[j + 1] - boundary_y[j]) * (flattened_locs[i] - sum(lenBound[0:j])) / lenBound[j] ) break return layout_x, layout_y
[docs] def boundary_grid( n_boundary_turbs, start, nrows, ncols, farm_width, farm_height, shear, rotation, center_x, center_y, shrink_boundary, boundary_x, boundary_y, eps=1e-3, ): """ Place turbines equally spaced traversing the perimiter if the wind farm along the boundary Args: n_boundary_turbs,start: boundary variables nrows,ncols,farm_width,farm_height,shear, rotation,center_x,center_y,shrink_boundary,eps: grid variables boundary_x,boundary_y: boundary points Returns layout_x (Array(Float)): turbine x locations layout_y (Array(Float)): turbine y locations """ boundary_turbines_x, boundary_turbines_y = place_boundary_turbines( n_boundary_turbs, start, boundary_x, boundary_y ) grid_turbines_x, grid_turbines_y = discontinuous_grid( nrows, ncols, farm_width, farm_height, shear, rotation, center_x, center_y, shrink_boundary, boundary_x, boundary_y, eps=eps, ) layout_x = np.append(boundary_turbines_x, grid_turbines_x) layout_y = np.append(boundary_turbines_y, grid_turbines_y) return layout_x, layout_y
[docs] class BoundaryGrid: """ Parameterize the wind farm layout with a grid or the boundary grid method """ def __init__(self, fi): """ Initializes a BoundaryGrid object by assigning a FlorisModel object. Args: fmodel (FlorisModel): A FlorisModel object. """ self.fmodel = fi self.n_boundary_turbs = 0 self.start = 0.0 self.nrows = 0 self.ncols = 0 self.farm_width = 0.0 self.farm_height = 0.0 self.shear = 0.0 self.rotation = 0.0 self.center_x = 0.0 self.center_y = 0.0 self.shrink_boundary = 0.0 self.boundary_x = np.array([]) self.boundary_y = np.array([]) self.eps = 1e-3
[docs] def reinitialize_bg( self, n_boundary_turbs=None, start=None, nrows=None, ncols=None, farm_width=None, farm_height=None, shear=None, rotation=None, center_x=None, center_y=None, shrink_boundary=None, boundary_x=None, boundary_y=None, eps=None, ): if n_boundary_turbs is not None: self.n_boundary_turbs = n_boundary_turbs if start is not None: self.start = start if nrows is not None: self.nrows = nrows if ncols is not None: self.ncols = ncols if farm_width is not None: self.farm_width = farm_width if farm_height is not None: self.farm_height = farm_height if shear is not None: self.shear = shear if rotation is not None: self.rotation = rotation if center_x is not None: self.center_x = center_x if center_y is not None: self.center_y = center_y if shrink_boundary is not None: self.shrink_boundary = shrink_boundary if boundary_x is not None: self.boundary_x = boundary_x if boundary_y is not None: self.boundary_y = boundary_y if eps is not None: self.eps = eps
[docs] def reinitialize_xy(self): layout_x, layout_y = boundary_grid( self.n_boundary_turbs, self.start, self.nrows, self.ncols, self.farm_width, self.farm_height, self.shear, self.rotation, self.center_x, self.center_y, self.shrink_boundary, self.boundary_x, self.boundary_y, eps=self.eps, ) self.fmodel.reinitialize_flow_field(layout_array=(layout_x, layout_y))
if __name__ == "__main__": nrows = 10 ncols = 10 farm_width = 600 farm_height = 600 shear = np.deg2rad(10) rotation = np.deg2rad(30) center_x = 250 center_y = 300 boundary_mult = 0.6 shrink_boundary = 10.0 # boundary_x = np.array([-300.0,-100.0,100.0,100.0,0.0]) + 2200.0 # boundary_y = np.array([-100.0,100.0,140.0,-100.0,0.0]) + 300.0 boundary_x = np.array( [0.0, 100.0, 100.0, 200.0, 200.0, 300.0, 300.0, 400.0, 400.0, 500.0, 500.0, 0.0] ) boundary_y = np.array( [ 500.0, 500.0, 400.0, 400.0, 300.0, 300.0, 200.0, 200.0, 100.0, 100.0, 600.0, 600.0, ] ) x, y = discontinuous_grid( nrows, ncols, farm_width, farm_height, shear, rotation, center_x, center_y, shrink_boundary, boundary_x, boundary_y, ) n_boundary_turbs = 25 start = 1000.0 layout_x, layout_y = place_boundary_turbines( n_boundary_turbs, start, boundary_x, boundary_y ) bx = np.append(boundary_x, boundary_x[0]) by = np.append(boundary_y, boundary_y[0]) boundary = np.zeros((len(bx), 2)) boundary[:, 0] = bx[:] boundary[:, 1] = by[:] poly = Polygon(boundary) # centroid = poly.centroid # new_bx = (bx[:]-centroid.x)*boundary_mult + centroid.x # new_by = (by[:]-centroid.y)*boundary_mult + centroid.y nBounds = len(bx) new_bx = np.zeros(len(bx)) new_by = np.zeros(len(by)) eps = 1e-3 for i in range(nBounds): point = Point(bx[i] + eps, by[i]) if poly.contains(point) is True or poly.touches(point) is True: new_bx[i] = bx[i] + shrink_boundary else: new_bx[i] = bx[i] - shrink_boundary point = Point(bx[i], by[i] + eps) if poly.contains(point) is True or poly.touches(point) is True: new_by[i] = by[i] + shrink_boundary else: new_by[i] = by[i] - shrink_boundary import matplotlib.pyplot as plt nx, ny = boundary_grid( n_boundary_turbs, start, nrows, ncols, farm_width, farm_height, shear, rotation, center_x, center_y, shrink_boundary, boundary_x, boundary_y, ) plt.plot(bx, by) plt.plot(new_bx, new_by) plt.plot(x, y, "o") plt.plot(layout_x, layout_y, "o") plt.axis("equal") plt.figure(2) plt.plot(bx, by) plt.plot(nx, ny, "o") plt.axis("equal") plt.show()