SPDX-FileCopyrightText: 2019 oemof developer group contact@oemof.org

SPDX-License-Identifier: MIT

SPDX-License-Identifier: CC-BY-4.0

ModelChain example

This example shows you the basic usage of the windpowerlib by using the ModelChain class. There are mainly three steps. First you have to import your weather data, then you need to specify your wind turbine, and in the last step call the windpowerlib functions to calculate the feed-in time series.

Before you start you have to import the packages needed for these steps.

Import necessary packages and modules

[1]:
import os
import pandas as pd
import requests

from windpowerlib import ModelChain, WindTurbine, create_power_curve
from windpowerlib import data as wt

You can use the logging package to get logging messages from the windpowerlib. Change the logging level if you want more or less messages.

[2]:
import logging
logging.getLogger().setLevel(logging.DEBUG)

Import weather data

In order to use the windpowerlib you need to at least provide wind speed data for the time frame you want to analyze. The function below imports example weather data from the weather.csv file provided along with the windpowerlib. The data includes wind speed at two different heights in m/s, air temperature in two different heights in K, surface roughness length in m and air pressure in Pa.

To find out which weather data in which units need to be provided to use the ModelChain or other functions of the windpowerlib see the individual function documentation.

[3]:
def get_weather_data(filename='weather.csv', **kwargs):
    r"""
    Imports weather data from a file.

    The data include wind speed at two different heights in m/s, air
    temperature in two different heights in K, surface roughness length in m
    and air pressure in Pa. The height in m for which the data applies is
    specified in the second row.
    In case no weather data file exists, an example weather data file is
    automatically downloaded and stored in the same directory as this example.

    Parameters
    ----------
    filename : str
        Filename of the weather data file. Default: 'weather.csv'.

    Other Parameters
    ----------------
    datapath : str, optional
        Path where the weather data file is stored.
        Default is the same directory this example is stored in.

    Returns
    -------
    :pandas:`pandas.DataFrame<frame>`
        DataFrame with time series for wind speed `wind_speed` in m/s,
        temperature `temperature` in K, roughness length `roughness_length`
        in m, and pressure `pressure` in Pa.
        The columns of the DataFrame are a MultiIndex where the first level
        contains the variable name as string (e.g. 'wind_speed') and the
        second level contains the height as integer at which it applies
        (e.g. 10, if it was measured at a height of 10 m). The index is a
        DateTimeIndex.

    """

    if 'datapath' not in kwargs:
        kwargs['datapath'] = os.path.dirname(__file__)

    file = os.path.join(kwargs['datapath'], filename)

    # download example weather data file in case it does not yet exist
    if not os.path.isfile(file):
        logging.debug("Download weather data for example.")
        req = requests.get("https://osf.io/59bqn/download")
        with open(file, "wb") as fout:
            fout.write(req.content)

    # read csv file
    weather_df = pd.read_csv(
        file,
        index_col=0,
        header=[0, 1],
        date_parser=lambda idx: pd.to_datetime(idx, utc=True))

    # change time zone
    weather_df.index = weather_df.index.tz_convert(
        'Europe/Berlin')

    return weather_df


# Read weather data from csv
weather = get_weather_data(filename='weather.csv', datapath='')
print(weather[['wind_speed', 'temperature', 'pressure']][0:3])
variable_name             wind_speed          temperature         pressure
height                            10       80           2      10        0
2010-01-01 00:00:00+01:00    5.32697  7.80697      267.60  267.57  98405.7
2010-01-01 01:00:00+01:00    5.46199  7.86199      267.60  267.55  98382.7
2010-01-01 02:00:00+01:00    5.67899  8.59899      267.61  267.54  98362.9

Initialize wind turbine

There are three ways to initialize a WindTurbine object in the windpowerlib. You can either use turbine data from the OpenEnergy Database (oedb) turbine library that is provided along with the windpowerlib, as done for the ‘enercon_e126’, or specify your own turbine by directly providing a power (coefficient) curve, as done below for ‘my_turbine’, or provide your own turbine data in csv files, as done for ‘my_turbine2’.

You can execute the following to get a table of all wind turbines for which power and/or power coefficient curves are provided.

[4]:
# get power curves
# get names of wind turbines for which power curves and/or are provided
# set print_out=True to see the list of all available wind turbines
df = wt.get_turbine_types(print_out=False)

# find all Enercons
print(df[df["manufacturer"].str.contains("Enercon")])
   manufacturer turbine_type  has_power_curve  has_cp_curve
1       Enercon   E-101/3050             True          True
2       Enercon   E-101/3500             True          True
3       Enercon   E-115/3000             True          True
4       Enercon   E-115/3200             True          True
5       Enercon   E-126/4200             True          True
6       Enercon   E-126/7500             True         False
7       Enercon   E-126/7580             True         False
8       Enercon   E-141/4200             True          True
9       Enercon     E-53/800             True          True
10      Enercon    E-70/2000             True         False
11      Enercon    E-70/2300             True          True
12      Enercon    E-82/2000             True          True
13      Enercon    E-82/2300             True          True
14      Enercon    E-82/2350             True          True
15      Enercon    E-82/3000             True          True
16      Enercon    E-92/2350             True          True
17      Enercon      E48/800             True          True
[5]:
# find all Enercon 101 turbines
print(df[df["turbine_type"].str.contains("E-101")])
  manufacturer turbine_type  has_power_curve  has_cp_curve
1      Enercon   E-101/3050             True          True
2      Enercon   E-101/3500             True          True
[6]:
# specification of wind turbine where power curve is provided in the
# oedb turbine library

enercon_e126 = {
        'turbine_type': 'E-126/4200',  # turbine type as in oedb turbine library
        'hub_height': 135  # in m
    }
# initialize WindTurbine object
e126 = WindTurbine(**enercon_e126)
[7]:
# specification of own wind turbine (Note: power curve values and
# nominal power have to be in Watt)
my_turbine = {
    'nominal_power': 3e6,  # in W
    'hub_height': 105,  # in m
    'power_curve': pd.DataFrame(
            data={'value': [p * 1000 for p in [
                      0.0, 26.0, 180.0, 1500.0, 3000.0, 3000.0]],  # in W
                  'wind_speed': [0.0, 3.0, 5.0, 10.0, 15.0, 25.0]})  # in m/s
    }
# initialize WindTurbine object
my_turbine = WindTurbine(**my_turbine)
[8]:
# specification of wind turbine where power coefficient curve and nominal
# power is provided in an own csv file

# Read your turbine data from your data file using functions like
# pandas.read_csv().
# >>> import pandas as pd
# >>> my_data = pd.read_csv("path/to/my/data/file")
# >>> my_power = my_data["my_power"]
# >>> my_wind_speed = my_data["my_wind_speed"]

my_power = pd.Series(
    [0.0, 39000.0, 270000.0, 2250000.0, 4500000.0, 4500000.0]
)
my_wind_speed = (0.0, 3.0, 5.0, 10.0, 15.0, 25.0)

my_turbine2 = {
    "nominal_power": 6e6,  # in W
    "hub_height": 115,  # in m
    "power_curve": create_power_curve(
        wind_speed=my_wind_speed, power=my_power
    ),
}
my_turbine2 = WindTurbine(**my_turbine2)

Use the ModelChain to calculate turbine power output

The ModelChain is a class that provides all necessary steps to calculate the power output of a wind turbine. When calling the ‘run_model’ method, first the wind speed and density (if necessary) at hub height are calculated and then used to calculate the power output. You can either use the default methods for the calculation steps, as done for ‘my_turbine’, or choose different methods, as done for the ‘e126’. Of course, you can also use the default methods while only changing one or two of them, as done for ‘my_turbine2’.

[9]:
# power output calculation for e126

