From 7fa3bf16b84e6fae70b244b82fdf83a5accb4f59 Mon Sep 17 00:00:00 2001 From: paulf81 Date: Fri, 24 May 2024 11:39:04 -0600 Subject: [PATCH] Randomized layout optimization (#697) * Add random optimization class * Add temporary example * rename example * Adding support for arbitrary pmf. * Plotting for pmf; update example. * Respecting new examples in develop. * Update base class to handle multiple regions of layout optimization. * geoyaw option added. * Terminology change: particle -> individual. * Adding functionality for plotting the optimization boundary only. * Adding grid. * Adding visualizations. * Allow random seed setting; non-parallel runs; log status. * Updating link to Stanleys published paper. * Enabling geometric yaw option. * WIP; storing for hotfix. * Bug fixed: updating layout when called. * Ruff * fi_subset needed updating rather than fi. * WIP commit to change branch. * runs. * Store initial aep correctly. * Minor update to defualt pmf' * Runs, but freq data not passed correctly. * Pipe through wind_data for freq information. * Move example to subdirectory. * Ruff. * Working on adding tests; still some work to do on value optimization. * Enable value optimization. * Handling TODO items * UserWarning -> ValueError; logger.warnings * Simple documentation added. * White space in docs. * Remove cm.get_cmap in favor of plt.get_cmap * Improve documentation and example. * renable geometric yaw option for v4; fix scipy layoutopt args. * remove self.x and self.y after initialization. * Improve progress plots and add to example. --------- Co-authored-by: misi9170 --- docs/_toc.yml | 1 + docs/layout_optimization.md | 81 ++ docs/plot_complex_docs.png | Bin 0 -> 147382 bytes .../003_genetic_random_search.py | 82 ++ floris/flow_visualization.py | 2 +- .../layout_optimization_base.py | 147 +++- .../layout_optimization_pyoptsparse.py | 6 +- .../layout_optimization_random_search.py | 707 ++++++++++++++++++ .../layout_optimization_scipy.py | 61 +- .../yaw_optimizer_geometric.py | 2 + floris/wind_data.py | 5 +- tests/layout_optimization_integration_test.py | 22 + ...andom_search_layout_opt_regression_test.py | 142 ++++ 13 files changed, 1202 insertions(+), 56 deletions(-) create mode 100644 docs/layout_optimization.md create mode 100644 docs/plot_complex_docs.png create mode 100644 examples/examples_layout_optimization/003_genetic_random_search.py create mode 100644 floris/optimization/layout_optimization/layout_optimization_random_search.py create mode 100644 tests/reg_tests/random_search_layout_opt_regression_test.py diff --git a/docs/_toc.yml b/docs/_toc.yml index 784be504d..4b78b0821 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -18,6 +18,7 @@ parts: - file: floating_wind_turbine - file: turbine_interaction - file: operation_models_user + - file: layout_optimization - file: input_reference_main - file: input_reference_turbine - file: examples diff --git a/docs/layout_optimization.md b/docs/layout_optimization.md new file mode 100644 index 000000000..361856579 --- /dev/null +++ b/docs/layout_optimization.md @@ -0,0 +1,81 @@ + +(layout_optimization)= +# 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 + +$$ +\begin{aligned} +\underset{x}{\text{maximize}} & \:\: f(x)\\ +\text{subject to} & \:\: x \subset R \\ +& \:\: ||x_i - x_j|| \geq d \:\: \forall j = 1,\dots,N, j\neq i +\end{aligned} +$$ + +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 an upcoming paper that will be linked here when it is +publicly available, 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. +![](plot_complex_docs.png) diff --git a/docs/plot_complex_docs.png b/docs/plot_complex_docs.png new file mode 100644 index 0000000000000000000000000000000000000000..bd4871298dc5e5e3bf74e6f2e49b47d000e41058 GIT binary patch literal 147382 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

Vb4RMHi&tp=l(H+f*xS(3ev20ugiI5X5eR#p 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 aTGU9`r)EUSzBz{;OG{JlMCS3!zy2Ra?MEg6 literal 0 HcmV?d00001 diff --git a/examples/examples_layout_optimization/003_genetic_random_search.py b/examples/examples_layout_optimization/003_genetic_random_search.py new file mode 100644 index 000000000..0955f151e --- /dev/null +++ b/examples/examples_layout_optimization/003_genetic_random_search.py @@ -0,0 +1,82 @@ +"""Example: Layout optimization with genetic random search +This example shows a layout optimization using the genetic random search +algorithm. It provides options for the users to try different distance +probability mass functions for the random search perturbations. +""" + +import matplotlib.pyplot as plt +import numpy as np +from scipy.stats import gamma + +from floris import FlorisModel, WindRose +from floris.optimization.layout_optimization.layout_optimization_random_search import ( + LayoutOptimizationRandomSearch, +) + + +if __name__ == '__main__': + # Set up FLORIS + fmodel = FlorisModel('../inputs/gch.yaml') + + + # Setup 72 wind directions with a random wind speed and frequency distribution + wind_directions = np.arange(0, 360.0, 5.0) + np.random.seed(1) + wind_speeds = 8.0 + np.random.randn(1) * 0.0 + # Shape frequency distribution to match number of wind directions and wind speeds + freq = ( + np.abs( + np.sort( + np.random.randn(len(wind_directions)) + ) + ) + .reshape( ( len(wind_directions), len(wind_speeds) ) ) + ) + freq = freq / freq.sum() + fmodel.set( + wind_data=WindRose( + wind_directions=wind_directions, + wind_speeds=wind_speeds, + freq_table=freq, + ti_table=0.06 + ) + ) + + # Set the boundaries + # The boundaries for the turbines, specified as vertices + boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)] + + # Set turbine locations to 4 turbines in a rectangle + D = 126.0 # rotor diameter for the NREL 5MW + layout_x = [0, 0, 6 * D, 6 * D] + layout_y = [0, 4 * D, 0, 4 * D] + fmodel.set(layout_x=layout_x, layout_y=layout_y) + + # Perform the optimization + distance_pmf = None + + # Other options that users can try + # 1. + # distance_pmf = {"d": [100, 1000], "p": [0.8, 0.2]} + # 2. + # p = gamma.pdf(np.linspace(0, 900, 91), 15, scale=20); p = p/p.sum() + # distance_pmf = {"d": np.linspace(100, 1000, 91), "p": p} + + layout_opt = LayoutOptimizationRandomSearch( + fmodel, + boundaries, + min_dist_D=5., + seconds_per_iteration=10, + total_optimization_seconds=60., + distance_pmf=distance_pmf + ) + layout_opt.describe() + layout_opt.plot_distance_pmf() + + layout_opt.optimize() + + layout_opt.plot_layout_opt_results() + + layout_opt.plot_progress() + + plt.show() diff --git a/floris/flow_visualization.py b/floris/flow_visualization.py index 57ae105a9..b893b172a 100644 --- a/floris/flow_visualization.py +++ b/floris/flow_visualization.py @@ -369,7 +369,7 @@ def plot_rotor_values( plot_rotor_values(floris.flow_field.w, findex=0, n_rows=1, ncols=4, show=True) """ - cmap = plt.cm.get_cmap(name=cmap) + cmap = plt.get_cmap(name=cmap) if t_range is None: t_range = range(values.shape[1]) diff --git a/floris/optimization/layout_optimization/layout_optimization_base.py b/floris/optimization/layout_optimization/layout_optimization_base.py index dd9afaae3..99977c2f5 100644 --- a/floris/optimization/layout_optimization/layout_optimization_base.py +++ b/floris/optimization/layout_optimization/layout_optimization_base.py @@ -1,7 +1,7 @@ import matplotlib.pyplot as plt import numpy as np -from shapely.geometry import LineString, Polygon +from shapely.geometry import MultiPolygon, Polygon from floris import TimeSeries from floris.optimization.yaw_optimization.yaw_optimizer_geometric import ( @@ -45,13 +45,28 @@ def __init__( self.enable_geometric_yaw = enable_geometric_yaw self.use_value = use_value - self._boundary_polygon = Polygon(self.boundaries) - self._boundary_line = LineString(self.boundaries) + # Allow boundaries to be set either as a list of corners or as a + # nested list of corners (for seperable regions) + self.boundaries = boundaries + b_depth = list_depth(boundaries) + + boundary_specification_error_msg = ( + "boundaries should be a list of coordinates (specifed as (x,y) "+\ + "tuples) or as a list of list of tuples (for seperable regions)." + ) - self.xmin = np.min([tup[0] for tup in boundaries]) - self.xmax = np.max([tup[0] for tup in boundaries]) - self.ymin = np.min([tup[1] for tup in boundaries]) - self.ymax = np.max([tup[1] for tup in boundaries]) + if b_depth == 1: + self._boundary_polygon = MultiPolygon([Polygon(self.boundaries)]) + self._boundary_line = self._boundary_polygon.boundary + elif b_depth == 2: + if not isinstance(self.boundaries[0][0], tuple): + raise TypeError(boundary_specification_error_msg) + self._boundary_polygon = MultiPolygon([Polygon(p) for p in self.boundaries]) + self._boundary_line = self._boundary_polygon.boundary + else: + raise TypeError(boundary_specification_error_msg) + + self.xmin, self.ymin, self.xmax, self.ymax = self._boundary_polygon.bounds # If no minimum distance is provided, assume a value of 2 rotor diameters if min_dist is None: @@ -115,36 +130,106 @@ def optimize(self): sol = self._optimize() return sol - def plot_layout_opt_results(self): + def plot_layout_opt_results(self, plot_boundary_dict={}, ax=None, fontsize=16): + x_initial, y_initial, x_opt, y_opt = self._get_initial_and_final_locs() - plt.figure(figsize=(9, 6)) - fontsize = 16 - plt.plot(x_initial, y_initial, "ob") - plt.plot(x_opt, y_opt, "or") - # plt.title('Layout Optimization Results', fontsize=fontsize) - plt.xlabel("x (m)", fontsize=fontsize) - plt.ylabel("y (m)", fontsize=fontsize) - plt.axis("equal") - plt.grid() - plt.tick_params(which="both", labelsize=fontsize) - plt.legend( - ["Old locations", "New locations"], + # Generate axis, if needed + if ax is None: + fig = plt.figure(figsize=(9,6)) + ax = fig.add_subplot(111) + ax.set_aspect("equal") + + default_plot_boundary_dict = { + "color":"None", + "alpha":1, + "edgecolor":"b", + "linewidth":2 + } + plot_boundary_dict = {**default_plot_boundary_dict, **plot_boundary_dict} + + self.plot_layout_opt_boundary(plot_boundary_dict, ax=ax) + ax.plot(x_initial, y_initial, "ob", label="Initial locations") + ax.plot(x_opt, y_opt, "or", label="New locations") + ax.set_xlabel("x (m)", fontsize=fontsize) + ax.set_ylabel("y (m)", fontsize=fontsize) + ax.grid(True) + ax.tick_params(which="both", labelsize=fontsize) + ax.legend( loc="lower center", bbox_to_anchor=(0.5, 1.01), ncol=2, fontsize=fontsize, ) - verts = self.boundaries - for i in range(len(verts)): - if i == len(verts) - 1: - plt.plot([verts[i][0], verts[0][0]], [verts[i][1], verts[0][1]], "b") - else: - plt.plot( - [verts[i][0], verts[i + 1][0]], [verts[i][1], verts[i + 1][1]], "b" + return ax + + def plot_layout_opt_boundary(self, plot_boundary_dict={}, ax=None): + + # Generate axis, if needed + if ax is None: + fig = plt.figure(figsize=(9,6)) + ax = fig.add_subplot(111) + ax.set_aspect("equal") + + default_plot_boundary_dict = { + "color":"k", + "alpha":0.1, + "edgecolor":None + } + + plot_boundary_dict = {**default_plot_boundary_dict, **plot_boundary_dict} + + for line in self._boundary_line.geoms: + xy = np.array(line.coords) + ax.fill(xy[:,0], xy[:,1], **plot_boundary_dict) + ax.grid(True) + + return ax + + def plot_progress(self, ax=None): + + if not hasattr(self, "objective_candidate_log"): + raise NotImplementedError( + "plot_progress not yet configured for "+self.__class__.__name__ + ) + + if ax is None: + _, ax = plt.subplots(1,1) + + objective_log_array = np.array(self.objective_candidate_log) + + if len(objective_log_array.shape) == 1: # Just one AEP candidate per step + ax.plot(np.arange(len(objective_log_array)), objective_log_array, color="k") + elif len(objective_log_array.shape) == 2: # Multiple AEP candidates per step + for i in range(objective_log_array.shape[1]): + ax.plot( + np.arange(len(objective_log_array)), + objective_log_array[:,i], + color="lightgray" ) + ax.scatter( + np.zeros(objective_log_array.shape[1]), + objective_log_array[0,:], + color="b", + label="Initial" + ) + ax.scatter( + objective_log_array.shape[0]-1, + objective_log_array[-1,:].max(), + color="r", + label="Final" + ) + + # Plot aesthetics + ax.grid(True) + ax.set_xlabel("Optimization step [-]") + ax.set_ylabel("Objective function") + ax.legend() + + return ax + ########################################################################### # Properties @@ -165,3 +250,11 @@ def nturbs(self): @property def rotor_diameter(self): return self.fmodel.core.farm.rotor_diameters_sorted[0][0] + +# Helper functions + +def list_depth(x): + if isinstance(x, list) and len(x) > 0: + return 1 + max(list_depth(item) for item in x) + else: + return 0 diff --git a/floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py b/floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py index 3a87dff70..794795767 100644 --- a/floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py +++ b/floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py @@ -4,7 +4,7 @@ from scipy.spatial.distance import cdist from shapely.geometry import Point -from .layout_optimization_base import LayoutOptimization +from .layout_optimization_base import LayoutOptimization, list_depth class LayoutOptimizationPyOptSparse(LayoutOptimization): @@ -54,6 +54,10 @@ def __init__( enable_geometric_yaw=False, use_value=False, ): + if list_depth(boundaries) > 1 and hasattr(boundaries[0][0], "__len__"): + raise NotImplementedError( + "LayoutOptimizationPyOptSparse is not configured for multiple regions." + ) super().__init__( fmodel, diff --git a/floris/optimization/layout_optimization/layout_optimization_random_search.py b/floris/optimization/layout_optimization/layout_optimization_random_search.py new file mode 100644 index 000000000..92e5d7f94 --- /dev/null +++ b/floris/optimization/layout_optimization/layout_optimization_random_search.py @@ -0,0 +1,707 @@ +# Copyright 2022 NREL + +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# See https://floris.readthedocs.io for documentation + + +from multiprocessing import Pool +from time import perf_counter as timerpc + +import matplotlib.pyplot as plt +import numpy as np +from numpy import random +from scipy.spatial.distance import cdist, pdist +from shapely.geometry import Point, Polygon + +from floris import FlorisModel +from floris.optimization.yaw_optimization.yaw_optimizer_geometric import ( + YawOptimizationGeometric, +) + +from .layout_optimization_base import LayoutOptimization + + +def _load_local_floris_object( + fmodel_dict, + wind_data=None, +): + # Load local FLORIS object + fmodel = FlorisModel(fmodel_dict) + fmodel.set(wind_data=wind_data) + return fmodel + +def test_min_dist(layout_x, layout_y, min_dist): + coords = np.array([layout_x,layout_y]).T + dist = pdist(coords) + return dist.min() >= min_dist + +def test_point_in_bounds(test_x, test_y, poly_outer): + return poly_outer.contains(Point(test_x, test_y)) + +# Return in MW +def _get_objective( + layout_x, + layout_y, + fmodel, + yaw_angles=None, + use_value=False +): + fmodel.set( + layout_x=layout_x, + layout_y=layout_y, + yaw_angles=yaw_angles + ) + fmodel.run() + + return fmodel.get_farm_AVP() if use_value else fmodel.get_farm_AEP() + +def _gen_dist_based_init( + N, # Number of turbins to place + step_size, #m, courseness of search grid + poly_outer, # Polygon of outer boundary + min_x, + max_x, + min_y, + max_y, + s +): + """ + Generates an initial layout by randomly placing + the first turbine than placing the remaining turbines + as far as possible from the existing turbines. + """ + + # Set random seed + np.random.seed(s) + + # Choose the initial point randomly + init_x = float(random.randint(int(min_x),int(max_x))) + init_y = float(random.randint(int(min_y),int(max_y))) + while not (poly_outer.contains(Point([init_x,init_y]))): + init_x = float(random.randint(int(min_x),int(max_x))) + init_y = float(random.randint(int(min_y),int(max_y))) + + # Intialize the layout arrays + layout_x = np.array([init_x]) + layout_y = np.array([init_y]) + layout = np.array([layout_x, layout_y]).T + + # Now add the remaining points + for i in range(1,N): + + print("Placing turbine {0} of {1}.".format(i, N)) + # Add a new turbine being as far as possible from current + max_dist = 0. + for x in np.arange(min_x, max_x,step_size): + for y in np.arange(min_y, max_y,step_size): + if poly_outer.contains(Point([x,y])): + test_dist = cdist([[x,y]],layout) + min_dist = np.min(test_dist) + if min_dist > max_dist: + max_dist = min_dist + save_x = x + save_y = y + + # Add point to the layout + layout_x = np.append(layout_x,[save_x]) + layout_y = np.append(layout_y,[save_y]) + layout = np.array([layout_x, layout_y]).T + + # Return the layout + return layout_x, layout_y + +class LayoutOptimizationRandomSearch(LayoutOptimization): + def __init__( + self, + fmodel, + boundaries, + min_dist=None, + min_dist_D=None, + distance_pmf=None, + n_individuals=4, + seconds_per_iteration=60., + total_optimization_seconds=600., + interface="multiprocessing", # Options are 'multiprocessing', 'mpi4py', None + max_workers=None, + grid_step_size=100., + relegation_number=1, + enable_geometric_yaw=False, + use_dist_based_init=True, + random_seed=None, + use_value=False, + ): + """ + _summary_ + + Args: + fmodel (_type_): _description_ + boundaries (iterable(float, float)): Pairs of x- and y-coordinates + that represent the boundary's vertices (m). + min_dist (float, optional): The minimum distance to be maintained + between turbines during the optimization (m). If not specified, + initializes to 2 rotor diameters. Defaults to None. + min_dist_D (float, optional): The minimum distance to be maintained + between turbines during the optimization, specified as a multiple + of the rotor diameter. + distance_pmf (dict, optional): Probability mass function describing the + length of steps in the random search. Specified as a dictionary with + keys "d" (array of step distances, specified in meters) and "p" + (array of probability of occurrence, should sum to 1). Defaults to + uniform probability between 0.5D and 2D, with some extra mass + to encourage large changes. + n_individuals (int, optional): The number of individuals to use in the + optimization. Defaults to 4. + seconds_per_iteration (float, optional): The number of seconds to + run each step of the optimization for. Defaults to 60. + total_optimization_seconds (float, optional): The total number of + seconds to run the optimization for. Defaults to 600. + interface (str): Parallel computing interface to leverage. Recommended is 'concurrent' + or 'multiprocessing' for local (single-system) use, and 'mpi4py' for high + performance computing on multiple nodes. Defaults to 'multiprocessing'. + max_workers (int): Number of parallel workers, typically equal to the number of cores + you have on your system or HPC. Defaults to None, which will use all + available cores. + grid_step_size (float): The coarseness of the grid used to generate the initial layout. + Defaults to 100. + relegation_number (int): The number of the lowest performing individuals to be replaced + with new individuals generated from the best performing individual. Must + be less than n_individuals / 2. Defaults to 1. + enable_geometric_yaw (bool): Use geometric yaw code to determine approximate wake + steering yaw angles during layout optimization routine. Defaults to False. + use_dist_based_init (bool): Generate initial layouts automatically by placing turbines + as far apart as possible. + random_seed (int or None): Random seed for reproducibility. Defaults to None. + use_value (bool, optional): If True, the layout optimization objective + is to maximize annual value production using the value array in the + FLORIS model's WindData object. If False, the optimization + objective is to maximize AEP. Defaults to False. + """ + # The parallel computing interface to use + if interface == "mpi4py": + import mpi4py.futures as mp + self._PoolExecutor = mp.MPIPoolExecutor + elif interface == "multiprocessing": + import multiprocessing as mp + self._PoolExecutor = mp.Pool + if max_workers is None: + max_workers = mp.cpu_count() + elif interface is None: + if n_individuals > 1 or (max_workers is not None and max_workers > 1): + print( + "Parallelization not possible with interface=None. " + +"Reducing n_individuals to 1 and ignoring max_workers." + ) + self._PoolExecutor = None + max_workers = None + n_individuals = 1 + + # elif interface == "concurrent": + # from concurrent.futures import ProcessPoolExecutor + # self._PoolExecutor = ProcessPoolExecutor + else: + raise ValueError( + f"Interface '{interface}' not recognized. " + "Please use ' 'multiprocessing' or 'mpi4py'." + ) + + # Store the max_workers + self.max_workers = max_workers + + # Store the interface + self.interface = interface + + # Set and store the random seed + self.random_seed = random_seed + + # Confirm the relegation_number is valid + if relegation_number > n_individuals / 2: + raise ValueError("relegation_number must be less than n_individuals / 2.") + self.relegation_number = relegation_number + + # Store the rotor diameter and number of turbines + self.D = fmodel.core.farm.rotor_diameters.max() + if not all(fmodel.core.farm.rotor_diameters == self.D): + self.logger.warning("Using largest rotor diameter for min_dist_D and distance_pmf.") + self.N_turbines = fmodel.n_turbines + + # Make sure not both min_dist and min_dist_D are defined + if min_dist is not None and min_dist_D is not None: + raise ValueError("Only one of min_dist and min_dist_D can be defined.") + + # If min_dist_D is defined, convert to min_dist + if min_dist_D is not None: + min_dist = min_dist_D * self.D + + super().__init__( + fmodel, + boundaries, + min_dist=min_dist, + enable_geometric_yaw=enable_geometric_yaw, + use_value=use_value, + ) + if use_value: + self._obj_name = "value" + self._obj_unit = "" + else: + self._obj_name = "AEP" + self._obj_unit = "[GWh]" + + # Save min_dist_D + self.min_dist_D = self.min_dist / self.D + + # Process and save the step distribution + self._process_dist_pmf(distance_pmf) + + # Store the Core dictionary + self.fmodel_dict = self.fmodel.core.as_dict() + + # Save the grid step size + self.grid_step_size = grid_step_size + + # Save number of individuals + self.n_individuals = n_individuals + + # Store the initial locations + self.x_initial = self.fmodel.layout_x + self.y_initial = self.fmodel.layout_y + + # Store the total optimization seconds + self.total_optimization_seconds = total_optimization_seconds + + # Store the seconds per iteration + self.seconds_per_iteration = seconds_per_iteration + + # Get the initial objective value + self.x = self.x_initial # Required by _get_geoyaw_angles + self.y = self.y_initial # Required by _get_geoyaw_angles + self.objective_initial = _get_objective( + self.x_initial, + self.y_initial, + self.fmodel, + self._get_geoyaw_angles(), + self.use_value, + ) + + # Initialize the objective statistics + self.objective_mean = self.objective_initial + self.objective_median = self.objective_initial + self.objective_max = self.objective_initial + self.objective_min = self.objective_initial + + # Initialize the numpy arrays which will hold the candidate layouts + # these will have dimensions n_individuals x N_turbines + self.x_candidate = np.zeros((self.n_individuals, self.N_turbines)) + self.y_candidate = np.zeros((self.n_individuals, self.N_turbines)) + + # Initialize the array which will hold the objective function values for each candidate + self.objective_candidate = np.zeros(self.n_individuals) + + # Initialize the iteration step + self.iteration_step = -1 + + # Initialize the optimization time + self.opt_time_start = timerpc() + self.opt_time = 0 + + # Generate the initial layouts + if use_dist_based_init: + self._generate_initial_layouts() + else: + print(f'Using supplied initial layout for {self.n_individuals} individuals.') + for i in range(self.n_individuals): + self.x_candidate[i, :] = self.x_initial + self.y_candidate[i, :] = self.y_initial + self.objective_candidate[i] = self.objective_initial + + # Evaluate the initial optimization step + self._evaluate_opt_step() + + # Delete stored x and y to avoid confusion + del self.x, self.y + + def describe(self): + print("Random Layout Optimization") + print(f"Number of turbines to optimize = {self.N_turbines}") + print(f"Minimum distance between turbines = {self.min_dist_D} [D], {self.min_dist} [m]") + print(f"Number of individuals = {self.n_individuals}") + print(f"Seconds per iteration = {self.seconds_per_iteration}") + print(f"Initial {self._obj_name} = {self.objective_initial/1e9:.1f} {self._obj_unit}") + + def _process_dist_pmf(self, dist_pmf): + """ + Check validity of pmf and assign default if none provided. + """ + if dist_pmf is None: + jump_dist = np.min([self.xmax-self.xmin, self.ymax-self.ymin])/2 + jump_prob = 0.05 + + d = np.append(np.linspace(0.0, 2.0*self.D, 99), jump_dist) + p = np.append((1-jump_prob)/len(d)*np.ones(len(d)-1), jump_prob) + p = p / p.sum() + dist_pmf = {"d":d, "p":p} + + # Check correct keys are provided + if not all(k in dist_pmf for k in ("d", "p")): + raise KeyError("distance_pmf must contains keys \"d\" (step distance)"+\ + " and \"p\" (probability of occurrence).") + + # Check entries are in the correct form + if not hasattr(dist_pmf["d"], "__len__") or not hasattr(dist_pmf["d"], "__len__")\ + or len(dist_pmf["d"]) != len(dist_pmf["p"]): + raise TypeError("distance_pmf entries should be numpy arrays or lists"+\ + " of equal length.") + + if not np.isclose(dist_pmf["p"].sum(), 1): + print("Probability mass function does not sum to 1. Normalizing.") + dist_pmf["p"] = np.array(dist_pmf["p"]) / np.array(dist_pmf["p"]).sum() + + self.distance_pmf = dist_pmf + + def _evaluate_opt_step(self): + + # Sort the candidate layouts by objective function value + sorted_indices = np.argsort(self.objective_candidate)[::-1] # Decreasing order + self.objective_candidate = self.objective_candidate[sorted_indices] + self.x_candidate = self.x_candidate[sorted_indices] + self.y_candidate = self.y_candidate[sorted_indices] + + # Update the optimization time + self.opt_time = timerpc() - self.opt_time_start + + # Update the optimizations step + self.iteration_step += 1 + + # Update the objective statistics + self.objective_mean = np.mean(self.objective_candidate) + self.objective_median = np.median(self.objective_candidate) + self.objective_max = np.max(self.objective_candidate) + self.objective_min = np.min(self.objective_candidate) + + # Report the results + increase_mean = ( + 100 * (self.objective_mean - self.objective_initial) / self.objective_initial + ) + increase_median = ( + 100 * (self.objective_median - self.objective_initial) / self.objective_initial + ) + increase_max = 100 * (self.objective_max - self.objective_initial) / self.objective_initial + increase_min = 100 * (self.objective_min - self.objective_initial) / self.objective_initial + print("=======================================") + print(f"Optimization step {self.iteration_step:+.1f}") + print(f"Optimization time = {self.opt_time:+.1f} [s]") + print( + f"Mean {self._obj_name} = {self.objective_mean/1e9:.1f}" + f" {self._obj_unit} ({increase_mean:+.2f}%)" + ) + print( + f"Median {self._obj_name} = {self.objective_median/1e9:.1f}" + f" {self._obj_unit} ({increase_median:+.2f}%)" + ) + print( + f"Max {self._obj_name} = {self.objective_max/1e9:.1f}" + f" {self._obj_unit} ({increase_max:+.2f}%)" + ) + print( + f"Min {self._obj_name} = {self.objective_min/1e9:.1f}" + f" {self._obj_unit} ({increase_min:+.2f}%)" + ) + print("=======================================") + + # Replace the relegation_number worst performing layouts with relegation_number + # best layouts + if self.relegation_number > 0: + self.objective_candidate[-self.relegation_number:] = ( + self.objective_candidate[:self.relegation_number] + ) + self.x_candidate[-self.relegation_number:] = self.x_candidate[:self.relegation_number] + self.y_candidate[-self.relegation_number:] = self.y_candidate[:self.relegation_number] + + + # Private methods + def _generate_initial_layouts(self): + """ + This method generates n_individuals initial layout of turbines. It does + this by calling the _generate_random_layout method within a multiprocessing + pool. + """ + + # Set random seed for initial layout + if self.random_seed is None: + multi_random_seeds = [None]*self.n_individuals + else: + multi_random_seeds = [23 + i for i in range(self.n_individuals)] + # 23 is just an arbitrary choice to ensure different random seeds + # to the evaluation code + + print(f'Generating {self.n_individuals} initial layouts...') + t1 = timerpc() + # Generate the multiargs for parallel execution + multiargs = [ + (self.N_turbines, + self.grid_step_size, + self._boundary_polygon, + self.xmin, + self.xmax, + self.ymin, + self.ymax, + multi_random_seeds[i]) + for i in range(self.n_individuals) + ] + + if self._PoolExecutor: # Parallelized + with self._PoolExecutor(self.max_workers) as p: + # This code is not currently necessary, but leaving in case implement + # concurrent later, based on parallel_computing_interface.py + if (self.interface == "mpi4py") or (self.interface == "multiprocessing"): + out = p.starmap(_gen_dist_based_init, multiargs) + else: # Parallelization not activated + out = [_gen_dist_based_init(*multiargs[0])] + + # Unpack out into the candidate layouts + for i in range(self.n_individuals): + self.x_candidate[i, :] = out[i][0] + self.y_candidate[i, :] = out[i][1] + + # Get the objective function values for each candidate layout + for i in range(self.n_individuals): + self.objective_candidate[i] = _get_objective( + self.x_candidate[i, :], + self.y_candidate[i, :], + self.fmodel, + self._get_geoyaw_angles(), + self.use_value, + ) + + t2 = timerpc() + print(f" Time to generate initial layouts: {t2-t1:.3f} s") + + def _get_initial_and_final_locs(self): + x_initial = self.x_initial + y_initial = self.y_initial + x_opt = self.x_opt + y_opt = self.y_opt + return x_initial, y_initial, x_opt, y_opt + + + # Public methods + + def optimize(self): + """ + Perform the optimization + """ + print(f'Optimizing using {self.n_individuals} individuals.') + opt_start_time = timerpc() + opt_stop_time = opt_start_time + self.total_optimization_seconds + sim_time = 0 + + self.objective_candidate_log = [self.objective_candidate.copy()] + self.num_objective_calls_log = [] + self._num_objective_calls = [0]*self.n_individuals + + while timerpc() < opt_stop_time: + + # Set random seed for the main loop + if self.random_seed is None: + multi_random_seeds = [None]*self.n_individuals + else: + multi_random_seeds = [55 + self.iteration_step + i + for i in range(self.n_individuals)] + # 55 is just an arbitrary choice to ensure different random seeds + # to the initialization code + + # Update the optimization time + sim_time = timerpc() - opt_start_time + print(f'Optimization time: {sim_time:.1f} s / {self.total_optimization_seconds:.1f} s') + + + # Generate the multiargs for parallel execution of single individual optimization + multiargs = [ + (self.seconds_per_iteration, + self.objective_candidate[i], + self.x_candidate[i, :], + self.y_candidate[i, :], + self.fmodel_dict, + self.fmodel.wind_data, + self.min_dist, + self._boundary_polygon, + self.distance_pmf, + self.enable_geometric_yaw, + multi_random_seeds[i], + self.use_value + ) + for i in range(self.n_individuals) + ] + + # Run the single individual optimization in parallel + if self._PoolExecutor: # Parallelized + with self._PoolExecutor(self.max_workers) as p: + out = p.starmap(_single_individual_opt, multiargs) + else: # Parallelization not activated + out = [_single_individual_opt(*multiargs[0])] + + # Unpack the results + for i in range(self.n_individuals): + self.objective_candidate[i] = out[i][0] + self.x_candidate[i, :] = out[i][1] + self.y_candidate[i, :] = out[i][2] + self._num_objective_calls[i] = out[i][3] + self.objective_candidate_log.append(self.objective_candidate) + self.num_objective_calls_log.append(self._num_objective_calls) + + # Evaluate the individuals for this step + self._evaluate_opt_step() + + # Finalize the result + self.objective_final = self.objective_candidate[0] + self.x_opt = self.x_candidate[0, :] + self.y_opt = self.y_candidate[0, :] + + # Print the final result + increase = 100 * (self.objective_final - self.objective_initial) / self.objective_initial + print( + f"Final {self._obj_name} = {self.objective_final/1e9:.1f}" + f" {self._obj_unit} ({increase:+.2f}%)" + ) + + return self.objective_final, self.x_opt, self.y_opt + + + # Helpful visualizations + def plot_distance_pmf(self, ax=None): + """ + Tool to check the used distance pmf. + """ + + if ax is None: + _, ax = plt.subplots(1,1) + + ax.stem(self.distance_pmf["d"], self.distance_pmf["p"], linefmt="k-") + ax.grid(True) + ax.set_xlabel("Step distance [m]") + ax.set_ylabel("Probability") + + return ax + + + +def _single_individual_opt( + seconds_per_iteration, + initial_objective, + layout_x, + layout_y, + fmodel_dict, + wind_data, + min_dist, + poly_outer, + dist_pmf, + enable_geometric_yaw, + s, + use_value +): + # Set random seed + np.random.seed(s) + + # Initialize the optimization time + single_opt_start_time = timerpc() + stop_time = single_opt_start_time + seconds_per_iteration + + num_objective_calls = 0 + + # Get the fmodel + fmodel_ = _load_local_floris_object(fmodel_dict, wind_data) + + # Initialize local variables + num_turbines = len(layout_x) + get_new_point = True # Will always be true, due to hardcoded use_momentum + current_objective = initial_objective + + # Establish geometric yaw optimizer, if desired + if enable_geometric_yaw: + yaw_opt = YawOptimizationGeometric( + fmodel_, + minimum_yaw_angle=-30.0, + maximum_yaw_angle=30.0, + ) + else: # yaw_angles will always be none + yaw_angles = None + + # We have a beta feature to maintain momentum, i.e., if a move improves + # the objective, we try to keep moving in that direction. This is currently + # disabled. + use_momentum = False + + # Loop as long as we've not hit the stop time + while timerpc() < stop_time: + + if not use_momentum: + get_new_point = True + + if get_new_point: #If the last test wasn't successful + + # Randomly select a turbine to nudge + tr = random.randint(0,num_turbines-1) + + # Randomly select a direction to nudge in (uniform direction) + rand_dir = np.random.uniform(low=0.0, high=2*np.pi) + + # Randomly select a distance to travel according to pmf + rand_dist = np.random.choice(dist_pmf["d"], p=dist_pmf["p"]) + + # Get a new test point + test_x = layout_x[tr] + np.cos(rand_dir) * rand_dist + test_y = layout_y[tr] + np.sin(rand_dir) * rand_dist + + # In bounds? + if not test_point_in_bounds(test_x, test_y, poly_outer): + get_new_point = True + continue + + # Make a new layout + original_x = layout_x[tr] + original_y = layout_y[tr] + layout_x[tr] = test_x + layout_y[tr] = test_y + + # Acceptable distances? + if not test_min_dist(layout_x, layout_y,min_dist): + # Revert and continue + layout_x[tr] = original_x + layout_y[tr] = original_y + get_new_point = True + continue + + # Does it improve the objective? + if enable_geometric_yaw: # Select appropriate yaw angles + yaw_opt.fmodel_subset.set(layout_x=layout_x, layout_y=layout_y) + df_opt = yaw_opt.optimize() + yaw_angles = np.vstack(df_opt['yaw_angles_opt']) + + num_objective_calls += 1 + test_objective = _get_objective(layout_x, layout_y, fmodel_, yaw_angles, use_value) + + if test_objective > current_objective: + # Accept the change + current_objective = test_objective + + # If not a random point this cycle and it did improve things + # try not getting a new point + # Feature is currently disabled by use_momentum flag + get_new_point = False + + else: + # Revert the change + layout_x[tr] = original_x + layout_y[tr] = original_y + get_new_point = True + + # Return the best result from this individual + return current_objective, layout_x, layout_y, num_objective_calls diff --git a/floris/optimization/layout_optimization/layout_optimization_scipy.py b/floris/optimization/layout_optimization/layout_optimization_scipy.py index f7ca643b1..ff0e30015 100644 --- a/floris/optimization/layout_optimization/layout_optimization_scipy.py +++ b/floris/optimization/layout_optimization/layout_optimization_scipy.py @@ -5,7 +5,7 @@ from scipy.spatial.distance import cdist from shapely.geometry import Point -from .layout_optimization_base import LayoutOptimization +from .layout_optimization_base import LayoutOptimization, list_depth class LayoutOptimizationScipy(LayoutOptimization): @@ -13,27 +13,6 @@ class LayoutOptimizationScipy(LayoutOptimization): This class provides an interface for optimizing the layout of wind turbines using the Scipy optimization library. The optimization objective is to maximize annual energy production (AEP) or annual value production (AVP). - - - Args: - fmodel (FlorisModel): A FlorisModel object. - boundaries (iterable(float, float)): Pairs of x- and y-coordinates - that represent the boundary's vertices (m). - bnds (iterable, optional): Bounds for the optimization - variables (pairs of min/max values for each variable (m)). If - none are specified, they are set to 0 and 1. Defaults to None. - min_dist (float, optional): The minimum distance to be maintained - between turbines during the optimization (m). If not specified, - initializes to 2 rotor diameters. Defaults to None. - solver (str, optional): Sets the solver used by Scipy. Defaults to 'SLSQP'. - optOptions (dict, optional): Dictionary for setting the - optimization options. Defaults to None. - enable_geometric_yaw (bool, optional): If True, enables geometric yaw - optimization. Defaults to False. - use_value (bool, optional): If True, the layout optimization objective - is to maximize annual value production using the value array in the - FLORIS model's WindData object. If False, the optimization - objective is to maximize AEP. Defaults to False. """ def __init__( self, @@ -46,6 +25,31 @@ def __init__( enable_geometric_yaw=False, use_value=False, ): + """ + Args: + fmodel (FlorisModel): A FlorisModel object. + boundaries (iterable(float, float)): Pairs of x- and y-coordinates + that represent the boundary's vertices (m). + bnds (iterable, optional): Bounds for the optimization + variables (pairs of min/max values for each variable (m)). If + none are specified, they are set to 0 and 1. Defaults to None. + min_dist (float, optional): The minimum distance to be maintained + between turbines during the optimization (m). If not specified, + initializes to 2 rotor diameters. Defaults to None. + solver (str, optional): Sets the solver used by Scipy. Defaults to 'SLSQP'. + optOptions (dict, optional): Dictionary for setting the + optimization options. Defaults to None. + enable_geometric_yaw (bool, optional): If True, enables geometric yaw + optimization. Defaults to False. + use_value (bool, optional): If True, the layout optimization objective + is to maximize annual value production using the value array in the + FLORIS model's WindData object. If False, the optimization + objective is to maximize AEP. Defaults to False. + """ + if list_depth(boundaries) > 1 and hasattr(boundaries[0][0], "__len__"): + raise NotImplementedError( + "LayoutOptimizationScipy is not configured for multiple regions." + ) super().__init__( fmodel, @@ -88,6 +92,10 @@ def __init__( # Private methods def _optimize(self): + + self._num_aep_calls = 0 + self._aep_record = [] + self.residual_plant = minimize( self._obj_func, self.x0, @@ -112,11 +120,16 @@ def _obj_func(self, locs): yaw_angles = self._get_geoyaw_angles() self.fmodel.set_operation(yaw_angles=yaw_angles) self.fmodel.run() + self._num_aep_calls += 1 if self.use_value: - return -1 * self.fmodel.get_farm_AVP() / self.initial_AEP_or_AVP + val = -1 * self.fmodel.get_farm_AVP() / self.initial_AEP_or_AVP + self._aep_record.append(val) + return val else: - return -1 * self.fmodel.get_farm_AEP() / self.initial_AEP_or_AVP + aep = -1 * self.fmodel.get_farm_AEP() / self.initial_AEP_or_AVP + self._aep_record.append(aep) + return aep def _change_coordinates(self, locs): diff --git a/floris/optimization/yaw_optimization/yaw_optimizer_geometric.py b/floris/optimization/yaw_optimization/yaw_optimizer_geometric.py index e78d48c9d..ea68204b4 100644 --- a/floris/optimization/yaw_optimization/yaw_optimizer_geometric.py +++ b/floris/optimization/yaw_optimization/yaw_optimizer_geometric.py @@ -12,6 +12,8 @@ class YawOptimizationGeometric(YawOptimization): :py:class:`floris.optimization.general_library.YawOptimization` that is used to provide a rough estimate of optimal yaw angles based purely on the wind farm geometry. Main use case is for coupled layout and yaw optimization. + + See Stanely et al. (2023) for details: https://wes.copernicus.org/articles/8/1341/2023/ """ def __init__( diff --git a/floris/wind_data.py b/floris/wind_data.py index 926ca9e0e..5745eca54 100644 --- a/floris/wind_data.py +++ b/floris/wind_data.py @@ -4,7 +4,6 @@ from abc import abstractmethod from pathlib import Path -import matplotlib.cm as cm import matplotlib.pyplot as plt import numpy as np import pandas as pd @@ -614,7 +613,7 @@ def plot( wd_step = wd_bins[1] - wd_bins[0] # Get a color array - color_array = cm.get_cmap(color_map, len(ws_bins)) + color_array = plt.get_cmap(color_map, len(ws_bins)) for wd_idx, wd in enumerate(wd_bins): rects = [] @@ -1514,7 +1513,7 @@ def plot( _, ax = plt.subplots(subplot_kw={"polar": True}) # Get a color array - color_array = cm.get_cmap(color_map, len(var_bins)) + color_array = plt.get_cmap(color_map, len(var_bins)) for wd_idx, wd in enumerate(wd_bins): rects = [] diff --git a/tests/layout_optimization_integration_test.py b/tests/layout_optimization_integration_test.py index 0732b969c..18353a8f5 100644 --- a/tests/layout_optimization_integration_test.py +++ b/tests/layout_optimization_integration_test.py @@ -12,6 +12,9 @@ from floris.optimization.layout_optimization.layout_optimization_base import ( LayoutOptimization, ) +from floris.optimization.layout_optimization.layout_optimization_random_search import ( + LayoutOptimizationRandomSearch, +) from floris.optimization.layout_optimization.layout_optimization_scipy import ( LayoutOptimizationScipy, ) @@ -70,3 +73,22 @@ def test_base_class(caplog): LayoutOptimization(fmodel, boundaries, 5) LayoutOptimization(fmodel=fmodel, boundaries=boundaries, min_dist=5) + +def test_LayoutOptimizationRandomSearch(): + fmodel = FlorisModel(configuration=YAML_INPUT) + fmodel.set(layout_x=[0, 500], layout_y = [0, 0]) + + # Set up a sample boundary + boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)] + + layout_opt = LayoutOptimizationRandomSearch( + fmodel=fmodel, + boundaries=boundaries, + min_dist_D=5, + seconds_per_iteration=1, + total_optimization_seconds=1, + use_dist_based_init=False, + ) + + # Check that the optimization runs + layout_opt.optimize() diff --git a/tests/reg_tests/random_search_layout_opt_regression_test.py b/tests/reg_tests/random_search_layout_opt_regression_test.py new file mode 100644 index 000000000..f29b40f28 --- /dev/null +++ b/tests/reg_tests/random_search_layout_opt_regression_test.py @@ -0,0 +1,142 @@ + +import numpy as np +import pandas as pd + +from floris import FlorisModel, WindRose +from floris.optimization.layout_optimization.layout_optimization_random_search import ( + LayoutOptimizationRandomSearch, +) +from tests.conftest import ( + assert_results_arrays, +) + + +DEBUG = False +VELOCITY_MODEL = "gauss" +DEFLECTION_MODEL = "gauss" + +locations_baseline_aep = np.array( + [ + [0.0, 571.5416296, 1260.0], + [0.0, 496.57085993, 0.], + ] +) +baseline_aep = 44787987324.21652 + +locations_baseline_value = np.array( + [ + [387.0, 100.0, 200.0, 300.0], + [192.0, 300.0, 100.0, 300.0], + ] +) +baseline_value = 8780876351.32277 + + +def test_random_search_layout_opt(sample_inputs_fixture): + """ + The SciPy optimization method optimizes turbine layout using SciPy's minimize method. This test + compares the optimization results from the SciPy layout optimization for a simple farm with a + simple wind rose to stored baseline results. + """ + sample_inputs_fixture.core["wake"]["model_strings"]["velocity_model"] = VELOCITY_MODEL + sample_inputs_fixture.core["wake"]["model_strings"]["deflection_model"] = DEFLECTION_MODEL + + boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)] + + fmodel = FlorisModel(sample_inputs_fixture.core) + wd_array = np.arange(0, 360.0, 5.0) + ws_array = 8.0 * np.ones_like(wd_array) + + wind_rose = WindRose( + wind_directions=wd_array, + wind_speeds=ws_array, + ti_table=0.1, + ) + D = 126.0 # Rotor diameter for the NREL 5 MW + fmodel.set( + layout_x=[0.0, 5 * D, 10 * D], + layout_y=[0.0, 0.0, 0.0], + wind_data=wind_rose + ) + + layout_opt = LayoutOptimizationRandomSearch( + fmodel=fmodel, + boundaries=boundaries, + min_dist_D=5, + seconds_per_iteration=1, + total_optimization_seconds=1, + use_dist_based_init=False, + random_seed=0, + ) + sol = layout_opt.optimize() + optimized_aep = sol[0] + locations_opt = np.array([sol[1], sol[2]]) + + if DEBUG: + print(locations_opt) + print(optimized_aep) + + assert_results_arrays(locations_opt, locations_baseline_aep) + assert np.isclose(optimized_aep, baseline_aep) + +def test_random_search_layout_opt_value(sample_inputs_fixture): + """ + This test compares the optimization results from the SciPy layout optimization for a simple + farm with a simple wind rose to stored baseline results, optimizing for annual value production + instead of AEP. The value of the energy produced depends on the wind direction, causing the + optimal layout to differ from the case where the objective is maximum AEP. In this case, because + the value is much higher when the wind is from the north or south, the turbines are staggered to + avoid wake interactions for northerly and southerly winds. + """ + sample_inputs_fixture.core["wake"]["model_strings"]["velocity_model"] = VELOCITY_MODEL + sample_inputs_fixture.core["wake"]["model_strings"]["deflection_model"] = DEFLECTION_MODEL + + boundaries = [(0.0, 0.0), (0.0, 400.0), (400.0, 400.0), (400.0, 0.0), (0.0, 0.0)] + + fmodel = FlorisModel(sample_inputs_fixture.core) + + # set wind conditions and values using a WindData object with the default uniform frequency + wd_array = np.arange(0, 360.0, 5.0) + ws_array = np.array([8.0]) + + # Define the value table such that the value of the energy produced is + # significantly higher when the wind direction is close to the north or + # south, and zero when the wind is from the east or west. + value_table = (0.5 + 0.5*np.cos(2*np.radians(wd_array)))**10 + value_table = value_table.reshape((len(wd_array),1)) + + wind_rose = WindRose( + wind_directions=wd_array, + wind_speeds=ws_array, + ti_table=0.1, + value_table=value_table + ) + + # Start with a rectangular 4-turbine array with 2D spacing + D = 126.0 # Rotor diameter for the NREL 5 MW + fmodel.set( + layout_x=200 + np.array([-1 * D, -1 * D, 1 * D, 1 * D]), + layout_y=200 + np.array([-1* D, 1 * D, -1 * D, 1 * D]), + wind_data=wind_rose, + ) + + layout_opt = LayoutOptimizationRandomSearch( + fmodel=fmodel, + boundaries=boundaries, + min_dist_D=5, + seconds_per_iteration=1, + total_optimization_seconds=1, + use_dist_based_init=True, + random_seed=0, + use_value=True, + ) + sol = layout_opt.optimize() + optimized_value = sol[0] + locations_opt = np.array([sol[1], sol[2]]) + + if DEBUG: + print(locations_opt) + print(optimized_value) + + assert_results_arrays(locations_opt, locations_baseline_value) + assert np.isclose(optimized_value, baseline_value)