"""
The ``turbine_cluster_modelchain`` module contains functions and classes of the
windpowerlib. This module makes it easy to get started with the windpowerlib
and shows use cases for the power output calculation of wind farms and wind
turbine clusters.
SPDX-FileCopyrightText: 2019 oemof developer group <contact@oemof.org>
SPDX-License-Identifier: MIT
"""
import logging
from windpowerlib import wake_losses
from windpowerlib.modelchain import ModelChain, data
[docs]
class TurbineClusterModelChain(ModelChain):
r"""
Model to determine the output of a wind farm or wind turbine cluster.
Parameters
----------
power_plant : :class:`~.wind_farm.WindFarm` or :class:`~.wind_turbine_cluster.WindTurbineCluster`
A :class:`~.wind_farm.WindFarm` object representing the wind farm or
a :class:`~.wind_turbine_cluster.WindTurbineCluster` object
representing the wind turbine cluster.
wake_losses_model : str or None
Defines the method for taking wake losses within the farm into
consideration.
* None -
Wake losses are not taken into account.
* 'wind_farm_efficiency' -
The values of the wind farm power curve(s) are reduced by the wind
farm efficiency, which needs to be set in the
:py:class:`~.wind_farm.WindFarm` class. Note: The wind farm
efficiency has no effect if `wake_losses_model` is not set to
'wind_farm_efficiency'.
See :func:`~.power_curves.wake_losses_to_power_curve` for more
information.
* 'dena_mean' or name of other wind efficiency curve -
The values of the wind speed time series are reduced by the chosen
wind efficiency curve in :func:`~.run_model` before the power output
calculations.
See :func:`~.wake_losses.reduce_wind_speed` for more information.
Use :func:`~.wake_losses.get_wind_efficiency_curve` to get a
DataFrame of all provided wind efficiency curves and see the provided
example on how to plot the wind efficiency curves.
Default: 'dena_mean'.
smoothing : bool
If True the power curves will be smoothed to account for the
distribution of wind speeds over space. Depending on the parameter
`smoothing_order` the power curves are smoothed before or after
aggregating wind turbine power curves to one representative power
curve of the wind farm or cluster.
See :func:`~.power_curves.smooth_power_curve` for more information.
Default: False.
block_width : float
Width between the wind speeds in the sum of the equation in
:py:func:`~.power_curves.smooth_power_curve`. This parameter is only
used if `smoothing` is True. To achieve a smooth curve without steps a
value not much higher than the step width between the power curve wind
speeds should be chosen.
Default: 0.5.
standard_deviation_method : str
Method for calculating the standard deviation for the Gauss
distribution if `smoothing` is True.
* 'turbulence_intensity' -
See :func:`~.power_curves.smooth_power_curve` for more information.
* 'Staffell_Pfenninger' -
See :func:`~.power_curves.smooth_power_curve` for more information.
Default: 'turbulence_intensity'.
smoothing_order : str
Defines when the smoothing takes place if `smoothing` is True.
* 'turbine_power_curves' -
Smoothing is applied to wind turbine power curves.
* 'wind_farm_power_curves' -
Smoothing is applied to wind farm power curves.
Default: 'wind_farm_power_curves'.
Other Parameters
----------------
wind_speed_model :
See :py:class:`~.modelchain.ModelChain` for more information.
temperature_model :
See :py:class:`~.modelchain.ModelChain` for more information.
density_model :
See :py:class:`~.modelchain.ModelChain` for more information.
power_output_model :
See :py:class:`~.modelchain.ModelChain` for more information.
density_correction :
See :py:class:`~.modelchain.ModelChain` for more information.
obstacle_height :
See :py:class:`~.modelchain.ModelChain` for more information.
hellman_exp :
See :py:class:`~.modelchain.ModelChain` for more information.
Attributes
----------
power_plant : :class:`~.wind_farm.WindFarm` or :class:`~.wind_turbine_cluster.WindTurbineCluster`
A :class:`~.wind_farm.WindFarm` object representing the wind farm or
a :class:`~.wind_turbine_cluster.WindTurbineCluster` object
representing the wind turbine cluster.
wake_losses_model : str or None
Defines the method for taking wake losses within the farm into
consideration.
smoothing : bool
If True the power curves are smoothed.
block_width : float
Width between the wind speeds in the sum of the equation in
:py:func:`~.power_curves.smooth_power_curve`.
standard_deviation_method : str
Method for calculating the standard deviation for the Gauss
distribution.
smoothing_order : str
Defines when the smoothing takes place if `smoothing` is True.
power_output : :pandas:`pandas.Series<series>`
Electrical power output of the wind turbine in W.
power_curve : :pandas:`pandas.Dataframe<frame>` or None
The calculated power curve of the wind farm.
wind_speed_model : str
Defines which model is used to calculate the wind speed at hub height.
temperature_model : str
Defines which model is used to calculate the temperature of air at hub
height.
density_model : str
Defines which model is used to calculate the density of air at hub
height.
power_output_model : str
Defines which model is used to calculate the turbine power output.
density_correction : bool
Used to set `density_correction` parameter in
:func:`~.power_output.power_curve`.
obstacle_height : float
Used to set `obstacle_height` in :func:`~.wind_speed.logarithmic`.
hellman_exp : float
Used to set `hellman_exponent` in :func:`~.wind_speed.hellman`.
"""
[docs]
def __init__(
self,
power_plant,
wake_losses_model="dena_mean",
smoothing=False,
block_width=0.5,
standard_deviation_method="turbulence_intensity",
smoothing_order="wind_farm_power_curves",
**kwargs,
):
super(TurbineClusterModelChain, self).__init__(power_plant, **kwargs)
self.power_plant = power_plant
self.wake_losses_model = wake_losses_model
self.smoothing = smoothing
self.block_width = block_width
self.standard_deviation_method = standard_deviation_method
self.smoothing_order = smoothing_order
self.power_curve = None
self.power_output = None
[docs]
def assign_power_curve(self, weather_df):
r"""
Calculates the power curve of the wind turbine cluster.
The power curve is aggregated from the wind farms' and wind turbines'
power curves by using :func:`power_plant.assign_power_curve`. Depending
on the parameters of the WindTurbineCluster power curves are smoothed
and/or wake losses are taken into account.
Parameters
----------
weather_df : :pandas:`pandas.DataFrame<frame>`
DataFrame with weather data time series. If power curve smoothing
:py:attr:`~smoothing` is True and chosen method for calculating the
standard deviation :py:attr:`~standard_deviation_method` is
`turbulence_intensity` the weather dataframe needs to either
contain the turbulence intensity in column 'turbulence_intensity'
or the roughness length in m in column 'roughness_length'. The
turbulence intensity should be provided at hub height or at least
at a height close to the hub height, as it cannot be inter- or
extrapolated.
Returns
-------
self
"""
# Get turbulence intensity from weather if existent
turbulence_intensity = (
weather_df["turbulence_intensity"].values.mean()
if "turbulence_intensity" in weather_df.columns.get_level_values(0)
else None
)
roughness_length = (
weather_df["roughness_length"].values.mean()
if "roughness_length" in weather_df.columns.get_level_values(0)
else None
)
# Assign power curve
if (
self.wake_losses_model == "wind_farm_efficiency"
or self.wake_losses_model is None
):
wake_losses_model_to_power_curve = self.wake_losses_model
if self.wake_losses_model is None:
logging.debug("Wake losses in wind farms are not considered.")
else:
logging.debug(
"Wake losses considered with {}.".format(
self.wake_losses_model
)
)
else:
logging.debug(
"Wake losses considered by {} wind ".format(
self.wake_losses_model
)
+ "efficiency curve."
)
wake_losses_model_to_power_curve = None
self.power_plant.assign_power_curve(
wake_losses_model=wake_losses_model_to_power_curve,
smoothing=self.smoothing,
block_width=self.block_width,
standard_deviation_method=self.standard_deviation_method,
smoothing_order=self.smoothing_order,
roughness_length=roughness_length,
turbulence_intensity=turbulence_intensity,
)
# Further logging messages
if self.smoothing is False:
logging.debug("Aggregated power curve not smoothed.")
else:
logging.debug(
"Aggregated power curve smoothed by method: "
+ self.standard_deviation_method
)
return self
[docs]
def run_model(self, weather_df):
r"""
Runs the model.
Parameters
----------
weather_df : :pandas:`pandas.DataFrame<frame>`
DataFrame with time series for wind speed `wind_speed` in m/s, and
roughness length `roughness_length` in m, as well as optionally
temperature `temperature` in K, pressure `pressure` in Pa,
density `density` in kg/m³ and turbulence intensity
`turbulence_intensity` depending on `power_output_model`,
`density_model` and `standard_deviation_model` chosen.
The columns of the DataFrame are a MultiIndex where the first level
contains the variable name (e.g. wind_speed) and the second level
contains the height at which it applies (e.g. 10, if it was
measured at a height of 10 m). See below for an example on how to
create the weather_df DataFrame.
Returns
-------
self
Examples
---------
>>> import numpy as np
>>> import pandas as pd
>>> my_weather_df = pd.DataFrame(np.random.rand(2,6),
... index=pd.date_range('1/1/2012',
... periods=2,
... freq='H'),
... columns=[np.array(['wind_speed',
... 'wind_speed',
... 'temperature',
... 'temperature',
... 'pressure',
... 'roughness_length']),
... np.array([10, 80, 10, 80,
... 10, 0])])
>>> my_weather_df.columns.get_level_values(0)[0]
'wind_speed'
"""
weather_df = data.check_weather_data(weather_df)
self.assign_power_curve(weather_df)
self.power_plant.mean_hub_height()
wind_speed_hub = self.wind_speed_hub(weather_df)
density_hub = (
None
if (
self.power_output_model == "power_curve"
and self.density_correction is False
)
else self.density_hub(weather_df)
)
if (
self.wake_losses_model != "wind_farm_efficiency"
and self.wake_losses_model is not None
):
# Reduce wind speed with wind efficiency curve
wind_speed_hub = wake_losses.reduce_wind_speed(
wind_speed_hub,
wind_efficiency_curve_name=self.wake_losses_model,
)
self.power_output = self.calculate_power_output(
wind_speed_hub, density_hub
)
return self