Timeseries data

In this example we calculate the data of a wind farm with 67 turbines in a time series containing 8000 uniform inflow states.

The required imports are:

%matplotlib inline
import matplotlib.pyplot as plt

import foxes
import foxes.variables as FV
/home/runner/work/foxes/foxes/foxes/core/engine.py:4: 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

First, we create the states. The data_source can be any csv-type file (or pandas readable equivalent), or a pandas.DataFrame object. If it is a file path, then it will first be searched in the file system, and if not found, in the static data. If it is also not found there, an error showing the available static data file names is displayed.

In this example the static data file timeseries_8000.csv.gz will be used, with content

Time,ws,wd,ti
2017-01-01 00:00:00,15.62,244.06,0.0504
2017-01-01 00:30:00,15.99,243.03,0.0514
2017-01-01 01:00:00,16.31,243.01,0.0522
2017-01-01 01:30:00,16.33,241.26,0.0523
...

Notice the column names, and how they appear in the Timeseries constructor:

states = foxes.input.states.Timeseries(
    data_source="timeseries_8000.csv.gz",
    output_vars=[FV.WS, FV.WD, FV.TI, FV.RHO],
    var2col={FV.WS: "ws", FV.WD: "wd", FV.TI: "ti"},
    fixed_vars={FV.RHO: 1.225},
)

We can visualize the wind distribution via the StatesRosePlotOutput. Here we display the ambient wind speed in a wind rose with 16 wind direction sectors and 5 wind speed bins:

o = foxes.output.StatesRosePlotOutput(states, point=[0.0, 0.0, 100.0])
o.get_figure(16, FV.AMB_WS, [0, 3.5, 6, 10, 15, 20], figsize=(6, 6))
plt.show()
DefaultEngine: Selecting engine 'single'
SingleChunkEngine: Calculating 8000 states for 1 turbines
SingleChunkEngine: Starting calculation using a single worker.
SingleChunkEngine: Completed all 1 chunks
../_images/e94e0c0b3047eab27b10f1277e6a2cef54a9532247ec2c33a4a5d4939280f8e3.png

For the time series with uniform data, any choice of the point argument will produce the same figure.

Next, we create the example wind farm with 67 turbines from static data. The file test_farm_67.csv has the following structure:

index,label,x,y
0,T0,101872.70,1004753.57
1,T1,103659.97,1002993.29
2,T2,100780.09,1000779.97
3,T3,100290.42,1004330.88
...

For more options, check the API section foxes.input.farm_layout.

We consider two turbine models in this example: the wind turbine type NREL5MW and the turbine model kTI_02, both from the default model book. The latter model adds the variable k for each state and turbine, calculated as k = kTI * TI, with constant kTI = 0.2. The parameter k will later be used by the wake model.

farm = foxes.WindFarm()
foxes.input.farm_layout.add_from_file(
    farm, "test_farm_67.csv", turbine_models=["NREL5MW"], verbosity=0
)

Next, we create the algorithm, with further model selections. In particular, two wake models are invoked, the model Bastankhah_quadratic for wind speed deficits and the model CrespoHernandez_max for turbulence intensity:

algo = foxes.algorithms.Downwind(
    farm,
    states,
    rotor_model="centre",
    wake_models=["Bastankhah2014_quadratic_ka02", "CrespoHernandez_max_ka04"],
    verbosity=0,
)

Also notice the chunks parameter, specifying that always 1000 states should be considered in vectorized form during calculations. The progress is automatically visualized when invoking the DaskRunner:

farm_results = algo.calc_farm()

fr = farm_results.to_dataframe()
print("\n", fr[[FV.WD, FV.AMB_REWS, FV.REWS, FV.AMB_P, FV.P]])
DefaultEngine: Selecting engine 'process'
ProcessEngine: Calculating 8000 states for 67 turbines
ProcessEngine: Starting calculation using 3 workers, for 3 states chunks.
ProcessEngine: Completed all 3 chunks
                                  WD  AMB_REWS       REWS    AMB_P            P
state               turbine                                                   
2017-01-01 00:00:00 0        244.06     15.62  15.610500  5000.00  5000.000000
                    1        244.06     15.62  14.012903  5000.00  5000.000000
                    2        244.06     15.62  15.021033  5000.00  5000.000000
                    3        244.06     15.62  15.560020  5000.00  5000.000000
                    4        244.06     15.62  14.564008  5000.00  5000.000000
...                             ...       ...        ...      ...          ...
2017-06-16 15:30:00 62       299.19     11.70   8.145984  4868.75  1880.222715
                    63       299.19     11.70  11.490711  4868.75  4777.186188
                    64       299.19     11.70  11.700000  4868.75  4868.750000
                    65       299.19     11.70  11.642754  4868.75  4843.705093
                    66       299.19     11.70   8.055085  4868.75  1812.276034

[536000 rows x 5 columns]

Let’s evaluate the results:

