Dynamic wakes 2

Sequential wake propagation

For some applications it may be useful to run foxes in state-by-state mode, i.e., without the benefits of state-wise chunking. For example, when coupling it to another simulation tool that runs based on an overall outer loop over the individual states.

For such cases the Sequential algorithm has been added, which basically is an iterator over the states. Obviously this algorithm is much slower than the Downwind algorithm. On the plus side, for timeseries ambient states, it has the advantage that it can be combined with local propagation of wake parcels between two subsequent time stamps. This functionality is provided by the wake frame class SeqDynamicWakes and does not require spatial homogeneity.

In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "jshtml"

import foxes
import foxes.variables as FV
import foxes.constants as FC

We create a case with a regular 3 x 3 wind farm layout:

In [2]:
states = foxes.input.states.Timeseries(
    data_source="timeseries_3000.csv.gz",
    output_vars=[FV.WS, FV.WD, FV.TI, FV.RHO],
    var2col={FV.WS: "WS", FV.WD: "WD", FV.TI: "TI", FV.RHO: "RHO"},
    states_sel=range(230, 280),
)

farm = foxes.WindFarm()
foxes.input.farm_layout.add_grid(
    farm,
    xy_base=np.array([0.0, 0.0]),
    step_vectors=np.array([[1000.0, 0], [0, 800.0]]),
    steps=(3, 3),
    turbine_models=["DTU10MW"],
    verbosity=0
)

algo = foxes.algorithms.Sequential(
    farm,
    states,
    rotor_model="centre",
    wake_models=["Bastankhah025_linear_lim_k004"],
    wake_frame="seq_dyn_wakes_1min",
    chunks={FC.STATE: None, FC.POINT: 5000},
    verbosity=1
)

Notice that for the sake of drama, we artificially reset the time step to 1min in the wake frame choice, more realistic would have been the choice seq_dyn_wakes which is based on the true time delta of the time series.

Our goal in this example is the creation of an animation that shows the dynamics of the flow in a horizontal plane at hub height. With the Sequential algorithm we can achieve this by treating the algo object as a Python iterator, for example within a for-loop.

Before doing so, we add a plugin that is evaluated whenever the iterator moves to the next state. In this case the plugin creates an image that is later on used for the animation:

In [3]:
with foxes.utils.runners.DaskRunner() as runner:

    # Add a plugin to the algorithm that updates
    # an image for an animation with every time step:
    fig, ax = plt.subplots()
    anigen = foxes.output.SeqFlowAnimationPlugin(
        runner=runner,
        orientation="xy",
        var=FV.WS,
        resolution=20,
        levels=None,
        quiver_pars=dict(scale=0.008, alpha=0.5),
        quiver_n=111,
        xmin=-5000,
        ymin=-5000,
        xmax=7000,
        ymax=7000,
        fig=fig,
        ax=ax,
        vmin=0,
        vmax=10,
        ret_im=True,
        title=lambda si, s: f"t = {si:02d} min",
        animated=True,
    )
    algo.plugins.append(anigen)

    # Now run all states sequentially:
    for r in algo:
        print(algo.index)

    print("\nFarm results:\n")
    print(algo.farm_results)

    # Create the animation:

    anim = foxes.output.Animator(fig)
    anim.add_generator(anigen.gen_images())
    ani = anim.animate(interval=600)

    lo = foxes.output.FarmLayoutOutput(farm)
    lo.get_figure(
        fig=fig,
        ax=ax,
        title="",
        annotate=1,
        anno_delx=-120,
        anno_dely=-60,
        alpha=0,
        s=10,
    )

    plt.close()
    print("done.")

print("Creating animation")
ani

Initializing algorithm 'Sequential'
Initializing model 'Sequential'
Initializing model 'Timeseries'
States 'Timeseries': Reading static data 'timeseries_3000.csv.gz' from context 'states'
Path: /home/jonas/gits/wakes/foxes/foxes/data/states/timeseries_3000.csv.gz
Initializing model 'SeqState'
Initializing model 'centre'
Initializing model 'basic_ctrl_prer'
Initializing model 'DTU10MW'
Turbine type 'DTU10MW': Reading static data from context 'power_ct_curve'
Path: /home/jonas/gits/wakes/foxes/foxes/data/power_ct_curves/DTU-10MW-D178d3-H119.csv
Initializing model 'basic_ctrl_postr'
Initializing model 'basic_ctrl'
Initializing model 'seq_dyn_wakes_1min'
Initializing model 'WakeK'
Initializing model 'Madsen'
Initializing model 'Bastankhah025_linear_lim_k004'
Initializing model 'axiwake6'

--------------------------------------------------
  Running Sequential: calc_farm
--------------------------------------------------
  n_states : 50
  n_turbines: 9
--------------------------------------------------
  states   : SeqState()
  rotor    : CentreRotor()
  controller: BasicFarmController()
  wake frame: SeqDynamicWakes(dt_min=1.0)
--------------------------------------------------
  wakes:
    0) Bastankhah025_linear_lim_k004: Bastankhah2014(ws_linear_lim, induction=Madsen, k=0.04)
--------------------------------------------------
  partial wakes:
    0) Bastankhah025_linear_lim_k004: axiwake6, PartialAxiwake(n=6)
--------------------------------------------------
  turbine models:
    0) DTU10MW: PCtFile(D=178.3, H=119.0, P_nominal=10000.0, P_unit=kW, rho=1.225, var_ws_ct=REWS2, var_ws_P=REWS3)
--------------------------------------------------

Initializing model 'InitFarmData'
Initializing model 'SetAmbFarmResults'
Initializing model 'FarmWakesCalculation'
Initializing model 'ReorderFarmOutput'
Initializing model 'Sequential_calc'

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

  weight: ('state', 'turbine') float64, shape (50, 9)
  Timeseries_data: ('state', 'Timeseries_vars') float64, shape (50, 4)
  tmodel_sels: ('state', 'turbine', 'tmodels') bool, shape (50, 9, 1)

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

2018-10-10T05:00:00.000000000
2018-10-10T06:00:00.000000000
2018-10-10T07:00:00.000000000
2018-10-10T08:00:00.000000000
2018-10-10T09:00:00.000000000
2018-10-10T10:00:00.000000000
2018-10-10T11:00:00.000000000
2018-10-10T12:00:00.000000000
2018-10-10T13:00:00.000000000
2018-10-10T14:00:00.000000000
2018-10-10T15:00:00.000000000
2018-10-10T16:00:00.000000000
2018-10-10T17:00:00.000000000
2018-10-10T18:00:00.000000000
2018-10-10T19:00:00.000000000
2018-10-10T20:00:00.000000000
2018-10-10T21:00:00.000000000
2018-10-10T22:00:00.000000000
2018-10-10T23:00:00.000000000
2018-10-11T00:00:00.000000000
2018-10-11T01:00:00.000000000
2018-10-11T02:00:00.000000000
2018-10-11T03:00:00.000000000
2018-10-11T04:00:00.000000000
2018-10-11T05:00:00.000000000
2018-10-11T06:00:00.000000000
2018-10-11T07:00:00.000000000
2018-10-11T08:00:00.000000000
2018-10-11T09:00:00.000000000
2018-10-11T10:00:00.000000000
2018-10-11T11:00:00.000000000
2018-10-11T12:00:00.000000000
2018-10-11T13:00:00.000000000
2018-10-11T14:00:00.000000000
2018-10-11T15:00:00.000000000
2018-10-11T16:00:00.000000000
2018-10-11T17:00:00.000000000
2018-10-11T18:00:00.000000000
2018-10-11T19:00:00.000000000
2018-10-11T20:00:00.000000000
2018-10-11T21:00:00.000000000
2018-10-11T22:00:00.000000000
2018-10-11T23:00:00.000000000
2018-10-12T00:00:00.000000000
2018-10-12T01:00:00.000000000
2018-10-12T02:00:00.000000000
2018-10-12T03:00:00.000000000
2018-10-12T04:00:00.000000000
2018-10-12T05:00:00.000000000
2018-10-12T06:00:00.000000000

Farm results:

<xarray.Dataset> Size: 105kB
Dimensions:     (state: 50, turbine: 9, xyh: 3)
Coordinates:
  * state       (state) datetime64[ns] 400B 2018-10-10T05:00:00 ... 2018-10-1...
  * turbine     (turbine) int64 72B 0 1 2 3 4 5 6 7 8
Dimensions without coordinates: xyh
Data variables: (12/28)
    AMB_CT      (state, turbine) float64 4kB 0.0 0.0 0.0 ... 0.814 0.814 0.814
    AMB_P       (state, turbine) float64 4kB 0.0 0.0 0.0 ... 6.451e+03 6.451e+03
    AMB_REWS    (state, turbine) float64 4kB 3.51 3.51 3.51 ... 9.59 9.59 9.59
    AMB_REWS2   (state, turbine) float64 4kB 3.51 3.51 3.51 ... 9.59 9.59 9.59
    AMB_REWS3   (state, turbine) float64 4kB 3.468 3.468 3.468 ... 9.577 9.577
    AMB_RHO     (state, turbine) float64 4kB 1.27 1.27 1.27 ... 1.23 1.23 1.23
    ...          ...
    order       (state, turbine) int64 4kB 8 7 6 5 4 3 2 1 0 ... 5 7 2 4 6 1 3 0
    order_inv   (state, turbine) float64 4kB 8.0 7.0 6.0 5.0 ... 1.0 5.0 2.0 0.0
    order_ssel  (state, turbine) float64 4kB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
    weight      (state, turbine) float64 4kB 0.02 0.02 0.02 ... 0.02 0.02 0.02
    txyh        (state, turbine, xyh) float64 11kB 0.0 0.0 ... 1.6e+03 119.0
    tname       (turbine) <U2 72B 'T0' 'T1' 'T2' 'T3' 'T4' 'T5' 'T6' 'T7' 'T8'
Creating animation data
done.
Creating animation
Out[3]: