• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wind-python / windpowerlib / 120

16 Jan 2019 - 13:24 coverage: 96.514% (-0.1%) from 96.629%
120

Pull #32

travis-ci

web-flow
Add a function to read the old power curves.
Pull Request #32: Re-activate the removed csv file

13 of 14 new or added lines in 1 file covered. (92.86%)

443 of 459 relevant lines covered (96.51%)

2.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.92
/windpowerlib/power_curves.py
1
"""
2
The ``power_curves`` module contains functions for applying alterations like
3
power curve smoothing or reducing power values by an efficiency to the power
4
curve of a wind turbine, wind farm or wind turbine cluster.
5

6
"""
7

8
__copyright__ = "Copyright oemof developer group"
3×
9
__license__ = "GPLv3"
3×
10

11
import os
3×
12
from collections import namedtuple
3×
13
import numpy as np
3×
14
import pandas as pd
3×
15
from windpowerlib import tools
3×
16

17

18
def smooth_power_curve(power_curve_wind_speeds, power_curve_values,
3×
19
                       block_width=0.5, wind_speed_range=15.0,
20
                       standard_deviation_method='turbulence_intensity',
21
                       mean_gauss=0, **kwargs):
22
    r"""
23
    Smooths the input power curve values by using a Gauss distribution.
24

25
    The smoothing serves for taking the distribution of wind speeds over space
26
    into account.
27

28
    Parameters
29
    ----------
30
    power_curve_wind_speeds : pandas.Series or numpy.array
31
        Wind speeds in m/s for which the power curve values are provided in
32
        `power_curve_values`.
33
    power_curve_values : pandas.Series or numpy.array
34
        Power curve values corresponding to wind speeds in
35
        `power_curve_wind_speeds`.
36
    block_width : float
37
        Width between the wind speeds in the sum of equation :eq:`power`.
38
        Default: 0.5.
39
    wind_speed_range : float
40
        The sum in the equation below is taken for this wind speed range below
41
        and above the power curve wind speed. Default: 15.0.
42
    standard_deviation_method : string
43
        Method for calculating the standard deviation for the Gauss
44
        distribution. Options: 'turbulence_intensity', 'Staffell_Pfenninger'.
45
        Default: 'turbulence_intensity'.
46
    mean_gauss : float
47
        Mean of the Gauss distribution in
48
        :py:func:`~.tools.gauss_distribution`. Default: 0.
49

50
    Other Parameters
51
    ----------------
52
    turbulence intensity : float, optional
53
        Turbulence intensity at hub height of the wind turbine, wind farm or
54
        wind turbine cluster the power curve is smoothed for.
55

56
    Returns
57
    -------
58
    smoothed_power_curve_df : pd.DataFrame
59
        Smoothed power curve. DataFrame has 'wind_speed' and 'power' columns
60
        with wind speeds in m/s and the corresponding power curve value in W.
61

62
    Notes
63
    -----
64
    The following equation is used to calculated the power curves values of the
65
    smoothed power curve [1]_:
66

67
    .. math:: P_{smoothed}(v_{std}) = \sum\limits_{v_i} \Delta v_i \cdot P(v_i)
68
        \cdot \frac{1}{\sigma \sqrt{2 \pi}}
69
        \exp \left[-\frac{(v_{std} - v_i -\mu)^2}{2 \sigma^2} \right]
70
       :label: power
71

72
    with:
73
        P: power [W], v: wind speed [m/s],
74
        :math:`\sigma`: standard deviation (Gauss), :math:`\mu`: mean (Gauss)
75

76
        :math:`P_{smoothed}` is the smoothed power curve value,
77
        :math:`v_{std}` is the standard wind speed in the power curve,
78
        :math:`\Delta v_i` is the interval length between
79
        :math:`v_\text{i}` and :math:`v_\text{i+1}`
80

81
    Power curve smoothing is applied to take account for the spatial
82
    distribution of wind speed. This way of smoothing power curves is also used
83
    in [2]_ and [3]_.
84

85
    The standard deviation :math:`\sigma` of the above equation can be
86
    calculated by the following methods.
87

88
    'turbulence_intensity' [2]_:
89

90
    .. math:: \sigma = v_\text{std} \sigma_\text{n} = v_\text{std} TI
91

92
    with:
93
        TI: turbulence intensity
94

95
    'Staffell_Pfenninger' [4]_:
96

97
    .. math:: \sigma = 0.6 \cdot 0.2 \cdot v_\text{std}
98

99
    References
100
    ----------
101
    .. [1]  Knorr, K.: "Modellierung von raum-zeitlichen Eigenschaften der
102
             Windenergieeinspeisung f��r wetterdatenbasierte
103
             Windleistungssimulationen". Universit��t Kassel, Diss., 2016,
104
             p. 106
105
    .. [2]  N��rgaard, P. and Holttinen, H.: "A Multi-Turbine and Power Curve
106
             Approach". Nordic Wind Power Conference, 1.���2.3.2004, 2000, p. 5
107
    .. [3]  Kohler, S. and Agricola, A.-Cl. and Seidl, H.:
108
             "dena-Netzstudie II. Integration erneuerbarer Energien in die
109
             deutsche Stromversorgung im Zeitraum 2015 ��� 2020 mit Ausblick
110
             2025". Technical report, 2010.
111
    .. [4]  Staffell, I. and Pfenninger, S.: "Using Bias-Corrected Reanalysis
112
              to Simulate Current and Future Wind Power Output". 2005, p. 11
113

114
    """