# add capacity factor and efficiency to farm_results:
o = foxes.output.FarmResultsEval(farm_results, algo=algo)
o.add_capacity_factor()
o.add_capacity_factor(ambient=True)
o.add_efficiency()

# print results by turbine:
turbine_results = o.reduce_states()
turbine_results[FV.AMB_YLD] = o.calc_yield(annual=True, ambient=True)
turbine_results[FV.YLD] = o.calc_yield(annual=True)
turbine_results[FV.EFF] = turbine_results[FV.P] / turbine_results[FV.AMB_P]
print("\nResults by turbine:\n")
print(turbine_results)

# print power results:
P0 = o.calc_mean_farm_power(ambient=True)
P = o.calc_mean_farm_power()
print(f"\nFarm power        : {P / 1000:.1f} MW")
print(f"Farm ambient power: {P0 / 1000:.1f} MW")
print(f"Farm efficiency   : {o.calc_farm_efficiency():.2f}")
print(f"Annual farm yield : {turbine_results[FV.YLD].sum():.2f} GWh")
Capacity factor added to farm results
Ambient capacity factor added to farm results
Efficiency added to farm results

Results by turbine:

           AMB_CT         AMB_P   AMB_REWS  AMB_REWS2  AMB_REWS3  AMB_RHO  \
turbine                                                                     
0        0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
1        0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
2        0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
3        0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
4        0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
...           ...           ...        ...        ...        ...      ...   
62       0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
63       0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
64       0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
65       0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   
66       0.593832  2.454179e+07  10.142951  10.142951  10.142951    1.225   

           AMB_TI      AMB_WD     AMB_YAW        CT  ...         YAW  \
turbine                                              ...               
0        0.056837  214.291794  214.291794  0.629342  ...  214.291794   
1        0.056837  214.291794  214.291794  0.648618  ...  214.291794   
2        0.056837  214.291794  214.291794  0.622579  ...  214.291794   
3        0.056837  214.291794  214.291794  0.622090  ...  214.291794   
4        0.056837  214.291794  214.291794  0.640959  ...  214.291794   
...           ...         ...         ...       ...  ...         ...   
62       0.056837  214.291794  214.291794  0.634036  ...  214.291794   
63       0.056837  214.291794  214.291794  0.637352  ...  214.291794   
64       0.056837  214.291794  214.291794  0.614525  ...  214.291794   
65       0.056837  214.291794  214.291794  0.641752  ...  214.291794   
66       0.056837  214.291794  214.291794  0.642317  ...  214.291794   

             order  order_inv   order_ssel         CAPF     AMB_CAPF  \
turbine                                                                
0        30.747125  31.543750  1332.833375  4222.251300  4908.357436   
1        29.423750  37.537250  1332.833375  3679.225291  4908.357436   
2        33.122125  32.728875  1332.833375  4103.081737  4908.357436   
3        34.077750  33.087375  1332.833375  4175.812673  4908.357436   
4        31.093875  29.326000  1332.833375  3828.742434  4908.357436   
...            ...        ...          ...          ...          ...   
62       31.599000  37.140000  1332.833375  3932.475484  4908.357436   
63       35.948000  30.083750  1332.833375  3896.693678  4908.357436   
64       39.153125  33.625125  1332.833375  4410.534587  4908.357436   
65       27.239750  31.799375  1332.833375  3812.884197  4908.357436   
66       28.507375  29.193875  1332.833375  3853.811458  4908.357436   

              EFF  tname    AMB_YLD        YLD  
turbine                                         
0        0.860217     T0  26.873257  23.116826  
1        0.749584     T1  26.873257  20.143758  
2        0.835938     T2  26.873257  22.464373  
3        0.850756     T3  26.873257  22.862574  
4        0.780046     T4  26.873257  20.962365  
...           ...    ...        ...        ...  
62       0.801180    T62  26.873257  21.530303  
63       0.793890    T63  26.873257  21.334398  
64       0.898576    T64  26.873257  24.147677  
65       0.776815    T65  26.873257  20.875541  
66       0.785153    T66  26.873257  21.099618  

[67 rows x 31 columns]

Farm power        : 166.3 MW
Farm ambient power: 205.5 MW
Farm efficiency   : 0.81
Annual farm yield : 1456.42 GWh

We can visualize the mean rotor equivalent wind speed as seen by each turbine and also the mean efficiency with respect to the time series data as colored layout plots:

fig, axs = plt.subplots(1, 2, figsize=(14, 5))
o = foxes.output.FarmLayoutOutput(farm, farm_results)
o.get_figure(
    fig=fig, ax=axs[0], color_by="mean_REWS", title="Mean REWS [m/s]", s=150, annotate=0
)
o.get_figure(
    fig=fig,
    ax=axs[1],
    color_by="mean_EFF",
    title="Mean efficiency [%]",
    s=150,
    annotate=0,
)
plt.show()
../_images/6dcdc028a2e383c852f22bf2220983cb3d2cfe7f4e0e63dc9dfdcc8ec9cc8e75.png