"""
The ``modelchain`` module contains functions and classes of the
windpowerlib. This module makes it easy to get started with the windpowerlib
and demonstrates standard ways to use the library.
"""
__copyright__ = "Copyright oemof developer group"
__license__ = "GPLv3"
import logging
from windpowerlib import (wind_speed, density, temperature, power_output,
tools)
[docs]class ModelChain(object):
r"""Model to determine the output of a wind turbine
Parameters
----------
power_plant : WindTurbine
A :class:`~.wind_turbine.WindTurbine` object representing the wind
turbine.
wind_speed_model : string
Parameter to define which model to use to calculate the wind speed at
hub height. Valid options are 'logarithmic', 'hellman' and
'interpolation_extrapolation', 'log_interpolation_extrapolation'.
Default: 'logarithmic'.
temperature_model : string
Parameter to define which model to use to calculate the temperature of
air at hub height. Valid options are 'linear_gradient' and
'interpolation_extrapolation'. Default: 'linear_gradient'.
density_model : string
Parameter to define which model to use to calculate the density of air
at hub height. Valid options are 'barometric', 'ideal_gas' and
'interpolation_extrapolation'. Default: 'barometric'.
power_output_model : string
Parameter to define which model to use to calculate the turbine power
output. Valid options are 'power_curve' and 'power_coefficient_curve'.
Default: 'power_curve'.
density_correction : boolean
If the parameter is True the density corrected power curve is used for
the calculation of the turbine power output. Default: False.
obstacle_height : float
Height of obstacles in the surrounding area of the wind turbine in m.
Set `obstacle_height` to zero for wide spread obstacles. Default: 0.
hellman_exp : float
The Hellman exponent, which combines the increase in wind speed due to
stability of atmospheric conditions and surface roughness into one
constant. Default: None.
Attributes
----------
power_plant : WindTurbine
A :class:`~.wind_turbine.WindTurbine` object representing the wind
turbine.
wind_speed_model : string
Parameter to define which model to use to calculate the wind speed at
hub height. Valid options are 'logarithmic', 'hellman' and
'interpolation_extrapolation', 'log_interpolation_extrapolation'.
Default: 'logarithmic'.
temperature_model : string
Parameter to define which model to use to calculate the temperature of
air at hub height. Valid options are 'linear_gradient' and
'interpolation_extrapolation'. Default: 'linear_gradient'.
density_model : string
Parameter to define which model to use to calculate the density of air
at hub height. Valid options are 'barometric', 'ideal_gas' and
'interpolation_extrapolation'. Default: 'barometric'.
power_output_model : string
Parameter to define which model to use to calculate the turbine power
output. Valid options are 'power_curve' and 'power_coefficient_curve'.
Default: 'power_curve'.
density_correction : boolean
If the parameter is True the density corrected power curve is used for
the calculation of the turbine power output. Default: False.
hellman_exp : float
The Hellman exponent, which combines the increase in wind speed due to
stability of atmospheric conditions and surface roughness into one
constant. Default: None.
obstacle_height : float
Height of obstacles in the surrounding area of the wind turbine in m.
Set `obstacle_height` to zero for wide spread obstacles. Default: 0.
power_output : pandas.Series
Electrical power output of the wind turbine in W.
Examples
--------
>>> from windpowerlib import modelchain
>>> from windpowerlib import wind_turbine
>>> enerconE126 = {
... 'hub_height': 135,
... 'rotor_diameter': 127,
... 'name': 'E-126/4200',
... 'fetch_curve': 'power_curve',
... 'data_source': 'oedb'}
>>> e126 = wind_turbine.WindTurbine(**enerconE126)
>>> modelchain_data = {'density_model': 'ideal_gas'}
>>> e126_mc = modelchain.ModelChain(e126, **modelchain_data)
>>> print(e126_mc.density_model)
ideal_gas
"""
[docs] def __init__(self, power_plant,
wind_speed_model='logarithmic',
temperature_model='linear_gradient',
density_model='barometric',
power_output_model='power_curve',
density_correction=False,
obstacle_height=0,
hellman_exp=None, **kwargs):
self.power_plant = power_plant
self.obstacle_height = obstacle_height
self.wind_speed_model = wind_speed_model
self.temperature_model = temperature_model
self.density_model = density_model
self.power_output_model = power_output_model
self.density_correction = density_correction
self.hellman_exp = hellman_exp
self.power_output = None
[docs] def temperature_hub(self, weather_df):
r"""
Calculates the temperature of air at hub height.
The temperature is calculated using the method specified by
the parameter `temperature_model`.
Parameters
----------
weather_df : pandas.DataFrame
DataFrame with time series for temperature `temperature` in K.
The columns of the DataFrame are a MultiIndex where the first level
contains the variable name (e.g. temperature) 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 documentation of
:func:`ModelChain.run_model` for an example on how to create the
weather_df DataFrame.
Returns
-------
temperature_hub : pandas.Series or numpy.array
Temperature of air in K at hub height.
Notes
-----
If `weather_df` contains temperatures at different heights the given
temperature(s) closest to the hub height are used.
"""
if self.power_plant.hub_height in weather_df['temperature']:
temperature_hub = weather_df['temperature'][
self.power_plant.hub_height]
elif self.temperature_model == 'linear_gradient':
logging.debug('Calculating temperature using temperature '
'gradient.')
closest_height = weather_df['temperature'].columns[
min(range(len(weather_df['temperature'].columns)),
key=lambda i: abs(weather_df['temperature'].columns[i] -
self.power_plant.hub_height))]
temperature_hub = temperature.linear_gradient(
weather_df['temperature'][closest_height], closest_height,
self.power_plant.hub_height)
elif self.temperature_model == 'interpolation_extrapolation':
logging.debug('Calculating temperature using linear inter- or '
'extrapolation.')
temperature_hub = tools.linear_interpolation_extrapolation(
weather_df['temperature'], self.power_plant.hub_height)
else:
raise ValueError("'{0}' is an invalid value. ".format(
self.temperature_model) + "`temperature_model` must be "
"'linear_gradient' or 'interpolation_extrapolation'.")
return temperature_hub
[docs] def density_hub(self, weather_df):
r"""
Calculates the density of air at hub height.
The density is calculated using the method specified by the parameter
`density_model`. Previous to the calculation of the density the
temperature at hub height is calculated using the method specified by
the parameter `temperature_model`.
Parameters
----------
weather_df : pandas.DataFrame
DataFrame with time series for temperature `temperature` in K,
pressure `pressure` in Pa and/or density `density` in kg/m³,
depending on the `density_model` used.
The columns of the DataFrame are a MultiIndex where the first level
contains the variable name (e.g. temperature) 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 documentation of
:func:`ModelChain.run_model` for an example on how to create the
weather_df DataFrame.
Returns
-------
density_hub : pandas.Series or numpy.array
Density of air in kg/m³ at hub height.
Notes
-----
If `weather_df` contains data at different heights the data closest to
the hub height are used.
If `interpolation_extrapolation` is used to calculate the density at
hub height, the `weather_df` must contain at least two time series for
density.
"""
if self.density_model != 'interpolation_extrapolation':
temperature_hub = self.temperature_hub(weather_df)
# Calculation of density in kg/m³ at hub height
if self.density_model == 'barometric':
logging.debug('Calculating density using barometric height '
'equation.')
closest_height = weather_df['pressure'].columns[
min(range(len(weather_df['pressure'].columns)),
key=lambda i: abs(weather_df['pressure'].columns[i] -
self.power_plant.hub_height))]
density_hub = density.barometric(
weather_df['pressure'][closest_height], closest_height,
self.power_plant.hub_height, temperature_hub)
elif self.density_model == 'ideal_gas':
logging.debug('Calculating density using ideal gas equation.')
closest_height = weather_df['pressure'].columns[
min(range(len(weather_df['pressure'].columns)),
key=lambda i: abs(weather_df['pressure'].columns[i] -
self.power_plant.hub_height))]
density_hub = density.ideal_gas(
weather_df['pressure'][closest_height], closest_height,
self.power_plant.hub_height, temperature_hub)
elif self.density_model == 'interpolation_extrapolation':
logging.debug('Calculating density using linear inter- or '
'extrapolation.')
density_hub = tools.linear_interpolation_extrapolation(
weather_df['density'], self.power_plant.hub_height)
else:
raise ValueError("'{0}' is an invalid value. ".format(
self.density_model) + "`density_model` " +
"must be 'barometric', 'ideal_gas' or " +
"'interpolation_extrapolation'.")
return density_hub
[docs] def wind_speed_hub(self, weather_df):
r"""
Calculates the wind speed at hub height.
The method specified by the parameter `wind_speed_model` is used.
Parameters
----------
weather_df : pandas.DataFrame
DataFrame with time series for wind speed `wind_speed` in m/s and
roughness length `roughness_length` in m.
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 documentation of
:func:`ModelChain.run_model` for an example on how to create the
weather_df DataFrame.
Returns
-------
wind_speed_hub : pandas.Series or numpy.array
Wind speed in m/s at hub height.
Notes
-----
If `weather_df` contains wind speeds at different heights the given
wind speed(s) closest to the hub height are used.
"""
if self.power_plant.hub_height in weather_df['wind_speed']:
wind_speed_hub = weather_df['wind_speed'][
self.power_plant.hub_height]
elif self.wind_speed_model == 'logarithmic':
logging.debug('Calculating wind speed using logarithmic wind '
'profile.')
closest_height = weather_df['wind_speed'].columns[
min(range(len(weather_df['wind_speed'].columns)),
key=lambda i: abs(weather_df['wind_speed'].columns[i] -
self.power_plant.hub_height))]
wind_speed_hub = wind_speed.logarithmic_profile(
weather_df['wind_speed'][closest_height], closest_height,
self.power_plant.hub_height,
weather_df['roughness_length'].iloc[:, 0],
self.obstacle_height)
elif self.wind_speed_model == 'hellman':
logging.debug('Calculating wind speed using hellman equation.')
closest_height = weather_df['wind_speed'].columns[
min(range(len(weather_df['wind_speed'].columns)),
key=lambda i: abs(weather_df['wind_speed'].columns[i] -
self.power_plant.hub_height))]
wind_speed_hub = wind_speed.hellman(
weather_df['wind_speed'][closest_height], closest_height,
self.power_plant.hub_height,
weather_df['roughness_length'].iloc[:, 0],
self.hellman_exp)
elif self.wind_speed_model == 'interpolation_extrapolation':
logging.debug('Calculating wind speed using linear inter- or '
'extrapolation.')
wind_speed_hub = tools.linear_interpolation_extrapolation(
weather_df['wind_speed'], self.power_plant.hub_height)
elif self.wind_speed_model == 'log_interpolation_extrapolation':
logging.debug('Calculating wind speed using logarithmic inter- or '
'extrapolation.')
wind_speed_hub = tools.logarithmic_interpolation_extrapolation(
weather_df['wind_speed'], self.power_plant.hub_height)
else:
raise ValueError("'{0}' is an invalid value. ".format(
self.wind_speed_model) + "`wind_speed_model` must be "
"'logarithmic', 'hellman', 'interpolation_extrapolation' " +
"or 'log_interpolation_extrapolation'.")
return wind_speed_hub
[docs] def calculate_power_output(self, wind_speed_hub, density_hub):
r"""
Calculates the power output of the wind power plant.
The method specified by the parameter `power_output_model` is used.
Parameters
----------
wind_speed_hub : pandas.Series or numpy.array
Wind speed at hub height in m/s.
density_hub : pandas.Series or numpy.array
Density of air at hub height in kg/m³.
Returns
-------
pandas.Series
Electrical power output of the wind turbine in W.
"""
if self.power_output_model == 'power_curve':
if self.power_plant.power_curve is None:
raise TypeError("Power curve values of " +
self.power_plant.name +
" are missing.")
logging.debug('Calculating power output using power curve.')
return (power_output.power_curve(
wind_speed_hub,
self.power_plant.power_curve['wind_speed'],
self.power_plant.power_curve['value'],
density_hub, self.density_correction))
elif self.power_output_model == 'power_coefficient_curve':
if self.power_plant.power_coefficient_curve is None:
raise TypeError("Power coefficient curve values of " +
self.power_plant.name +
" are missing.")
logging.debug('Calculating power output using power coefficient '
'curve.')
return (power_output.power_coefficient_curve(
wind_speed_hub,
self.power_plant.power_coefficient_curve[
'wind_speed'],
self.power_plant.power_coefficient_curve[
'value'],
self.power_plant.rotor_diameter, density_hub))
else:
raise ValueError("'{0}' is an invalid value. ".format(
self.power_output_model) +
"`power_output_model` must be " +
"'power_curve' or 'power_coefficient_curve'.")
[docs] def run_model(self, weather_df):
r"""
Runs the model.
Parameters
----------
weather_df : pandas.DataFrame
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 and
density `density` in kg/m³ depending on `power_output_model` and
`density_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.
Other Parameters
----------------
roughness_length : Float, optional.
Roughness length.
turbulence_intensity : Float, optional.
Turbulence intensity.
Returns
-------
self
Examples
---------
>>> import numpy as np
>>> import pandas as pd
>>> 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])])
>>> weather_df.columns.get_level_values(0)[0]
'wind_speed'
"""
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))
self.power_output = self.calculate_power_output(wind_speed_hub,
density_hub)
return self