Turbine-based ambient flow data

In some cases the inflow data is directly known at the turbine locations, in terms of (state, turbine)-type data. Such data can be simulated with foxes by using the TurbinePointCloud states class, as demonstrated here.

We start by importing the necessary packages and setting up the engine:

%matplotlib inline
import numpy as np
from xarray import Dataset, date_range
import matplotlib.pyplot as plt

import foxes
import foxes.variables as FV
/home/runner/work/foxes/foxes/foxes/core/engine.py:6: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)
  from tqdm.autonotebook import tqdm
engine = foxes.Engine.new("default", verbosity=0)

The first step is the creation of a regular grid of wind turbines:

n_turbines_x = 2
n_turbines_y = 3
n_turbines = n_turbines_x * n_turbines_y

farm = foxes.WindFarm()
foxes.input.farm_layout.add_grid(
    farm,
    xy_base=[1000, 1000],
    step_vectors=[[500, 0], [0, 500]],
    steps=[n_turbines_x, n_turbines_y],
    turbine_models=["DTU10MW"],
    verbosity=0,
)
o = foxes.output.FarmLayoutOutput(farm)
o.get_figure()
plt.show()
../_images/d3c6630c30f463a58896281ed7d2b013642139cf039188e3db001ba1a1df5470.png

Next, let’s create an artificial Dataset object that represents data with (time, turbine) dimensions, representing a timeseries in January 2026 measured at he turbines of the above wind farm:

n_times = 10
times = date_range("2026-01-01", periods=n_times, freq="10min", unit="s")
times
DatetimeIndex(['2026-01-01 00:00:00', '2026-01-01 00:10:00',
               '2026-01-01 00:20:00', '2026-01-01 00:30:00',
               '2026-01-01 00:40:00', '2026-01-01 00:50:00',
               '2026-01-01 01:00:00', '2026-01-01 01:10:00',
               '2026-01-01 01:20:00', '2026-01-01 01:30:00'],
              dtype='datetime64[s]', freq='10min')
np.random.seed(42)

# Turbine i has wind speed (10 + i.x) m/s, where x grows linear with time
ws = np.zeros((n_times, n_turbines))
ws[:] = 10 + np.arange(n_turbines)[None, :]
ws += np.linspace(0, 1, n_times, endpoint=False)[:, None]

# the wind directions are randomly selected from a southern sector:
wd = np.random.uniform(0, 190, (n_times, n_turbines))

sdata = Dataset(
    coords={"time": times},
    data_vars={
        "ws": (("time", "turbine"), ws),
        "wd": (("time", "turbine"), wd),
        "ti": ("time", 0.1 + np.arange(n_times) / 100),
        "rho": ("turbine", 1.2 + np.arange(n_turbines) / 100),
    },
)
sdata
<xarray.Dataset> Size: 1kB
Dimensions:  (time: 10, turbine: 6)
Coordinates:
  * time     (time) datetime64[s] 80B 2026-01-01 ... 2026-01-01T01:30:00
Dimensions without coordinates: turbine
Data variables:
    ws       (time, turbine) float64 480B 10.0 11.0 12.0 13.0 ... 13.9 14.9 15.9
    wd       (time, turbine) float64 480B 71.16 180.6 139.1 ... 8.593 61.81
    ti       (time) float64 80B 0.1 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19
    rho      (turbine) float64 48B 1.2 1.21 1.22 1.23 1.24 1.25

This is what the wind speed per turbine looks like, increasing linearly with time as described above:

for t in range(0, n_times):
    plt.scatter(sdata["turbine"], sdata["ws"][t])
plt.xticks(sdata["turbine"])
plt.xlabel("turbine")
plt.ylabel("ws [m/s]")
plt.show()
../_images/cdcde931bcb49c4a5b8be8aa36658abbd5dc7549bf26cf9480cefa0ecb826a90.png

The data frame sdata is the base for our ambient states object:

states = foxes.input.states.TurbinePointCloud(
    data_source=sdata,
    states_coord="time",
    turbine_coord="turbine",
    output_vars=[FV.WS, FV.WD, FV.TI, FV.RHO],
    var2ncvar={
        FV.WS: "ws",
        FV.WD: "wd",
        FV.TI: "ti",
        FV.RHO: "rho",
    },
)

Next, let’s create the algorithm object:

algo = foxes.algorithms.Downwind(
    farm=farm,
    states=states,
    wake_models=["TurbOPark"],
    rotor_model="centre",
)

We now run the farm calculation:

with engine:
    farm_results = algo.calc_farm()