# own specifications for ModelChain setup
modelchain_data = {
    'wind_speed_model': 'logarithmic',      # 'logarithmic' (default),
                                            # 'hellman' or
                                            # 'interpolation_extrapolation'
    'density_model': 'ideal_gas',           # 'barometric' (default), 'ideal_gas'
                                            #  or 'interpolation_extrapolation'
    'temperature_model': 'linear_gradient', # 'linear_gradient' (def.) or
                                            # 'interpolation_extrapolation'
    'power_output_model':
        'power_coefficient_curve',          # 'power_curve' (default) or
                                            # 'power_coefficient_curve'
    'density_correction': True,             # False (default) or True
    'obstacle_height': 0,                   # default: 0
    'hellman_exp': None}                    # None (default) or None

# initialize ModelChain with own specifications and use run_model method to
# calculate power output
mc_e126 = ModelChain(e126, **modelchain_data).run_model(
    weather)
# write power output time series to WindTurbine object
e126.power_output = mc_e126.power_output
DEBUG:root:Calculating wind speed using logarithmic wind profile.
DEBUG:root:Calculating temperature using temperature gradient.
DEBUG:root:Calculating density using ideal gas equation.
DEBUG:root:Calculating power output using power coefficient curve.
[10]:
# power output calculation for my_turbine

# initialize ModelChain with default parameters and use run_model
# method to calculate power output
mc_my_turbine = ModelChain(my_turbine).run_model(weather)
# write power output time series to WindTurbine object
my_turbine.power_output = mc_my_turbine.power_output
DEBUG:root:Calculating wind speed using logarithmic wind profile.
DEBUG:root:Calculating power output using power curve.
[11]:
# power output calculation for example_turbine
# own specification for 'power_output_model'
mc_example_turbine = ModelChain(
    my_turbine2,
    wind_speed_model='hellman').run_model(weather)
my_turbine2.power_output = mc_example_turbine.power_output
DEBUG:root:Calculating wind speed using hellman equation.
DEBUG:root:Calculating power output using power curve.

Plot results

If you have matplotlib installed you can visualize the calculated power output and used power (coefficient) curves.

[12]:
# try to import matplotlib
logging.getLogger().setLevel(logging.WARNING)
try:
    from matplotlib import pyplot as plt
    # matplotlib inline needed in notebook to plot inline
    %matplotlib inline
except ImportError:
    plt = None
[13]:
# plot turbine power output
if plt:
    e126.power_output.plot(legend=True, label='Enercon E126')
    my_turbine.power_output.plot(legend=True, label='myTurbine')
    my_turbine2.power_output.plot(legend=True, label='myTurbine2')
    plt.xlabel('Time')
    plt.ylabel('Power in W')
    plt.show()
_images/modelchain_example_notebook_21_0.png
[14]:
# plot power (coefficient) curves
if plt:
    if e126.power_coefficient_curve is not None:
        e126.power_coefficient_curve.plot(
            x='wind_speed', y='value', style='*',
            title='Enercon E126 power coefficient curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
    if e126.power_curve is not None:
        e126.power_curve.plot(x='wind_speed', y='value', style='*',
                              title='Enercon E126 power curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
    if my_turbine.power_coefficient_curve is not None:
        my_turbine.power_coefficient_curve.plot(
            x='wind_speed', y='value', style='*',
            title='myTurbine power coefficient curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
    if my_turbine.power_curve is not None:
        my_turbine.power_curve.plot(x='wind_speed', y='value', style='*',
                                    title='myTurbine power curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
    if my_turbine2.power_coefficient_curve is not None:
        my_turbine2.power_coefficient_curve.plot(
            x='wind_speed', y='value', style='*',
            title='myTurbine2 power coefficient curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
    if my_turbine2.power_curve is not None:
        my_turbine2.power_curve.plot(x='wind_speed', y='value', style='*',
                                    title='myTurbine2 power curve')
        plt.xlabel('Wind speed in m/s')
        plt.ylabel('Power in W')
        plt.show()
_images/modelchain_example_notebook_22_0.png
_images/modelchain_example_notebook_22_1.png
_images/modelchain_example_notebook_22_2.png
_images/modelchain_example_notebook_22_3.png
[ ]: