Example: Layout optimization with heterogeneous inflow#
This example shows a layout optimization using the geometric yaw option. Itcombines elements of layout optimization and heterogeneousinflow for demonstrative purposes.Heterogeneity in the inflow provides the necessary driver for coupled yawand layout optimization to be worthwhile. First, a layout optimization isrun without coupled yaw optimization; then a coupled optimization is run toshow the benefits of coupled optimization when flows are heterogeneous.
import os
import matplotlib.pyplot as plt
import numpy as np
from floris import FlorisModel, WindRose
from floris.optimization.layout_optimization.layout_optimization_scipy import (
LayoutOptimizationScipy,
)
# Initialize FLORIS
fmodel = FlorisModel("../inputs/gch.yaml")
# Setup 2 wind directions (due east and due west)
# and 1 wind speed with uniform probability
wind_directions = np.array([270.0, 90.0])
n_wds = len(wind_directions)
wind_speeds = [8.0] * np.ones_like(wind_directions)
turbulence_intensities = 0.06 * np.ones_like(wind_directions)
# Shape frequency distribution to match number of wind directions and wind speeds
freq_table = np.ones((len(wind_directions), len(wind_speeds)))
freq_table = freq_table / freq_table.sum()
# The boundaries for the turbines, specified as vertices
D = 126.0 # rotor diameter for the NREL 5MW
size_D = 12
boundaries = [(0.0, 0.0), (size_D * D, 0.0), (size_D * D, 0.1), (0.0, 0.1), (0.0, 0.0)]
# Set turbine locations to 4 turbines at corners of the rectangle
# (optimal without flow heterogeneity)
layout_x = [0.1, 0.3 * size_D * D, 0.6 * size_D * D]
layout_y = [0, 0, 0]
# Generate exaggerated heterogeneous inflow (same for all wind directions)
speed_multipliers = np.repeat(np.array([0.5, 1.0, 0.5, 1.0])[None, :], n_wds, axis=0)
x_locs = [0, size_D * D, 0, size_D * D]
y_locs = [-D, -D, D, D]
# Create the configuration dictionary to be used for the heterogeneous inflow.
heterogeneous_inflow_config_by_wd = {
"speed_multipliers": speed_multipliers,
"wind_directions": wind_directions,
"x": x_locs,
"y": y_locs,
}
# Establish a WindRose object
wind_rose = WindRose(
wind_directions=wind_directions,
wind_speeds=wind_speeds,
freq_table=freq_table,
ti_table=0.06,
heterogeneous_inflow_config_by_wd=heterogeneous_inflow_config_by_wd,
)
fmodel.set(
layout_x=layout_x,
layout_y=layout_y,
wind_data=wind_rose,
)
# Setup and solve the layout optimization problem without heterogeneity
maxiter = 100
layout_opt = LayoutOptimizationScipy(
fmodel, boundaries, min_dist=2 * D, optOptions={"maxiter": maxiter}
)
# Run the optimization
np.random.seed(0)
sol = layout_opt.optimize()
# Get the resulting improvement in AEP
print("... calcuating improvement in AEP")
fmodel.run()
base_aep = fmodel.get_farm_AEP() / 1e6
fmodel.set(layout_x=sol[0], layout_y=sol[1])
fmodel.run()
opt_aep = fmodel.get_farm_AEP() / 1e6
percent_gain = 100 * (opt_aep - base_aep) / base_aep
# Print and plot the results
print(f"Optimal layout: {sol}")
print(
f"Optimal layout improves AEP by {percent_gain:.1f}% "
f"from {base_aep:.1f} MWh to {opt_aep:.1f} MWh"
)
layout_opt.plot_layout_opt_results()
ax = plt.gca()
fig = plt.gcf()
sm = ax.tricontourf(x_locs, y_locs, speed_multipliers[0], cmap="coolwarm")
fig.colorbar(sm, ax=ax, label="Speed multiplier")
ax.legend(["Initial layout", "Optimized layout", "Optimization boundary"])
ax.set_title("Geometric yaw disabled")
# Rerun the layout optimization with geometric yaw enabled
print("\nReoptimizing with geometric yaw enabled.")
fmodel.set(layout_x=layout_x, layout_y=layout_y)
layout_opt = LayoutOptimizationScipy(
fmodel, boundaries, min_dist=2 * D, enable_geometric_yaw=True, optOptions={"maxiter": maxiter}
)
# Run the optimization
np.random.seed(0)
sol = layout_opt.optimize()
# Get the resulting improvement in AEP
print("... calcuating improvement in AEP")
fmodel.set(yaw_angles=np.zeros_like(layout_opt.yaw_angles))
fmodel.run()
base_aep = fmodel.get_farm_AEP() / 1e6
fmodel.set(layout_x=sol[0], layout_y=sol[1], yaw_angles=layout_opt.yaw_angles)
fmodel.run()
opt_aep = fmodel.get_farm_AEP() / 1e6
percent_gain = 100 * (opt_aep - base_aep) / base_aep
# Print and plot the results
print(f"Optimal layout: {sol}")
print(
f"Optimal layout improves AEP by {percent_gain:.1f}% "
f"from {base_aep:.1f} MWh to {opt_aep:.1f} MWh"
)
layout_opt.plot_layout_opt_results()
ax = plt.gca()
fig = plt.gcf()
sm = ax.tricontourf(x_locs, y_locs, speed_multipliers[0], cmap="coolwarm")
fig.colorbar(sm, ax=ax, label="Speed multiplier")
ax.legend(["Initial layout", "Optimized layout", "Optimization boundary"])
ax.set_title("Geometric yaw enabled")
print(
"Turbine geometric yaw angles for wind direction {0:.2f}".format(wind_directions[1])
+ " and wind speed {0:.2f} m/s:".format(wind_speeds[0]),
f"{layout_opt.yaw_angles[1, :]}",
)
plt.show()
import warnings
warnings.filterwarnings('ignore')
=====================================================
Optimizing turbine layout...
Number of parameters to optimize = 6
=====================================================
NIT FC OBJFUN GNORM
1 8 -2.212410E+00 2.629932E+00
2 15 -2.242661E+00 3.547760E+00
3 22 -2.143406E+00 3.843797E+00
4 30 -2.247379E+00 3.886024E+00
5 37 -2.247343E+00 3.977168E+00
6 54 -2.247350E+00 3.977160E+00
7 71 -2.247350E+00 3.977151E+00
8 88 -2.247350E+00 3.977143E+00
9 105 -2.247350E+00 3.977135E+00
10 122 -2.247350E+00 3.977127E+00
11 139 -2.247350E+00 3.977118E+00
12 156 -2.247350E+00 3.977110E+00
13 173 -2.247350E+00 3.977102E+00
14 190 -2.247350E+00 3.977094E+00
15 207 -2.247350E+00 3.977086E+00
16 224 -2.247350E+00 3.977078E+00
17 241 -2.247350E+00 3.977071E+00
18 258 -2.247350E+00 3.977063E+00
19 275 -2.247350E+00 3.977055E+00
20 292 -2.247350E+00 3.977048E+00
21 309 -2.247350E+00 3.977040E+00
22 326 -2.247350E+00 3.977032E+00
23 343 -2.247350E+00 3.977025E+00
24 360 -2.247350E+00 3.977017E+00
25 377 -2.247350E+00 3.977010E+00
26 394 -2.247350E+00 3.977003E+00
27 411 -2.247350E+00 3.976995E+00
28 428 -2.247350E+00 3.976988E+00
29 445 -2.247350E+00 3.976981E+00
30 462 -2.247350E+00 3.976974E+00
31 479 -2.247350E+00 3.976966E+00
32 496 -2.247350E+00 3.976959E+00
33 513 -2.247350E+00 3.976952E+00
34 530 -2.247350E+00 3.976945E+00
35 547 -2.247350E+00 3.976938E+00
36 564 -2.247350E+00 3.976931E+00
37 581 -2.247350E+00 3.976925E+00
38 598 -2.247350E+00 3.976918E+00
Optimization terminated successfully (Exit mode 0)
Current function value: -2.247378947225584
Iterations: 38
Function evaluations: 608
Gradient evaluations: 38
Optimization complete.
... calcuating improvement in AEP
Optimal layout: [[292.59583871603314, 704.3387065923789, 1511.9999999999893], [1.3342253732452536e-09, 4.82634845501135e-10, 5.690297624297925e-09]]
Optimal layout improves AEP by 124.7% from 6198.3 MWh to 13930.0 MWh
Reoptimizing with geometric yaw enabled.
=====================================================
Optimizing turbine layout...
Number of parameters to optimize = 6
=====================================================
NIT FC OBJFUN GNORM
1 8 -2.365430E+00 2.961907E+00
2 15 -2.498460E+00 3.815898E+00
3 22 -4.022027E+00 3.448231E+00
5 29 -3.500884E+00 2.123034E+02
6 42 -2.534787E+00 2.123034E+02
7 59 -2.411855E+00 2.123034E+02
8 66 -3.550245E+00 3.437672E+00
9 75 -2.515631E+00 3.300989E+00
10 82 -2.574165E+00 6.377456E+00
11 90 -2.660793E+00 4.588374E+00
12 97 -2.661877E+00 4.609823E+00
14 104 -2.598354E+00 4.619920E+00
15 112 -2.662405E+00 4.716649E+00
16 120 -2.662589E+00 4.685435E+00
17 127 -4.345299E+00 7.324759E+00
19 134 -2.203584E+00 2.425742E+02
20 151 -2.239965E+00 2.010962E+02
21 168 -2.279566E+00 2.010959E+02
22 175 -2.571612E+00 3.354666E+00
23 182 -2.367076E+00 4.358893E+00
24 190 -2.365764E+00 5.647083E+00
25 199 -2.581811E+00 6.377595E+00
26 208 -2.539621E+00 4.473524E+00
27 219 -2.650893E+00 4.826031E+00
28 227 -2.654484E+00 4.478846E+00
29 234 -2.423173E+00 4.958384E+00
30 251 -2.654513E+00 5.008351E+00
31 258 -2.596941E+00 6.940706E+00
32 267 -2.633805E+00 7.417251E+00
33 284 -2.575890E+00 3.225501E+00
34 291 -2.654761E+00 1.028703E+01
35 298 -2.654828E+00 7.416705E+00
36 305 -2.654829E+00 4.512198E+00
37 312 -2.597017E+00 6.904396E+00
38 320 -2.634682E+00 4.733280E+00
39 329 -2.655505E+00 4.733243E+00
40 336 -2.655506E+00 4.509499E+00
41 343 -2.655516E+00 4.954092E+00
42 350 -2.634737E+00 4.509437E+00
43 358 -2.655642E+00 4.509410E+00
44 365 -2.655643E+00 9.663361E+00
45 372 -2.655646E+00 4.508760E+00
46 379 -2.655654E+00 4.953615E+00
47 386 -2.634818E+00 6.590202E+00
48 394 -2.655656E+00 1.098597E+01
49 400 -2.655656E+00 6.590199E+00
Optimization terminated successfully (Exit mode 0)
Current function value: -2.655656447889527
Iterations: 49
Function evaluations: 400
Gradient evaluations: 46
Optimization complete.
... calcuating improvement in AEP
Optimal layout: [[1512.0, 967.357791585612, 442.5964943654864], [0.09999999998985194, 0.0, 4.2511595964914314e-12]]
Optimal layout improves AEP by 165.6% from 6198.3 MWh to 16460.6 MWh
Turbine geometric yaw angles for wind direction 90.00 and wind speed 8.00 m/s: [ 0. 24.80798657 24.99750908]