# Overview

PyWake is an open-source wind farm simulation tool used for studying the interaction between turbines within a wind farm and its influence on the farm’s flow field and power production. Based in Python, PyWake is capable of accurately computing the physics behind wind farms as well as obtaining their AEP. It provides a unified interface to wind farm models of different fidelities, e.g., different engineering models and CFD-RANS (commercial plugin). Given its heavy vectorization and use of numerical libraries, PyWake is a very fast tool that can handle many variables at once.

## The PyWake Philosophy

“Empowering users” underlines the formulation of PyWake. Its highly modular architecture (shown in the figure below) allows users to combine different AEP modelling blocks in all sorts of fashions - giving the flexibility to shape PyWake around the particularities of real-world problems more accurately. Yet with power also comes responsibility - the user needs to make an informed decision when combining the multitude of building blocks PyWake supplies. Essentially, everyone can build their own AEP model chain leveraging PyWake’s flexibility, so there is not one PyWake solution either; users should thus ensure to report the particular PyWake building blocks they used to transparently communicate their results and methodology.

The main object in PyWake’s architecture is the WindFarmModel, which is initialized with a Site and a WindTurbines object. It returns a SimulationResult object containing the calculated effective wind speed, power production, and thrust coefficient of individual turbines. In addition, it relies on methods to calculate the AEP and generate flow maps of entire wind farms.

• Site: for given turbine positions (x, y), reference wind speed (WSref) and wind direction (WDref), the Site object provides the local wind condition in terms of wind speed (WS), wind direction (WD), turbulence intensity (TI), and the probability of each combination of wind direction and wind speed. Furthermore, the Site object is responsible for calculating the down-wind, cross-wind, and vertical distance between wind turbines (which in non-flat terrain is different from the straight-line distances).

• WindTurbines: for a given wind turbine type and effective wind speed (WSeff), the WindTurbines object provides the power curve, thrust coefficient (CT) curve, as well as the wind turbine’s hub height (h) and diameter (D).

The Tutorials section provides examples on how to define both the WindTurbines and Site objects in PyWake.

### Engineering models

The engineering wind farm models (EngineeringWindFarmModel) in PyWake are composed of one or two wind farm models in combination with a wake deficit model, a superposition model, and optionally a blockage deficit and a turbulence model. The two main objects correspond to the PropagateDownwind and All2AllIterative objects. These two define the procedure that determines how wake and blockage deficits propagate in the wind farm. PropagateDownwind does not consider blockage effects whereas All2AllIterative does. The Tutorials section depicts a much more detailed definition of these two.

Whereas a wake deficit model always needs to be selected, all other components are optional. Here is a quick overview of the different building blocks forming part of the engineering model setup:

• Wake Deficit Model: calculates the wake deficit from one turbine to downstream wind turbines or sites in the wind farm. A set of predefined wake models are available in PyWake, please refer to Predefined WindFarm Models for more details.

• groundModel: Option for modelling the ground effect.

• use_effective_ws: Option for using the local wind speed at the rotor to compute the deficit.

• use_effective_ti: Option for using the local turbulence intensity at the rotor to compute TI dependant quantities.

• Blockage Deficit Model: calculates the blockage deficit (speed-ups) from one wind turbine to upstream/downstream turbines or sites in the wind farm.

• Superposition Model: defines how deficits from multiple sources add up.

• Rotor Average Model: defines how the wind speeds are reaching the swept area of a turbine rotor and estimates the rotor-average wind speed.

• Deflection Model: defines the wake deflection due to yaw misalignment, sheared inflow, etc. It does this by modifying the down- and cross- wind distances.

• Turbulence Model: calculates the added turbulence in the wake from one wind turbine to downstream wind turbines or sites in the wind farm.

This list should only serve as a rough overview of the different components constituting the EngineeringWindFarmModel and the available options - please refer to the more detailed description of each component and their respective methods before simulating.

Disclaimer

The specific implementation of the different models might differ from the respective published method, either due to practical reasons, to make it more versatile or to incorporate our own improvements.

### EllipSys 3D (RANS-CDF)

The EllipSys wind farm model is based on a Reynolds-Averaged Navier-Stokes method as implemented in the general purpose flow solver EllipSys3D, initially developed by Jess A. Michelsen at DTU Fluid Mechanics[1,2] and Niels N. Sørensen in connection with his PhD study[3].

