Source code for windpowerlib.modelchain

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