115
    # Specify normalized standard deviation
116
    if standard_deviation_method == 'turbulence_intensity':
3×
117
        if ('turbulence_intensity' in kwargs and
3×
118
                kwargs['turbulence_intensity'] is not np.nan):
119
            normalized_standard_deviation = kwargs['turbulence_intensity']
3×
120
        else:
121
            raise ValueError("Turbulence intensity must be defined for " +
3×
122
                             "using 'turbulence_intensity' as " +
123
                             "`standard_deviation_method`")
124
    elif standard_deviation_method == 'Staffell_Pfenninger':
3×
125
        normalized_standard_deviation = 0.2
3×
126
    else:
127
        raise ValueError("{} is no valid `standard_deviation_method`. Valid "
3×
128
                         + "options are 'turbulence_intensity', or "
129
                         + "'Staffell_Pfenninger'".format(
130
            standard_deviation_method))
131
    # Initialize list for power curve values
132
    smoothed_power_curve_values = []
3×
133
    # Append wind speeds to `power_curve_wind_speeds`
134
    maximum_value = power_curve_wind_speeds.values[-1] + wind_speed_range
3×
135
    while power_curve_wind_speeds.values[-1] < maximum_value:
3×
136
        power_curve_wind_speeds = power_curve_wind_speeds.append(
3×
137
            pd.Series(power_curve_wind_speeds.iloc[-1] + 0.5,
138
                      index=[power_curve_wind_speeds.index[-1] + 1]))
139
        power_curve_values = power_curve_values.append(
3×
140
            pd.Series(0.0, index=[power_curve_values.index[-1] + 1]))
141
    for power_curve_wind_speed in power_curve_wind_speeds:
3×
142
        # Create array of wind speeds for the sum
143
        wind_speeds_block = (np.arange(
3×
144
            -wind_speed_range, wind_speed_range + block_width, block_width) +
145
            power_curve_wind_speed)
146
        # Get standard deviation for Gauss function
147
        standard_deviation = (
3×
148
            (power_curve_wind_speed * normalized_standard_deviation + 0.6)
149
            if standard_deviation_method is 'Staffell_Pfenninger'
150
            else power_curve_wind_speed * normalized_standard_deviation)
151
        # Get the smoothed value of the power output
152
        if standard_deviation == 0.0:
3×
153
            # The gaussian distribution is not defined for a standard deviation
154
            # of zero. Smoothed power curve value is set to zero.
155
            smoothed_value = 0.0
3×
156
        else:
157
            smoothed_value = sum(
3×
158
                block_width * np.interp(wind_speed, power_curve_wind_speeds,
159
                                        power_curve_values, left=0, right=0) *
160
                tools.gauss_distribution(
161
                    power_curve_wind_speed - wind_speed,
162
                    standard_deviation, mean_gauss)
163
                for wind_speed in wind_speeds_block)
164
        # Add value to list - add zero if `smoothed_value` is nan as Gauss
165
        # distribution for a standard deviation of zero.
166
        smoothed_power_curve_values.append(smoothed_value)
3×
167
    # Create smoothed power curve data frame
168
    smoothed_power_curve_df = pd.DataFrame(
3×
169
        data=[list(power_curve_wind_speeds.values),
170
              smoothed_power_curve_values]).transpose()
171
    # Rename columns of the data frame
172
    smoothed_power_curve_df.columns = ['wind_speed', 'power']
3×
173
    return smoothed_power_curve_df
3×
174

175

176
def wake_losses_to_power_curve(power_curve_wind_speeds, power_curve_values,
3×
177
                               wind_farm_efficiency,
178
                               wake_losses_model='power_efficiency_curve'):
179
    r"""
180
    Reduces the power values of a power curve by an efficiency (curve).
181

182
    Parameters
183
    ----------
184
    power_curve_wind_speeds : pandas.Series or numpy.array
185
        Wind speeds in m/s for which the power curve values are provided in
186
        `power_curve_values`.
187
    power_curve_values : pandas.Series or numpy.array
188
        Power curve values corresponding to wind speeds in
189
        `power_curve_wind_speeds`.
190
    wind_farm_efficiency : float or pd.DataFrame
191
        Efficiency of the wind farm. Either constant (float) or efficiency
192
        curve (pd.DataFrame) containing 'wind_speed' and 'efficiency' columns
193
        with wind speeds in m/s and the corresponding dimensionless wind farm
194
        efficiency (reduction of power). Default: None.
195
    wake_losses_model : String
196
        Defines the method for taking wake losses within the farm into
197
        consideration. Options: 'power_efficiency_curve',
198
        'constant_efficiency'. Default: 'power_efficiency_curve'.
199

200
    Returns
201
    -------
202
    power_curve_df : pd.DataFrame
203
        Power curve with power values reduced by a wind farm efficiency.
204
        DataFrame has 'wind_speed' and 'power' columns with wind speeds in m/s
205
        and the corresponding power curve value in W.
206

207
    """
208
    # Create power curve DataFrame
209
    power_curve_df = pd.DataFrame(
3×
210
        data=[list(power_curve_wind_speeds),
211
              list(power_curve_values)]).transpose()
212
    # Rename columns of DataFrame
213
    power_curve_df.columns = ['wind_speed', 'power']
3×
214
    if wake_losses_model == 'constant_efficiency':
3×
215
        if not isinstance(wind_farm_efficiency, float):
3×
216
            raise TypeError("'wind_farm_efficiency' must be float if " +
3×
217
                            "`wake_losses_model�� is '{}' but is {}".format(
218
                                wake_losses_model, wind_farm_efficiency))
219
        power_curve_df['power'] = power_curve_values * wind_farm_efficiency
3×
220
    elif wake_losses_model == 'power_efficiency_curve':
3×
221
        if (not isinstance(wind_farm_efficiency, dict) and
3×
222
                not isinstance(wind_farm_efficiency, pd.DataFrame)):
223
            raise TypeError(
!
224
                "'wind_farm_efficiency' must be pd.DataFrame if " +
225
                "`wake_losses_model�� is '{}' but is {}".format(
226
                    wake_losses_model, wind_farm_efficiency))
227
        df = pd.concat([power_curve_df.set_index('wind_speed'),
3×
228
                        wind_farm_efficiency.set_index('wind_speed')], axis=1)
229
        # Add column with reduced power (nan values of efficiency are interpolated)
230
        df['reduced_power'] = df['power'] * df['efficiency'].interpolate(
3×
231
            method='index')
232
        reduced_power = df['reduced_power'].dropna()
3×
233
        power_curve_df = pd.DataFrame([reduced_power.index,
3×
234
                                       reduced_power.values]).transpose()
235
        power_curve_df.columns = ['wind_speed', 'power']
3×
236
    else:
237
        raise ValueError(
!
238
            "`wake_losses_model` is {} but should be ".format(
239
                wake_losses_model) +
240
            "'constant_efficiency' or 'power_efficiency_curve'")
241
    return power_curve_df
3×
242

243

244
def get_power_curve_from_file(name, filename=None, coefficient_curve=False):
3×
245
    """
246
    Get a power curve from a csv file as a named tuple. Fields are
247

248
    * windspeed (array)
249
    * value (power or coefficient) (array)
250
    * nominal_power (int)
251

252
    The csv file has to have a special format. See example file.
253

254
    Parameters
255
    ----------
256
    name : str
257
        Type of the turbine (full name)
258
    filename : str or None
259
        Full filename of the csv file. If None an internal file will be used.
260

261
    Examples
262
    --------
263
    >>> data = get_power_curve_from_file('AN BONUS 54')
264
    >>> data.nominal_power
265
    1000000
266
    >>> my_turbine = {
267
    ...     'name': 'myTurbine',
268
    ...     'nominal_power': data.nominal_power,
269
    ...     'hub_height': 105,
270
    ...     'rotor_diameter': 90,
271
    ...     'power_curve': pd.DataFrame({'power': data.value,
272
    ...                                  'wind_speed': data.windspeed})}
273
    >>> my_turbine['nominal_power']
274
    1000000
275

276
    Returns
277
    -------
278
    namedtuple : Fields: windspeed, value, nominal_power
279

280
    """
281
    pwr_curve = namedtuple('power_curve', 'windspeed, value, nominal_power')
3×
282
    if filename is None:
3×
283
        if coefficient_curve:
3×
NEW
284
            fn = 'power_coefficient_curves.csv'
!
285
        else:
286
            fn = 'power_curves.csv'
3×
287

288
        filename = os.path.join(os.path.dirname(__file__), 'data', fn)
3×
289
    pc = pd.read_csv(filename, index_col=[1])
3×
290

291
    pc.drop(['source', 'modificationtimestamp', 'Unnamed: 0'], axis=1,
3×
292
            inplace=True)
293

294
    p_nom = pc.pop('p_nom')
3×
295
    pc = pc.unstack().unstack()[name].dropna()
3×
296
    return pwr_curve(nominal_power=p_nom[name], windspeed=pc.index.values,
3×
297
                     value=pc.values)
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc