Unconstrained wake steering optimization
In TOPFARM, it is also possible to perform an active yaw control optimization, or wake steering, where the objective function is still the AEP but now the turbines are allowed to yaw to find a better configuration and increase the AEP of a wind farm.
When using yaw angles as design variables, it is important to include a wake deflection model, as this will allow for a more accurate representation of the wake behind a turbine when subject to yaw misalignment.
Install Topfarm if needed
[1]:
# Install TopFarm if needed
import importlib
if not importlib.util.find_spec("topfarm"):
%pip install git+https://gitlab.windenergy.dtu.dk/TOPFARM/TopFarm2.git
We import first the site and wind turbines to use as well as the Jimenez wake deflection model. In addition, we import the CostModelComponent to use for the optimization.
[2]:
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
[3]:
from py_wake.examples.data.lillgrund import LillgrundSite
from py_wake.deflection_models.jimenez import JimenezWakeDeflection
from py_wake.examples.data.iea37 import IEA37_WindTurbines
from py_wake.deficit_models.gaussian import IEA37SimpleBastankhahGaussian
from topfarm.cost_models.cost_model_wrappers import CostModelComponent
from topfarm import TopFarmProblem
from topfarm.plotting import NoPlot
from topfarm.easy_drivers import EasyScipyOptimizeDriver
We set up the site and wind turbines to use. In this example, we will use the Lillgrund site with IEA 3.4MW wind turbines. Since the yaw angles depend on the number of turbines, wind speed and wind directions studied, these must be selected before using PyWake’s wind farm simulation tool.
[4]:
site = LillgrundSite()
windTurbines = IEA37_WindTurbines()
wf_model = IEA37SimpleBastankhahGaussian(site, windTurbines,deflectionModel=JimenezWakeDeflection())
#choosing the flow cases for the optimization
wsp = np.asarray([10])
wdir = np.asarray([270])
#getting initial position of turbines
x,y = site.initial_position.T
x = x[::2]
y = y[::2]
n_wt = x.size
#setting up yaw angles for each turbine, wind direction and wind speed
i = n_wt
k = wsp.size
l = wdir.size
yaw_zero = np.zeros((i,l,k)) #initial condition of yaw angles
Now we can set up our AEP function, that calculates the AEP of each turbine while considering the yaw angles.
[5]:
def aep_func(yaw_ilk):
simres = wf_model(x,y,wd=wdir,ws=wsp,yaw=yaw_ilk, tilt=0)
aep = simres.aep().sum()
return aep
Specifying the cost component and topfarm problem
[6]:
cost_comp = CostModelComponent(input_keys=[('yaw_ilk', np.zeros((i, l, k)))],
n_wt = n_wt,
cost_function = aep_func,
objective=True,
maximize=True,
output_keys=[('AEP', 0)]
)
maxiter=30
tol=1e-4
ec=1e-4
problem = TopFarmProblem(design_vars={'yaw_ilk': (yaw_zero, -30, 30)}, #setting up initial values and lower and upper bounds for yaw angles
n_wt=n_wt,
cost_comp=cost_comp,
driver=EasyScipyOptimizeDriver(optimizer='SLSQP', maxiter=maxiter, tol=tol),
plot_comp=NoPlot(),
expected_cost=ec)
[7]:
_, state,_ = problem.optimize()
Iteration limit reached (Exit mode 9)
Current function value: -1384947.6773303992
Iterations: 30
Function evaluations: 92
Gradient evaluations: 31
Optimization FAILED.
Iteration limit reached
-----------------------------------
Now we can plot the wake map of the wind farm to visualize the final yaw angles of each turbine.
[8]:
# simulationResult = wf_model(x,y,wd=wdir[0], ws=wsp[0], yaw=state['yaw_ilk'][:,0,0], tilt=0)
# plt.figure(figsize=(12,4))
# simulationResult.flow_map().plot_wake_map()
# plt.xlabel('x [m]')
# plt.ylabel('y [m]')