EllipSys3D is a closed-source licensed software and it is based on Fortran and MPI. The EllipSys wind farm model uses PyEllipSys, which is a direct memory Python interface to the Fortran version of EllipSys3D. This means that it is possible to import EllipSys3D as a Python object and change flow variables during a simulation.

The wind turbines are represented by actuator discs (AD) and the inflow is an idealized atmospheric boundary layer including effects of Coriolis and atmospheric stability. The main setup uses flat terrain, with a homogeneous roughness length, but the EllipSys wind farm model can also be run with complex terrain. More information can be found here: https://topfarm.pages.windenergy.dtu.dk/cuttingedge/pywake/pywake_ellipsys/.

Installation

The EllipSys wind farm model only runs in a linux environment and it requires the commercial cutting-edge plugin py_wake_ellipsys. Contact us if you are interested to get access to it.

References

1. Jess A. Michelsen, Basis3D - a Platform for Development of Multiblock PDE Solvers, AFM 92-05, Department of Fluid Mechanics, Technical University of Denmark, December 1994.

2. Jess A. Michelsen, Block structured Multigrid solution of 2D and 3D Elliptic PDEs, AFM 94-06, Department of Fluid Mechanics, Technical University of Denmark, May 1994.

3. Niels N. Sørensen, General Purpose Flow Solver Applied to Flow Over Hills, Risø-R-827, Risø National Laboratory, Roskilde, Denmark, 1995.

## General modelling considerations

By Alexander Meyer Forsting (alrf@dtu.dk)

The never ending stream of publications concerning wind farm flows nicely demonstrates the difficulty we are still facing in accurately modelling the aerodynamic phenomena within the field of wind energy. There is currently not a single accepted method that could possibly capture the extensive range of flow scales we are dealing with - from aerofoil boundary layers to farm-to-farm interactions - especially not one that is sufficiently cheap to allow AEP predictions. Engineering wind farm models present a reasonable balance between accuracy and costs for wind farm AEP simulations, yet they rely on multiple sub-models that need to be selected wisely according to the problem at hand. A certain model and parameter combination might work for one particular case but not another - as demonstrated in an endless number of published model comparisons/validations. PyWake’s engineering wind farm models are therefore also completely modular, allowing to combine different single wake models with different superposition, blockage, turbulence and deflection models to simulate wind farm flows. Each respective model is also configurable and its parameters tunable.

The sheer amount of possible sub-model combinations and settings can be overwhelming, so here we would like to give a very general guidance on how to combine them and what choices to consider.

1) Selection of the superposition model

Here you mainly have to decide between SquaredSum or LinearSum. The former does not really have a clear physical foundation, but was found to give some promising results in deep-arrays, as it isolates the most severe deficits, much like MaxSum. Beware, though, that its successful application largely depends on how the deficits are calculated inside the farm. Depending on the control volume one considers, one could either use the wind farm free-stream wind speed (even for turbines inside the array) or the incoming wind speed at each turbine (if isolating individual turbines). When studying a single turbine, the deficits from upstream turbines (and blockage from upstream/downstream) is included. Whilst physically it is hard to argue for using the free-stream velocity inside the array, one could choose to do so, as many have done before; however, it is then imperative to avoid using LinearSum. Since PyWake uses the effective wind speed at each turbine to calculate the thrust, power and deficit, if the free-stream velocity is chosen as effective wind speed the deficits will be extremely large - even inside the array - and the flow speed can turn negative when summing them linearly. A more consistent approach (in line with using single wake models) is to use the turbine’s incoming wind speed as effective wind speed by setting use_effective_ws=True. Then, the deficits are to be combined with the LinearSum model. Note that the SquaredSum actually leads to double counting (see Park2 model description for details).

There is also the WeightedSum approach by Zong et al but it is only available for Gaussian wake deficit models so far, and tends towards the LinearSum results. It is an iterative method with high memory requirements and only differs from the LinearSum when combining extremely deep deficits. It should individually be judged whether its benefits outweigh the additional costs. A more lightweight alternative constitutes Bastankhah et al’s CumulativeWakeSum, which was derived for the Gaussian wake models. Despite its theoretical foundation it ultimately still relies on empiricism and its accuracy is fully dependant on the optimal configuration of the underlying wake deficit model (same applies to the Zong superposition model performance).

