# Layout Optimization#

The FLORIS package provides layout optimization tools to place turbines within a specified
boundary area to optimize annual energy production (AEP) or wind plant value. Layout
optimizers accept an instantiated `FlorisModel`

and alter the turbine layouts in order to
improve the objective function value (AEP or value).

## Background#

Layout optimization entails placing turbines in a wind farm in a configuration that maximizes an objective function, usually the AEP. Turbines are moved to minimize their wake interactions in the most dominant wind directions, while respecting the boundaries of the area for turbine placement as well as minimum distance requirements between neighboring turbines.

Mathematically, we represent this as a (nonconvex) optimization problem. Let \(x = \{x_i\}_{i=1,\dots,N}\), \(x_i \in \mathbb{R}^2\) represent the set of coordinates of turbines within a farm (that is, \(x_i\) represents the \((X, Y)\) location of turbine \(i\)). Further, let \(R \subset \mathbb{R}^2\) be a closed region in which to place turbines. Finally, let \(d\) represent the minimum allowable distance between two turbines. Then, the layout optimization problem is expressed as

Here, \(||\cdot||\) denotes the Euclidean norm, and \(f(x)\) is the cost function to be maximized.

When maximizing the AEP, \(f = \sum_w P(w, x)p_W(w)\), where \(w\) is the wind condition bin (e.g., wind speed, wind direction pair); \(P(w, x)\) is the power produced by the wind farm in condition \(w\) with layout \(x\); and \(p_W(w)\) is the annual frequency of occurrence of condition \(w\).

Layout optimizers take iterative approaches to solving the layout optimization problem specified above. Optimization routines available in FLORIS are described below.

## Scipy layout optimization#

The `LayoutOptimizationScipy`

class is built around `scipy.optimize`

s `minimize`

routine, using the `SLSQP`

solver by default. Options for adjusting
`minimize`

's behavior are exposed to the user with the `optOptions`

argument.
Other options include enabling fast wake steering at each layout optimizer
iteration with the `enable_geometric_yaw`

argument, and switch from AEP
optimization to value optimization with the `use_value`

argument.

## Genetic random search layout optimization#

The `LayoutOptimizationRandomSearch`

class is a custom optimizer designed specifically for
layout optimization via random perturbations of the turbine locations. It is designed to have
the following features:

Robust to complex wind conditions and complex boundaries, including disjoint regions for turbine placement

Easy to parallelize and wrapped in a genetic algorithm for propagating candidate solutions

Simple to set up and tune for non-optimization experts

Set up to run cheap constraint checks prior to more expensive objective function evaluations to accelerate optimization

The algorithm, described in full in Sinner and Fleming [1],
moves a random turbine and random distance in a random direction; checks
that constraints are satisfied; evaluates the objective function (AEP or value); and then
commits to the move if there is an objective function improvement. The main tuning parameter
is the probability mass function for the random movement distance, which is a dictionary to be
passed to the `distance_pmf`

argument.

The `distance_pmf`

dictionary should contain two keys, each containing a 1D array of equal
length: `"d"`

, which specifies the perturbation distance *in units of the rotor diameter*,
and `"p"`

, which specifies the probability that the corresponding perturbation distance is
chosen at any iteration of the random search algorithm. The `distance_pmf`

can therefore be
used to encourage or discourage more aggressive or more conservative movements, and to enable
or disable jumps between disjoint regions for turbine placement.

The figure below shows an example of the optimized layout of a farm using the GRS algorithm, with the black dots indicating the initial layout; red dots indicating the final layout; and blue shading indicating wind speed heterogeneity (lighter shade is lower wind speed, darker shade is higher wind speed). The progress of each of the genetic individuals in the optimization process is shown in the right-hand plot.

## Gridded layout optimization#

The `LayoutOptimizationGridded`

class allows users to quickly find a layout that fits the most
turbines possible into the specified boundary area, given that the turbines are arranged in a
gridded layout.
To do so, a range of different rotations and translations of a generic gridded arrangement are
tried, and the one that fits the most turbines into the boundary area is selected. No AEP
evaluations are performed; rather, the cost function \(f\) to be maximized is simply \(N\), the number
of turbines, and there is an additional constraint that the turbines are arranged in a gridded
fashion. Note that in other layout optimizers, \(N\) is fixed.

We envisage that this will be useful for users that want to quickly generate a layout to
"fill" a boundary region in a gridded manner. By default, the gridded arrangement is a square grid
with spacing of `min_dist`

(or `min_dist_D`

); however, instantiating with the `hexagonal_packing`

keyword argument set to `True`

will provide a grid that offsets the rows to enable tighter packing
of turbines while still satisfying the `min_dist`

.

As with the `LayoutOptimizationRandomSearch`

class, the boundaries specified can be complex (and
may contain separate areas).
User settings include `rotation_step`

, which specifies the step size for rotating the grid
(in degrees); `rotation_range`

, which specifies the range of rotation angles; `translation_step`

or
`translation_step_D`

, which specifies the step size for translating the grid in meters or rotor
diameters, respectively; and `translation_range`

, which specifies the range of possible
translations. All come with default values, which we expect to be suitable for many or most users.