Engineering Wind Farm Models Object
In PyWake, the pre defined wind farm models encompass all engineering models available that have been implemented from literature and adapdated to work with PyWake’s capabilities. Each of the model comes with default settings in terms of wake deficit models, superposition models, turbulence models, etc. However, these are easily customizable to study the impact of different models on the results.
The wind farm models are inherited from two base classes: PropagateDownwind
and All2AllIterative
.
PropagateDownwind
The PropagateDownwind
wind farm model is very fast as it only performs a minimum of deficit calculations. It iterates over all turbines in downstream order. In each iteration it calculates the effective wind speed at the current wind turbine as the free stream wind speed minus the sum of the deficit from upstream sources. Based on this effective wind speed, it calculates the deficit caused by the current turbine on all downstream destinations. Note, that this procedure neglects upstream
blockage effects.
for wt in wind turbines in downstream order:
ws_eff[wt] = ws[wt] - superposition(deficit[from_upstream_src,to_wt])
ct = windTurbines.ct(ws_eff[wt])
deficit[from_wt,to_downstream_dst] = wakeDeficitModel(ct, distances[from_wt,to_downstream_dst], ...)
The proceedure is illustrated in the animation below:
Iteration 1: WT0 sees the free wind (10m/s). Its deficit on WT1 and WT2 is calculated.
Iteration 2: WT1 sees the free wind minus the deficit from WT0. Its deficit on WT2 is calculated and the effective wind speed at WT2 is updated.
In PyWake, the class is represented as follows:
def __init__(self, site, windTurbines, wake_deficitModel,
superpositionModel=LinearSum(),
deflectionModel=None, turbulenceModel=None, rotorAvgModel=None,
inputModifierModels=[]):
where a Site and Wind Turbine objects are necessary for the calculation. In addition, a wake deficit model must be provided. By default, the class uses the Linear Sum technique to add the wakes from downstream turbines. In the general class, the deflection, turbulence and rotor average model are set to None
, which can be overwritten for each pre-defined engineering wind farm model.
All2AllIterative
The All2AllIterative
wind farm model is slower but is capable of handling blockage effects. It iterates until the effective wind speed converges (i.e. less than or equal to the maximum number of turbines that affect each other in the wind farm. The converge tolerance is an input parameter. In each iteration it sums up the deficit from all wind turbine sources and calculates the deficit caused by the all wind turbines turbine on all wind turbines.
while ws_eff not converged:
ws_eff[all] = ws[all] - superposition(deficit[from_all,to_all])
ct[all] = windTurbines.ct(ws_eff[all])
deficit[from_all,to_all] = wakeDeficitModel(ct[all], distances[from_all,to_all], ...)
The proceedure is illustrated in the animation below:
Iteration 1: All three WT see the free wind (10m/s) and their CT values and resulting deficits are therefore equal.
Iteration 2: The local effective wind speeds are updated taking into account the wake and blockage effects of the other WT. Based on these wind speeds the CT and deficits are recalculated.
Iteration 3: Repeat after which the flow field has converged.
Similarly, the All2AllIterative
class is defined in PyWake as:
def __init__(self, site, windTurbines, wake_deficitModel,
superpositionModel=LinearSum(),
blockage_deficitModel=None, deflectionModel=None, turbulenceModel=None,
convergence_tolerance=1e-6, rotorAvgModel=None, inputModifierModels=[]):
In addition to the parameters specified in the PropagateDownwind
class, here we determine a convergence tolerance in terms of the maximum accepted change in WS_eff_ilk
in m/s. In this case, the blockage deficit model is set to None
as default, but this should be changed depending on the engineering wind farm model used.
An example of how some wind farm models are defined in PyWake are shown below.
Predefined Wind Farm Models
The pre-defines wind farm models are adapted from the literature, where their corresponding default superposition model, turbulence model and calibration parameters are taken from the paper describing each model.
The engineering wind farm models comprise:
Reference |
Name |
WindFarm Model |
Wake Deficit Model |
Blockage Deficit Model |
Superposition Model |
Turbulence Model |
---|---|---|---|---|---|---|
Jensen_1983 |
||||||
Ott_Nielsen_2014 |
||||||
Ott_Nielsen_2014_Blockage |
||||||
Bastankhah_PorteAgel_2014 |
||||||
IEA37CaseStudy1 |
||||||
Niayifar_PorteAgel_2016 |
||||||
Zong_PorteAgel_2020 |
` ZongGaussianDeficit <WakeDeficitModels.ipynb#ZongGaussianDeficit>`__ |
|||||
Nygaard_2022 |
||||||
Blondel_Cathelain_2020 |
Default rotor-average model:
RotorCenter
Default turbulence model:
None
All models require a Site
and a WindTurbine
object to run, and each of them may require additional inputs such as calibration parameters. The parameters shown are the default and used in the literature, but if necessary, they can be modified to better suit a particular case study.
In the case of Fuga, a file with look up tables is needed; the file is created by specifying the turbine’s rotor diameter, hub height and roughness length of the site to study.
For information on the calculation of the velocity deficit for each model, please refer to the Wake Deficit Models notebook.
Below are some examples of different wind farm models under the PropagateDownwind
base class. The full set of pre-defined wind farm models can be found in PyWake’s repository under the literature folder.
1) Bastankhah Gaussian
class Bastankhah_PorteAgel_2014(PropagateDownwind):
def __init__(self, site, windTurbines, k=0.0324555, ceps=.2, ct2a=ct2a_madsen, use_effective_ws=False,
rotorAvgModel=None, superpositionModel=SquaredSum(),
deflectionModel=None, turbulenceModel=None, groundModel=None):
2) Niayifar Gaussian
class Niayifar_PorteAgel_2016(PropagateDownwind):
def __init__(self, site, windTurbines, a=[0.38, 4e-3], ceps=.2, superpositionModel=LinearSum(),
deflectionModel=None, turbulenceModel=CrespoHernandez(), rotorAvgModel=None, groundModel=None,
use_effective_ws=True, use_effective_ti=True):
3) Zong Gaussian
class Zong_PorteAgel_2020(PropagateDownwind):
def __init__(self, site, windTurbines, a=[0.38, 4e-3], deltawD=1. / np.sqrt(2), lam=7.5, B=3,
rotorAvgModel=None, superpositionModel=WeightedSum(), deflectionModel=None,
turbulenceModel=CrespoHernandez(), groundModel=None, use_effective_ws=True, use_effective_ti=True):
3) TurbOPark
class Nygaard_2022(PropagateDownwind):
def __init__(self, site, windTurbines):
wake_deficitModel = TurboGaussianDeficit(
ct2a=ct2a_mom1d,
groundModel=Mirror(),
rotorAvgModel=GaussianOverlapAvgModel())
4) Fuga
class Ott_Nielsen_2014(PropagateDownwind):
def __init__(self, LUT_path, site, windTurbines,
rotorAvgModel=None, deflectionModel=None, turbulenceModel=None, remove_wriggles=False):
In addition, Fuga’s wind farm model comes with the possibility of modeling blockage. For this, the All2AllIterative
base class is used.
class Ott_Nielsen_2014_Blockage(All2AllIterative):
def __init__(self, LUT_path, site, windTurbines, rotorAvgModel=None,
deflectionModel=None, turbulenceModel=None, convergence_tolerance=1e-6, remove_wriggles=False):