Example 5: Getting Turbine and Farm Power

Example 5: Getting Turbine and Farm Power#

"""Example 5: Getting Turbine and Farm Power

After setting the FlorisModel and running, the next step is typically to get the power output
of the turbines.  FLORIS has several methods for getting power:

1. `get_turbine_powers()`: Returns the power output of each turbine in the farm for each findex
    (n_findex, n_turbines)
2. `get_farm_power()`: Returns the total power output of the farm for each findex (n_findex)
3. `get_expected_farm_power()`: Returns the combination of the farm power over each findex
    with the frequency of each findex to get the expected farm power
4. `get_farm_AEP()`: Multiplies the expected farm power by the number of hours in a year to get
    the expected annual energy production (AEP) of the farm


"""

import matplotlib.pyplot as plt
import numpy as np

from floris import (
    FlorisModel,
    TimeSeries,
    WindRose,
)


fmodel = FlorisModel("inputs/gch.yaml")

# Set to a 3-turbine layout
fmodel.set(layout_x=[0, 126 * 5, 126 * 10], layout_y=[0, 0, 0])

######################################################
# Using TimeSeries
######################################################

# Set up a time series in which the wind speed and TI are constant but the wind direction
# sweeps the range from 250 to 290 degrees
wind_directions = np.arange(250, 290, 1.0)
time_series = TimeSeries(
    wind_directions=wind_directions, wind_speeds=9.9, turbulence_intensities=0.06
)
fmodel.set(wind_data=time_series)

# Run the model
fmodel.run()

# Get the turbine powers
turbine_powers = fmodel.get_turbine_powers()

# Turbines powers will have shape (n_findex, n_turbines) where n_findex is the number of unique
# wind conditions and n_turbines is the number of turbines in the farm
print(f"Turbine power has shape {turbine_powers.shape}")

# It is also possible to get the farm power directly
farm_power = fmodel.get_farm_power()

# Farm power has length n_findex, and is the sum of the turbine powers
print(f"Farm power has shape {farm_power.shape}")

# It's possible to get these powers with wake losses disabled, this can be useful
# for computing total wake losses
fmodel.run_no_wake()
farm_power_no_wake = fmodel.get_farm_power()

# Plot the results
fig, axarr = plt.subplots(1, 3, figsize=(15, 5))

# Plot the turbine powers
ax = axarr[0]
for i in range(turbine_powers.shape[1]):
    ax.plot(wind_directions, turbine_powers[:, i] / 1e3, label=f"Turbine {i+1}  ")
ax.set_xlabel("Wind Direction (deg)")
ax.set_ylabel("Power (kW)")
ax.grid(True)
ax.legend()
ax.set_title("Turbine Powers")

# Plot the farm power
ax = axarr[1]
ax.plot(wind_directions, farm_power / 1e3, label="Farm Power With Wakes", color="k")
ax.plot(wind_directions, farm_power_no_wake / 1e3, label="Farm Power No Wakes", color="r")
ax.set_xlabel("Wind Direction (deg)")
ax.set_ylabel("Power (kW)")
ax.grid(True)
ax.legend()
ax.set_title("Farm Power")

# Plot the percent wake losses
ax = axarr[2]
percent_wake_losses = 100 * (farm_power_no_wake - farm_power) / farm_power_no_wake
ax.plot(wind_directions, percent_wake_losses, label="Percent Wake Losses", color="k")
ax.set_xlabel("Wind Direction (deg)")
ax.set_ylabel("Percent Wake Losses")
ax.grid(True)
ax.legend()
ax.set_title("Percent Wake Losses")


######################################################
# Using WindRose
######################################################

# When running FLORIS using a wind rose, that is when a WindRose or WindTIRose object is
# passed into the set function.  The functions get_expected_farm_power and get_farm_AEP
# will operate the same as above, however the functions get_turbine_powers and get_farm_power
# will be reshaped from (n_findex, n_turbines) and
# (n_findex) to (n_wind_dir, n_wind_speed, n_turbines)
# and (n_wind_dir, n_wind_speed) respectively.  This is make the powers align more easily with the
# provided wind rose.

# Declare a WindRose object of 2 wind directions and 3 wind speeds and constant turbulence intensity
wind_rose = WindRose(
    wind_directions=np.array([270.0, 280.0]), wind_speeds=np.array([8.0, 9.0, 10.0]), ti_table=0.06
)

fmodel.set(wind_data=wind_rose)

print("==========Wind Rose==========")
print(f"Number of conditions to simulate (2 x 3): {fmodel.n_findex}")

fmodel.run()

turbine_powers = fmodel.get_turbine_powers()

print(f"Shape of turbine powers: {turbine_powers.shape}")

farm_power = fmodel.get_farm_power()

print(f"Shape of farm power: {farm_power.shape}")


# Plot the farm power
fig, ax = plt.subplots()

for w_idx, wd in enumerate(wind_rose.wind_directions):
    ax.plot(wind_rose.wind_speeds, farm_power[w_idx, :] / 1e3, label=f"WD: {wd}")

ax.set_xlabel("Wind Speed (m/s)")
ax.set_ylabel("Power (kW)")
ax.grid(True)
ax.legend()
ax.set_title("Farm Power (from Wind Rose)")

plt.show()
import warnings
warnings.filterwarnings('ignore')
Turbine power has shape (40, 3)
Farm power has shape (40,)
==========Wind Rose==========
Number of conditions to simulate (2 x 3): 6
Shape of turbine powers: (2, 3, 3)
Shape of farm power: (2, 3)
../_images/4a8f3287b0cd783dfbc008026ffa507cd6dc94739d110fcf7f41e1c44253a845.png ../_images/34e993bff6ca1d6200d1b55764fe78d0b22e803a8cbd404afa768060cc7b48fb.png