Initializing model 'TurbinePointCloud'

Initializing algorithm 'Downwind'

------------------------------------------------------------
  Algorithm: Downwind
  Running Downwind: calc_farm
------------------------------------------------------------
  n_states : 10
  n_turbines: 6
------------------------------------------------------------
  states    : TurbinePointCloud()
  rotor     : CentreRotor()
  controller: BasicFarmController()
  deflection: NoDeflection()
  wake frame: RotorWD()
  wake lngth: None
------------------------------------------------------------
  wakes:
    0) TurbOPark: TurbOParkWake(ws_quadratic_amb_target, induction=Betz, k=0.04*AMB_TI)
------------------------------------------------------------
  partial wakes:
    0) TurbOPark: gaussian, PartialGaussian(min_weight=1e-08)
------------------------------------------------------------
  turbine models:
    0) DTU10MW: PCtFile(D=178.3, H=119.0, P_nominal=10000.0, P_unit=kW, rho=1.225, var_ws_ct=REWS, var_ws_P=REWS)
------------------------------------------------------------


--------------------------------------------------
  Model oder
--------------------------------------------------
00) basic_ctrl
01) InitFarmData
02) centre
03) basic_ctrl
  03.0) Post-rotor: DTU10MW
04) SetAmbFarmResults
05) FarmWakesCalculation
06) ReorderFarmOutput
--------------------------------------------------


Input data:

 <xarray.Dataset> Size: 2kB
Dimensions:                  (state: 10, turbine: 6,
                              TurbinePointCloud_vars0: 2,
                              TurbinePointCloud_vars1: 1,
                              TurbinePointCloud_vars2: 1, DTU10MW_WS: 22,
                              DTU10MW_vars: 2, tmodels: 1)
Coordinates:
  * state                    (state) datetime64[s] 80B 2026-01-01 ... 2026-01...
  * TurbinePointCloud_vars0  (TurbinePointCloud_vars0) <U2 16B 'WS' 'WD'
  * TurbinePointCloud_vars1  (TurbinePointCloud_vars1) <U2 8B 'TI'
  * TurbinePointCloud_vars2  (TurbinePointCloud_vars2) <U3 12B 'RHO'
  * DTU10MW_WS               (DTU10MW_WS) float64 176B 4.0 5.0 6.0 ... 24.0 25.0
  * DTU10MW_vars             (DTU10MW_vars) <U2 16B 'P' 'CT'
  * tmodels                  (tmodels) <U7 28B 'DTU10MW'
Dimensions without coordinates: turbine
Data variables:
    TurbinePointCloud_data0  (state, turbine, TurbinePointCloud_vars0) float64 960B ...
    TurbinePointCloud_data1  (state, TurbinePointCloud_vars1) float64 80B 0.1...
    TurbinePointCloud_data2  (turbine, TurbinePointCloud_vars2) float64 48B 1...
    DTU10MW_data             (DTU10MW_WS, DTU10MW_vars) float64 352B 280.2 ..... 

Extra data:
  TurbinePointCloud_meta: dict

Farm variables: AMB_CT, AMB_P, AMB_REWS, AMB_RHO, AMB_TI, AMB_WD, AMB_YAW, CT, D, H, P, REWS, RHO, TI, WD, X, Y, YAW, order, order_inv, order_ssel, weight

Output variables: AMB_CT, AMB_P, AMB_REWS, AMB_RHO, AMB_TI, AMB_WD, AMB_YAW, CT, D, H, P, REWS, RHO, TI, WD, X, Y, YAW, order, order_inv, order_ssel, weight

The results demonstrate that all data was correctly passed from the flow states to ambient variables:

farm_results.to_dataframe()[
    [FV.AMB_WD, FV.AMB_RHO, FV.AMB_TI, FV.AMB_REWS, FV.REWS, FV.P]
]
AMB_WD AMB_RHO AMB_TI AMB_REWS REWS P
state turbine
2026-01-01 00:00:00 0 71.162623 1.20 0.10 9.931505 9.198372 5703.525196
1 180.635718 1.21 0.10 10.954918 10.921840 9509.794691
2 139.078849 1.22 0.10 11.983651 8.060716 3826.697881
3 113.745112 1.23 0.10 13.017663 13.017663 10648.337500
4 29.643542 1.24 0.10 14.056911 14.056911 10641.826857
5 29.638959 1.25 0.10 15.101354 15.101354 10679.473520
2026-01-01 00:10:00 0 11.035886 1.20 0.11 10.030820 10.030819 7360.829534
1 164.573468 1.21 0.11 11.054508 9.185939 5678.973026
2 114.211852 1.22 0.11 12.083515 11.028848 9725.440640
3 134.533790 1.23 0.11 13.117799 13.117799 10647.416250
4 3.911054 1.24 0.11 14.157318 14.157317 10646.284884
5 184.282872 1.25 0.11 15.202030 15.202030 10675.275344
2026-01-01 00:20:00 0 158.164102 1.20 0.12 10.130135 10.005078 7298.747150
1 40.344431 1.21 0.12 11.154098 11.152484 9841.756915
2 34.546744 1.22 0.12 12.183379 11.513966 10181.839297
3 34.846857 1.23 0.12 13.217935 13.217935 10646.495000
4 57.806026 1.24 0.12 14.257724 14.257724 10650.742955
5 99.703722 1.25 0.12 15.302706 15.302706 10671.077167
2026-01-01 00:30:00 0 82.069554 1.20 0.13 10.229450 9.952056 7191.824198
1 55.333537 1.21 0.13 11.253688 11.253553 9936.842552
2 116.252050 1.22 0.13 12.283242 12.228697 10641.249753
3 26.503834 1.23 0.13 13.318071 13.318071 10645.573750
4 55.507483 1.24 0.13 14.358131 14.358131 10655.201004
5 69.608750 1.25 0.13 15.403382 15.403382 10666.878991
2026-01-01 00:40:00 0 86.653297 1.20 0.14 10.328765 9.128607 5565.759329
1 149.183433 1.21 0.14 11.353278 11.310925 9990.818330
2 37.938019 1.22 0.14 12.383106 12.382259 10642.693238
3 97.704543 1.23 0.14 13.418207 13.276684 10645.954503
4 112.558768 1.24 0.14 14.458537 13.608316 10642.903494
5 8.825578 1.25 0.14 15.504057 15.504057 10662.680814
2026-01-01 00:50:00 0 115.433522 1.20 0.15 10.428080 10.428080 8318.943186
1 32.399584 1.21 0.15 11.452868 11.452868 10124.358519
2 12.359803 1.22 0.15 12.482970 12.482970 10643.639918
3 180.288252 1.23 0.15 13.518342 13.518342 10643.731250
4 183.470086 1.24 0.15 14.558944 12.260430 10641.548041
5 153.595496 1.25 0.15 15.604733 11.528096 10195.132902
2026-01-01 01:00:00 0 57.876616 1.20 0.16 10.527395 9.212689 5731.796859
1 18.557702 1.21 0.16 11.552458 11.552458 10218.052941
2 130.004275 1.22 0.16 12.582834 11.523702 10190.998406
3 83.628974 1.23 0.16 13.618478 13.590286 10643.069366
4 23.187265 1.24 0.16 14.659350 14.659350 10668.575151
5 94.083613 1.25 0.16 15.705409 15.705409 10654.284461
2026-01-01 01:10:00 0 6.533819 1.20 0.17 10.626710 10.562499 8643.135777
1 172.770876 1.21 0.17 11.652049 11.094385 9787.097539
2 49.168197 1.22 0.17 12.682698 11.987713 10627.540147
3 125.879234 1.23 0.17 13.718614 13.718614 10641.888750
4 59.225104 1.24 0.17 14.759757 14.759757 10673.033200
5 98.812924 1.25 0.17 15.806084 15.806084 10650.086285
2026-01-01 01:20:00 0 103.874953 1.20 0.18 10.726025 10.726025 9037.527277
1 35.122347 1.21 0.18 11.751639 11.545029 10211.063384
2 184.221079 1.22 0.18 12.782561 12.284747 10641.776626
3 147.275236 1.23 0.18 13.818750 13.818750 10640.967500
4 178.504799 1.24 0.18 14.860163 14.859563 10677.464611
5 170.017197 1.25 0.18 15.906760 14.155569 10646.207264
2026-01-01 01:30:00 0 113.600996 1.20 0.19 10.825340 10.824652 9275.395419
1 175.156105 1.21 0.19 11.851229 11.520783 10188.252221
2 16.813575 1.22 0.19 12.882425 12.880279 10647.374620
3 37.236744 1.23 0.19 13.918886 12.982061 10648.331370
4 8.593185 1.24 0.19 14.960570 14.960570 10681.949298
5 61.812763 1.25 0.19 16.007436 16.007436 10641.985129

For completeness, the states results at off-turbine evaluation points will be interpolated by point cloud methods.