2) Selection of the wake deficit model and its configuration

Here the general recommendation is to use a Gaussian type model. They can conserve deficit momentum (in isolation) and avoid singular behavior (step changes). In addition, they are faster than the top-hat model. The available Gaussian model versions differ in their formulation of the streamwise wake expansion, which is governed by the initial wake diameter (at the wake origin) and its rate of expansion with downstream distance. The expansion can be constant (pre-set by user) or based on the effective turbulence intensity (TI). Increasing TI leads to greater mixing and thus quicker expansion/deficit attenuation (users can change the coefficients if desired).

When using a turbulence model, the wake added turbulence in a farm is combined (the superposition of TI is another area of great uncertainty, but can also be modified by the user) and leads to spatially varying TI. As with the deficit, the user can choose to use the local TI at the rotor (use_effective_ti=True) or the free-stream TI. Whilst physically one might argue for using the local TI, this approach leads to excessive wake expansion deep inside the array when summing all contributions. Thus, the wake added turbulence is overestimated, making the free-stream TI a better reference for the wake expansion set up given the simplistic representation of turbulence by a single figure and its connection to wake expansion. The free-stream TI describes the atmospheric turbulence and thus also the larger scales contributing to wake-meandering and wake breakdown. On the other hand, the wake-added turbulence is small scale and dissipates quicker; therefore, it contributes differently to wake mixing and its superposition is not straight forward. For this reason, the Fuga and Dynamic Wake Meandering (DWM) models simulate only the free-stream TI governs wake expansion, as it is also the case in the more recent TurbOPark. One should also keep in mind that the Gaussian wake shape is a time-averaged solution, that incorporates meandering, shear-layer breakdown and mixing without differentiating between them.

Classically, Gaussian models are far-wake models, so the near-wake is rather crude. Shapiro et al introduced a smooth growth in the deficit, which also forms part of the Zong deficit model (not to be confused with the superposition model). The latter also sets the initial wake diameter by the near-wake length to capture the effect of TI and tip speed ratio on near-wake breakdown and subsequent far-wake onset. Other near-wake updates exist, yet their value is limited in AEP computations as turbines are usually placed outside this region in wind farms.

3) Simulation of the ground effect

In PyWake it is also possible to introduce a mirror plane to represent the ground effect, i.e turbines mirrored in the ground plane. This is a method commonly employed in vortex models, as it enforces zero wall normal velocity. However, while highly recommended for blockage modelling, it is less obvious whether to use a mirror plane for wakes. Wake models are generally tuned to measurement or simulation data that intrinsically contain the ground effect - so additional modelling could lead to double counting. This is also the reason why the groundModel can be set separately for blockage and wake models.

4) Implementation of a wind turbine model

PyWake uses power and CT curves, which can also be multi-dimensional (more suited to wind farm simulations), which need to be a function of the free-stream (reference) wind speed. In PyWake, a turbine’s blockage and wake effects on itself, as well as its own mirror contributions (performance curves already include the ground effect), are zero. Thus, the wind speed at the rotor can be used to interpolate power and CT from the reference curves. The velocity at the rotor can be computed in different ways using the rotorAvgModel object. The default is extracting the velocity at the rotor-centre, however one can also opt for more rotor-equivalent wind speed quantities. Yet, one should consider that a turbine’s performance curves are usually generated by using the rotor-centre velocity. The wind speed used for interpolation and deficit computation are always identical. As the power and CT curves are non-linear, users are advised to use higher-order splines in their interpolation (for instance pchip). A final issue relates to the often singular behaviour of power/thrust curves around cut-in and cut-out. Firstly, sudden jumps in production can occur around those wind-speeds as turbines are close to switch on/off, so even small changes in wind speed/direction can lead to strong relative changes. Secondly, in combination with blockage there is no definite solution, as some turbines might be on or off - either would be correct. This is mostly related to the downstream speed-up that blockage can cause in addition to upstream deficit. In the All2AllIterative model, on/off oscillations are avoided by tracking unstable turbines and switching them all off.

We hope the above recommendations will help you getting started with PyWake and enjoy exploring its flexibility in your own work. We are happy to receive any comments, suggestions and ideas for collaboration.

The PyWake Team