Example: Compare yaw optimizers#
"""Example: Compare yaw optimizers
This example compares the SciPy-based yaw optimizer with the Serial-Refine optimizer
and geometric optimizer.
First, we initialize Floris, and then generate a 3 turbine wind farm.
Next, we create two yaw optimization objects, `yaw_opt_sr` and `yaw_opt_scipy` for the
Serial-Refine and SciPy methods, respectively.
We then perform the optimization using both methods.
Finally, we compare the time it took to find the optimal angles and plot the optimal yaw angles
and resulting wind farm powers.
The example now also compares the Geometric Yaw optimizer, which is fast
a method to find approximately optimal yaw angles based on the wind farm geometry. Its
main use case is for coupled layout and yaw optimization.
see floris.optimization.yaw_optimization.yaw_optimizer_geometric.py and the paper online
at https://wes.copernicus.org/preprints/wes-2023-1/. See also example 16c.
"""
from time import perf_counter as timerpc
import matplotlib.pyplot as plt
import numpy as np
from floris import FlorisModel
from floris.optimization.yaw_optimization.yaw_optimizer_geometric import (
YawOptimizationGeometric,
)
from floris.optimization.yaw_optimization.yaw_optimizer_scipy import YawOptimizationScipy
from floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR
# Load the default example floris object
fmodel = FlorisModel("../inputs/gch.yaml")
# Reinitialize as a 3-turbine farm with range of WDs and 1 WS
D = 126.0 # Rotor diameter for the NREL 5 MW
wd_array = np.arange(0.0, 360.0, 3.0)
ws_array = 8.0 * np.ones_like(wd_array)
turbulence_intensities = 0.06 * np.ones_like(wd_array)
fmodel.set(
layout_x=[0.0, 5 * D, 10 * D],
layout_y=[0.0, 0.0, 0.0],
wind_directions=wd_array,
wind_speeds=ws_array,
turbulence_intensities=turbulence_intensities,
)
print("Performing optimizations with SciPy...")
start_time = timerpc()
yaw_opt_scipy = YawOptimizationScipy(fmodel)
df_opt_scipy = yaw_opt_scipy.optimize()
time_scipy = timerpc() - start_time
print("Performing optimizations with Serial Refine...")
start_time = timerpc()
yaw_opt_sr = YawOptimizationSR(fmodel)
df_opt_sr = yaw_opt_sr.optimize()
time_sr = timerpc() - start_time
print("Performing optimizations with Geometric Yaw...")
start_time = timerpc()
yaw_opt_geo = YawOptimizationGeometric(fmodel)
df_opt_geo = yaw_opt_geo.optimize()
time_geo = timerpc() - start_time
# Print time spent
print("\n Time spent, Geometric Yaw: {:.2f} s.".format(time_geo))
print(" Time spent, Serial Refine: {:.2f} s.".format(time_sr))
print(" Time spent, SciPy (SLSQP): {:.2f} s.\n".format(time_scipy))
# Split out the turbine results
yaw_angles_opt_geo = np.vstack(df_opt_geo.yaw_angles_opt)
yaw_angles_opt_sr = np.vstack(df_opt_sr.yaw_angles_opt)
yaw_angles_opt_scipy = np.vstack(df_opt_scipy.yaw_angles_opt)
# Yaw results
for t in range(3):
fig, ax = plt.subplots()
ax.plot(df_opt_geo.wind_direction, yaw_angles_opt_geo[:, t],color='m',label='Geometric')
ax.plot(df_opt_sr.wind_direction, yaw_angles_opt_sr[:, t],color='r',label='Serial Refine')
ax.plot(df_opt_scipy.wind_direction, yaw_angles_opt_scipy[:, t],'--', color='g', label='SciPy')
ax.grid(True)
ax.set_ylabel('Yaw Offset (deg')
ax.legend()
ax.grid(True)
ax.set_title("Turbine {:d}".format(t))
# Power results ==============
# Before plotting results, need to compute values for GEOOPT since it doesn't compute
# power within the optimization
fmodel.set(yaw_angles=yaw_angles_opt_geo)
fmodel.run()
geo_farm_power = fmodel.get_farm_power().squeeze()
fig, ax = plt.subplots()
ax.plot(
df_opt_sr.wind_direction,
df_opt_sr.farm_power_baseline,
color='k',
label='Baseline'
)
ax.plot(
df_opt_geo.wind_direction,
geo_farm_power,
color='m',
label='Optimized, Gemoetric'
)
ax.plot(
df_opt_sr.wind_direction,
df_opt_sr.farm_power_opt,
color='r',
label='Optimized, Serial Refine'
)
ax.plot(
df_opt_scipy.wind_direction,
df_opt_scipy.farm_power_opt,
'--',
color='g',
label='Optimized, SciPy'
)
ax.set_ylabel('Wind Farm Power (W)')
ax.set_xlabel('Wind Direction (deg)')
ax.legend()
ax.grid(True)
# Finally, compare the overall the power gains
fig, ax = plt.subplots()
ax.plot(
df_opt_geo.wind_direction,
geo_farm_power - df_opt_sr.farm_power_baseline,
color='m',
label='Optimized, Gemoetric'
)
ax.plot(
df_opt_sr.wind_direction,
df_opt_sr.farm_power_opt - df_opt_sr.farm_power_baseline,
color='r',
label='Optimized, Serial Refine'
)
ax.plot(
df_opt_scipy.wind_direction,
df_opt_scipy.farm_power_opt - df_opt_scipy.farm_power_baseline,
'--',
color='g',
label='Optimized, SciPy'
)
ax.set_ylabel('Increase in Wind Farm Power (W)')
ax.set_xlabel('Wind Direction (deg)')
ax.legend()
ax.grid(True)
# Finally, make a quick bar plot comparing nomimal power and nomimal uplift
total_power_uplift_geo = np.sum(geo_farm_power - df_opt_sr.farm_power_baseline)
total_power_uplift_sr = np.sum(df_opt_sr.farm_power_opt - df_opt_sr.farm_power_baseline)
total_power_uplift_scipy = np.sum(df_opt_scipy.farm_power_opt - df_opt_scipy.farm_power_baseline)
# Plot on the left subplot a barplot comparing the uplift normalized to scipy and on the right
# subplot a barplot of total time normalzed to scipy
fig, axarr = plt.subplots(1,2,figsize=(10,5))
ax = axarr[0]
ax.bar(
[0, 1, 2],
[
total_power_uplift_geo / total_power_uplift_scipy,
total_power_uplift_sr / total_power_uplift_scipy,
1.0,
],
color=['m', 'r', 'g'],
)
ax.set_xticks([0, 1, 2])
ax.set_xticklabels(['Geometric', 'Serial Refine', 'SciPy'])
ax.set_ylabel('Normalized Power Gain')
ax.grid(True)
ax = axarr[1]
ax.bar(
[0, 1, 2],
[
time_geo / time_scipy,
time_sr / time_scipy,
1.0,
],
color=['m', 'r', 'g'],
)
ax.set_xticks([0, 1, 2])
ax.set_xticklabels(['Geometric', 'Serial Refine', 'SciPy'])
ax.set_ylabel('Normalized Computation Time')
ax.grid(True)
# Change to semi-logy
axarr[1].set_yscale('log')
plt.show()
import warnings
warnings.filterwarnings('ignore')
Performing optimizations with SciPy...
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.362152E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.365698E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.454492E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 9.711141E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.217228E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 7.129374E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 1.419861E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.180748E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.208611E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 4 -1.003155E+00 6.242130E-02
2 7 -1.093049E+00 1.020444E-01
3 10 -1.203810E+00 1.954488E-01
4 13 -1.211961E+00 1.281127E-01
5 16 -1.214226E+00 1.153093E-01
6 19 -1.214237E+00 1.015314E-01
7 22 -1.214237E+00 1.013118E-01
8 24 -1.214237E+00 1.013095E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.2142370269715685
Iterations: 8
Function evaluations: 24
Gradient evaluations: 8
NIT FC OBJFUN GNORM
1 4 -1.077700E+00 2.636250E-01
2 7 -1.240651E+00 3.181902E-01
3 10 -1.245722E+00 6.558203E-02
4 13 -1.254002E+00 5.362665E-02
5 16 -1.254090E+00 1.319603E-02
6 19 -1.254067E+00 1.309625E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.254089791882447
Iterations: 6
Function evaluations: 29
Gradient evaluations: 6
NIT FC OBJFUN GNORM
1 4 -1.041029E+00 2.069800E-01
2 7 -1.123711E+00 1.859063E-01
3 10 -1.126458E+00 4.218585E-02
4 13 -1.126780E+00 2.116581E-02
5 16 -1.125994E+00 1.612383E-02
6 20 -1.126860E+00 1.533901E-02
7 25 -1.126833E+00 1.311498E-02
8 29 -1.128280E+00 8.142882E-03
9 32 -1.126762E+00 2.579974E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.1282800408328353
Iterations: 9
Function evaluations: 42
Gradient evaluations: 9
NIT FC OBJFUN GNORM
1 4 -1.017900E+00 1.295852E-01
2 7 -1.046548E+00 9.997854E-02
3 10 -1.046487E+00 8.887290E-03
4 23 -1.046525E+00 8.887263E-03
5 28 -1.046624E+00 7.099863E-03
6 31 -1.046658E+00 1.033764E-03
7 34 -1.046683E+00 4.341467E-04
8 37 -1.046685E+00 3.729168E-05
9 40 -1.046685E+00 2.824111E-06
10 42 -1.046685E+00 6.047025E-08
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0466852786523977
Iterations: 10
Function evaluations: 42
Gradient evaluations: 10
NIT FC OBJFUN GNORM
1 4 -1.002993E+00 4.975943E-02
2 7 -1.006900E+00 3.378644E-02
3 10 -1.007674E+00 1.032241E-02
4 13 -1.007874E+00 3.814488E-03
5 16 -1.007914E+00 2.517815E-03
6 19 -1.007945E+00 2.060119E-03
7 22 -1.007921E+00 7.695137E-04
Optimization terminated successfully (Exit mode 0)
Current function value: -1.007944748375735
Iterations: 7
Function evaluations: 32
Gradient evaluations: 7
NIT FC OBJFUN GNORM
1 4 -1.000005E+00 8.565508E-04
2 7 -1.000025E+00 7.819653E-04
3 10 -1.000035E+00 5.322843E-04
4 12 -1.000035E+00 4.924128E-04
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0000354608371065
Iterations: 4
Function evaluations: 12
Gradient evaluations: 4
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 7.483173E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.306803E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.359719E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.361989E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.362152E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.365698E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.454492E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 9.711141E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.217228E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 7.129374E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 1.419861E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.180748E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 2.208611E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 4 -1.003155E+00 6.242130E-02
2 7 -1.093049E+00 1.020444E-01
3 10 -1.203810E+00 1.954488E-01
4 13 -1.211961E+00 1.281127E-01
5 16 -1.214226E+00 1.153093E-01
6 19 -1.214237E+00 1.015314E-01
7 22 -1.214237E+00 1.013118E-01
8 24 -1.214237E+00 1.013095E-01
Optimization terminated successfully (Exit mode 0)
Current function value: -1.2142370269715692
Iterations: 8
Function evaluations: 24
Gradient evaluations: 8
NIT FC OBJFUN GNORM
1 4 -1.077700E+00 2.636250E-01
2 7 -1.240651E+00 3.181902E-01
3 10 -1.245722E+00 6.558203E-02
4 13 -1.254002E+00 5.362665E-02
5 16 -1.254090E+00 1.319603E-02
6 19 -1.254067E+00 1.309625E-02
Optimization terminated successfully (Exit mode 0)
Current function value: -1.254089791882446
Iterations: 6
Function evaluations: 29
Gradient evaluations: 6
NIT FC OBJFUN GNORM
1 4 -1.041029E+00 2.069800E-01
2 7 -1.123711E+00 1.859063E-01
3 10 -1.126458E+00 4.218585E-02
4 13 -1.126780E+00 2.116581E-02
5 16 -1.125994E+00 1.612383E-02
6 20 -1.126860E+00 1.533901E-02
7 25 -1.126833E+00 1.311498E-02
8 29 -1.128280E+00 8.142882E-03
9 32 -1.126762E+00 2.579974E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.1282800408328355
Iterations: 9
Function evaluations: 42
Gradient evaluations: 9
NIT FC OBJFUN GNORM
1 4 -1.017900E+00 1.295852E-01
2 7 -1.046548E+00 9.997854E-02
3 10 -1.046487E+00 8.887290E-03
4 23 -1.046525E+00 8.887263E-03
5 28 -1.046624E+00 7.099863E-03
6 31 -1.046658E+00 1.033765E-03
7 34 -1.046683E+00 4.341468E-04
8 37 -1.046685E+00 3.729169E-05
9 40 -1.046685E+00 2.824112E-06
10 42 -1.046685E+00 6.047028E-08
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0466852786523961
Iterations: 10
Function evaluations: 42
Gradient evaluations: 10
NIT FC OBJFUN GNORM
1 4 -1.002993E+00 4.975943E-02
2 7 -1.006900E+00 3.378644E-02
3 10 -1.007674E+00 1.032241E-02
4 13 -1.007874E+00 3.814488E-03
5 16 -1.007914E+00 2.517815E-03
6 19 -1.007945E+00 2.060119E-03
7 22 -1.007921E+00 7.695137E-04
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0079447483757351
Iterations: 7
Function evaluations: 32
Gradient evaluations: 7
NIT FC OBJFUN GNORM
1 4 -1.000005E+00 8.565508E-04
2 7 -1.000025E+00 7.819653E-04
3 10 -1.000035E+00 5.322843E-04
4 12 -1.000035E+00 4.924128E-04
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0000354608371067
Iterations: 4
Function evaluations: 12
Gradient evaluations: 4
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 7.483173E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.306803E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.359719E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
NIT FC OBJFUN GNORM
1 3 -1.000000E+00 8.361989E-03
Optimization terminated successfully (Exit mode 0)
Current function value: -1.0
Iterations: 1
Function evaluations: 3
Gradient evaluations: 1
Performing optimizations with Serial Refine...
[Serial Refine] Processing pass=0, turbine_depth=0 (0.0%)
[Serial Refine] Processing pass=0, turbine_depth=1 (16.7%)
[Serial Refine] Processing pass=0, turbine_depth=2 (33.3%)
[Serial Refine] Processing pass=1, turbine_depth=0 (50.0%)
[Serial Refine] Processing pass=1, turbine_depth=1 (66.7%)
[Serial Refine] Processing pass=1, turbine_depth=2 (83.3%)
Performing optimizations with Geometric Yaw...
Time spent, Geometric Yaw: 0.12 s.
Time spent, Serial Refine: 0.76 s.
Time spent, SciPy (SLSQP): 31.75 s.