# Unconstrained turbulence

The basic function for all turbulence generation is the `gen_turb`

function, which can be used both with and without constraining time series. In this notebook, we will show it being used without any constraining time series. We will generate a turbulence box that follows IEC 61400-1 Ed. 3 specifications.

This notebook demonstrates the following:

To specify custom functions for the mean wind speed, turbulence standard deviation, or power spectrum as a function of \(y\) and \(z\), please see the related example in the sidebar.

## Preliminaries: importing functions

We begin by importing the necessary functions so we can use them.

```
[1]:
```

```
%matplotlib inline
import matplotlib.pyplot as plt # matplotlib for some plotting
import numpy as np # numeric python functions
import pandas as pd # need this to load our data from the csv files
from pyconturb import gen_turb, gen_spat_grid # generate turbulence, useful helper
from pyconturb.sig_models import iec_sig # IEC 61400-1 turbulence std dev
from pyconturb.spectral_models import kaimal_spectrum # Kaimal spectrum
from pyconturb.wind_profiles import constant_profile, power_profile # wind-speed profile functions
from _nb_utils import plot_slice
```

## Defining the simulation points manually

The only required input to the `gen_turb`

function is a Pandas dataframe that specifies the xyz locations of the simulation points to be simulated and the turbulence components to be simulated at each point. This dataframe is referred to as the *spatial dataframe* (`spat_df`

), and it must have the following rows: * `k`

(turbulence component, 0=\(u\), 1=\(v\) and 2=\(w\)), * `x`

(along-wind location of the simulation point; positive is downwind), * `y`

(lateral
location of the simulation point; positive is to the left looking downwind) and * `z`

(vertical location of the simulation point; positive is upwards).

The columns may be named for the user’s convenience, but PyConTurb does not require it.

Note that the x-value will often be 0 for standard simulations in a y-z plane that is parallel to the incoming wind.

As an example, consider the following spatial dataframe:

```
[2]:
```

```
spat_df = pd.DataFrame([[0, 1, 2],
[0, 0, 0],
[0, 0, -10],
[15, 15, 30]], index=['k', 'x', 'y', 'z'],
columns=['pointA_u', 'pointA_v', 'pointB_w']) # column names are optional
spat_df # let's look at it
```

```
[2]:
```

pointA_u | pointA_v | pointB_w | |
---|---|---|---|

k | 0 | 1 | 2 |

x | 0 | 0 | 0 |

y | 0 | 0 | -10 |

z | 15 | 15 | 30 |

This spatial dataframe will tell PyConTurb to simulate the \(u\) and \(v\) components at Point A, located at \((0, 0, 15)\), and the \(w\) component at Point B, located at \((0, -10, 30)\). We can run a quick simulation to see the result.

```
[3]:
```

```
turb_df = gen_turb(spat_df, T=60, dt=0.5, u_ref=10)
turb_df.head() # show just the first few row
```

```
[3]:
```

u_p0 | v_p0 | w_p1 | |
---|---|---|---|

0.0 | 6.276168 | -2.602351 | -1.412486 |

0.5 | 7.105002 | -0.019472 | -0.998736 |

1.0 | 9.171079 | 1.110533 | 1.092972 |

1.5 | 7.740324 | -0.351597 | 1.077588 |

2.0 | 6.194271 | -1.021853 | 1.357559 |

The output is another Pandas dataframe, this one referred to as the *turbulence dataframe*. Each column of the dataframe corresponds to a different column in `spat_df`

, and the index of the dataframe (i.e., the rows) are the time steps. As expected, the generated `turb_df`

has the \(u\) and \(v\) components at Point A (renamed to 0) and the \(w\) component at Point B (renamed to 1).

**Notes**:

`spat_df`

. A column name `u_p0`

indicates the longitudinal component at Point 0. PyConTurb numbers the points by unique xyz locations, going from left to right. In other words, the leftmost unique xyz coordinate is Point 0, the next unique xyz location is Point 1, etc.Here is a quick demo of some visualization/filtering abilities.

```
[4]:
```

```
turb_df.u_p0.plot(); # plot the u_p0 channel
```

```
[5]:
```

```
turb_df[(turb_df.index > 10) & ((turb_df.index < 30))].w_p1.max() # max of w_p0 between 10 and 30 seconds
```

```
[5]:
```

```
2.4960612399067545
```

```
[6]:
```

```
turb_df.describe() # show statistics for the turbulence dataframe
```

```
[6]:
```

u_p0 | v_p0 | w_p1 | |
---|---|---|---|

count | 120.000000 | 1.200000e+02 | 1.200000e+02 |

mean | 6.988271 | -1.480297e-17 | -7.401487e-18 |

std | 2.096000 | 1.676800e+00 | 1.048000e+00 |

min | 2.363388 | -3.043431e+00 | -2.594625e+00 |

25% | 5.261389 | -1.188543e+00 | -6.965065e-01 |

50% | 6.850676 | -1.911416e-01 | -2.081711e-01 |

75% | 8.434220 | 1.283614e+00 | 7.343218e-01 |

max | 11.486009 | 4.135347e+00 | 2.658873e+00 |

```
[7]:
```

```
turb_df.std()/turb_df.mean().u_p0 # turbulence intensities
```

```
[7]:
```

```
u_p0 0.299931
v_p0 0.239945
w_p1 0.149966
dtype: float64
```

## Easily defining a y-z simulation grid

In most of our applications, our turbulence box is a regular, rectangular grid, and we want to simulate the same component(s) at each point. In this case, the built-in function `gen_spat_grid`

is useful for generating a spatial grid. The function takes a 1D array of the lateral points you want to simulate and a 1D array of the vertical points you want to simulate. By default, the point numbering will place Point 0 at the most-negative \(y\) and \(z\) locations. The numbering will then
proceed vertically before proceeding laterally.

Here are a few examples of using `gen_spat_grid`

.

```
[8]:
```

```
y = [-10, 10] # two lateral locations
z = [90] # one vertical location
gen_spat_grid(y, z, comps=[0, 2]) # only want longitudinal + vertical components
```

```
[8]:
```

u_p0 | w_p0 | u_p1 | w_p1 | |
---|---|---|---|---|

k | 0 | 2 | 0 | 2 |

x | 0 | 0 | 0 | 0 |

y | -10 | -10 | 10 | 10 |

z | 90 | 90 | 90 | 90 |

```
[9]:
```

```
y = np.linspace(-50, 50, 11) # 11 lateral points from -50 to 50 (center @ 0)
z = np.linspace(40, 160, 13) # 13 vertical points from 40 to 160 (center @ 100)
spat_df = gen_spat_grid(y, z) # if `comps` not passed in, assumes all 3 components are wanted
spat_df.head() # look at the first few rows
```

```
[9]:
```

u_p0 | v_p0 | w_p0 | u_p1 | v_p1 | w_p1 | u_p2 | v_p2 | w_p2 | u_p3 | ... | w_p139 | u_p140 | v_p140 | w_p140 | u_p141 | v_p141 | w_p141 | u_p142 | v_p142 | w_p142 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

k | 0.0 | 1.0 | 2.0 | 0.0 | 1.0 | 2.0 | 0.0 | 1.0 | 2.0 | 0.0 | ... | 2.0 | 0.0 | 1.0 | 2.0 | 0.0 | 1.0 | 2.0 | 0.0 | 1.0 | 2.0 |

x | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |

y | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | -50.0 | ... | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 | 50.0 |

z | 40.0 | 40.0 | 40.0 | 50.0 | 50.0 | 50.0 | 60.0 | 60.0 | 60.0 | 70.0 | ... | 130.0 | 140.0 | 140.0 | 140.0 | 150.0 | 150.0 | 150.0 | 160.0 | 160.0 | 160.0 |

4 rows × 429 columns

This spatial dataframe can easily be passed into `gen_turb`

to simulate unconstrained turbulence at the specified grid.

```
[10]:
```

```
turb_df = gen_turb(spat_df, T=10, dt=2, u_ref=10)
```

We can use the matplotlib function `imshow`

to visualize slices of the turbulence at certain times.

```
[11]:
```

```
t = 0
ax = plot_slice(spat_df, turb_df, val=t)
ax.set_title(f'Turbulence slice at t = {t}');
```

## Using built-in profile functions

Until this point, we have used the default parameters in `gen_turb`

, which has hidden from view many things. Something that many users may find useful (or want to change), is how the values for the mean wind speed, turbulence standard deviation, and power spectra change with \(y\)- and \(z\)-coordinates. These functions are collectively called the *profile functions*.

We start by using Jupyter’s built-in help function to get the list of optional arguments for `gen_turb`

. (Note that this list does not include keyword arguments for any subfunctions.)

```
[12]:
```

```
?gen_turb
```

The profile functions are `wsp_func`

, `sig_func`

and `spec_func`

. If no values are passed in for these functions (which is what we had in the earlier examples), they will by default take the IEC 61400-1 values for an unconstrainted simulation. More details on the profile functions can be found in their respective documentation sections.

Below are examples of how you manually specify the profile functions if you don’t want the IEC defaults.

```
[13]:
```

```
y, z = [-10, 0, 10], [70, 80, 90] # first define our turbulence grid locations
spat_df = gen_spat_grid(y, z)
```

**Wind speed profile**

The values for the profiles functions can be placed in a single keyword-argument dictionary, like in `kwargs`

below. The necessary arguments for each profile function are listed in the function’s documentation function.

```
[14]:
```

```
# specify mean wind speed profile function (constant_profile or power_profile)
wsp_func = constant_profile
# define simulation arguments
kwargs = {'u_ref': 6, 'z_ref': 80, 'T': 60, 'dt': 1}
# simulate turbulence
turb_df = gen_turb(spat_df, wsp_func=wsp_func, **kwargs)
# plot the spatial variation of the mean wind speed
ax = plot_slice(spat_df, turb_df, val='mean')
ax.set_title(f'Mean of turbulence box');
```

**Turbulence standard deviation profile**

The main keyword argument for the IEC standard deviation is the turbulence class, `turb_class`

.

Note that the standard deviation will not match the theory at all spatial points due to the spatial correlation procedure inherent withing the KSEC method.

```
[15]:
```

```
# specify standard deviation profile function
sig_func = iec_sig
# define simulation arguments
kwargs = {'turb_class': 'C', 'T': 60, 'dt': 1, 'u_ref': 10}
# simulate turbulence
turb_df = gen_turb(spat_df, sig_func=sig_func, **kwargs)
# plot the spatial variation of the mean wind speed
ax = plot_slice(spat_df, turb_df, val='std')
ax.set_title(f'Std. dev. of turbulence box');
```

**Power spectrum**

Specify the power spectrum profile using the `spec_func`

input argument.

```
[16]:
```

```
# specify power spectrum profile function
spec_func = kaimal_spectrum
# define simulation arguments
kwargs = {'u_ref': 12, 'T': 60, 'dt': 1, 'u_ref': 10}
# simulate turbulence
turb_df = gen_turb(spat_df, spec_func=spec_func, **kwargs) # no plot, just demo
```

## Specifying custom profile functions

To specify your own functions for the mean wind speed, turbulence standard deviation, or power spectrum as a function of \(y\) and \(z\), please see the related example in the sidebar.