Open and run in Colab (interactive) Edit on Gitlab

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.

PropagateDownwind

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.

All2AllIterative

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

1

Jensen_1983

PropagateDownwind

NOJDeficit

SquaredSum

2

Ott_Nielsen_2014

PropagateDownwind

FugaDeficit

LinearSum

3

Ott_Nielsen_2014_Blockage

All2AllIterative

FugaDeficit

FugaDeficit

LinearSum

4

Bastankhah_PorteAgel_2014

PropagateDownwind

BastankhahGa ussianDeficit

SquaredSum

5

IEA37CaseStudy1

PropagateDownwind

IEA37SimpleBastankhahGaussianDefic it

SquaredSum

6

Niayifar_PorteAgel_2016

PropagateDownwind

Niayifar GaussianDeficit

LinearSum

CrespoHernandez

7

Zong_PorteAgel_2020

PropagateDownwind

` ZongGaussianDeficit <WakeDeficitModels.ipynb#ZongGaussianDeficit>`__

WeightedSum

CrespoHernandez

8

Nygaard_2022

PropagateDownwind

Tu rboGaussianDeficit

SquaredSum

9

Blondel_Cathelain_2020

PropagateDownwind

BlondelSuperG aussianDeficit2020

LinearSum

  • 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):