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

wind-python / windpowerlib / 350

30 Jul 2019 - 12:55 coverage: 99.603% (+3.2%) from 96.378%
350

Pull #62

travis-ci

web-flow
Update oedb turbine library files
Pull Request #62: Refactor v0.2.0 branch

123 of 124 new or added lines in 7 files covered. (99.19%)

502 of 504 relevant lines covered (99.6%)

2.99 hits per line

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

96.88
/windpowerlib/wind_farm.py
1
"""
2
The ``wind_farm`` module contains the class WindFarm that implements
3
a wind farm in the windpowerlib and functions needed for the modelling of a
4
wind farm.
5

6
"""
7

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

11
from windpowerlib import tools, power_curves
3×
12
import numpy as np
3×
13
import pandas as pd
3×
14
import logging
3×
15

16

17
class WindFarm(object):
3×
18
    r"""
19
    Defines a standard set of wind farm attributes.
20

21
    Parameters
22
    ----------
23
    wind_turbine_fleet : list(dict)
24
        Wind turbines of wind farm. Dictionaries must have 'wind_turbine'
25
        (contains a :class:`~.wind_turbine.WindTurbine` object) and
26
        'number_of_turbines' (number of wind turbines of the same turbine type
27
        in the wind farm) as keys.
28
    efficiency : float or :pandas:`pandas.DataFrame<frame>` or None (optional)
29
        Efficiency of the wind farm. Provide as either constant (float) or
30
        power efficiency curve (pd.DataFrame) containing 'wind_speed' and
31
        'efficiency' columns with wind speeds in m/s and the corresponding
32
        dimensionless wind farm efficiency. Default: None.
33
    name : str (optional)
34
        Can be used as an identifier of the wind farm. Default: ''.
35

36
    Attributes
37
    ----------
38
    wind_turbine_fleet : list(dict)
39
        Wind turbines of wind farm. Dictionaries must have 'wind_turbine'
40
        (contains a :class:`~.wind_turbine.WindTurbine` object) and
41
        'number_of_turbines' (number of wind turbines of the same turbine type
42
        in the wind farm) as keys.
43
    efficiency : float or :pandas:`pandas.DataFrame<frame>` or None
44
        Efficiency of the wind farm. Either constant (float) power efficiency
45
        curve (pd.DataFrame) containing 'wind_speed' and 'efficiency'
46
        columns with wind speeds in m/s and the corresponding
47
        dimensionless wind farm efficiency. Default: None.
48
    name : str
49
        If set this is used as an identifier of the wind farm.
50
    hub_height : float
51
        The calculated mean hub height of the wind farm. See
52
        :py:func:`mean_hub_height` for more information.
53
    nominal_power : float
54
        The nominal power is the sum of the nominal power of all turbines in
55
        the wind farm in W.
56
    power_curve : :pandas:`pandas.DataFrame<frame>` or None
57
        The calculated power curve of the wind farm. See
58
        :py:func:`assign_power_curve` for more information.
59

60
    Examples
61
    --------
62
    >>> from windpowerlib import wind_farm
63
    >>> from windpowerlib import wind_turbine
64
    >>> enerconE126 = {
65
    ...    'hub_height': 135,
66
    ...    'rotor_diameter': 127,
67
    ...    'turbine_type': 'E-126/4200'}
68
    >>> e126 = wind_turbine.WindTurbine(**enerconE126)
69
    >>> example_farm_data = {
70
    ...    'name': 'example_farm',
71
    ...    'wind_turbine_fleet': [{'wind_turbine': e126,
72
    ...                            'number_of_turbines': 6}]}
73
    >>> example_farm = wind_farm.WindFarm(**example_farm_data)
74
    >>> print(example_farm.nominal_power)
75
    25200000.0
76

77
    """
78

79
    def __init__(self, wind_turbine_fleet, efficiency=None, name='', **kwargs):
3×
80

81
        self.wind_turbine_fleet = wind_turbine_fleet
3×
82
        self.efficiency = efficiency
3×
83
        self.name = name
3×
84

85
        self.hub_height = None
3×
86
        self._nominal_power = None
3×
87
        self.power_curve = None
3×
88

89
    def __repr__(self):
3×
90

91
        if self.name is not '':
3×
92
            repr = 'Wind farm: {name}'.format(name=self.name)
3×
93
        else:
94
            info = []
3×
95
            for turbine_dict in self.wind_turbine_fleet:
3×
96
                info.append(r"{number}x {type}".format(
3×
97
                    number=turbine_dict['number_of_turbines'],
98
                    type=turbine_dict['wind_turbine']))
99
            repr = r'Wind farm with: {info}'.format(info=info)
3×
100
        return repr
3×
101

102
    @property
3×
103
    def nominal_power(self):
104
        r"""
105
        The nominal power of the wind farm.
106

107
        See :attr:`~.wind_farm.WindFarm.nominal_power` for further information.
108

109
        Parameters
110
        -----------
111
        nominal_power : float
112
            Nominal power of the wind farm in W.
113

114
        Returns
115
        -------
116
        float
117
            Nominal power of the wind farm in W.
118

119
        """
120
        if not self._nominal_power:
3×
121
            self.nominal_power = self.get_installed_power()
3×
122
        return self._nominal_power
3×
123

124
    @nominal_power.setter
3×
125
    def nominal_power(self, nominal_power):
126
        self._nominal_power = nominal_power
3×
127

128
    def mean_hub_height(self):
3×
129
        r"""
130
        Calculates the mean hub height of the wind farm.
131

132
        The mean hub height of a wind farm is necessary for power output
133
        calculations with an aggregated wind farm power curve containing wind
134
        turbines with different hub heights. Hub heights of wind turbines with
135
        higher nominal power weigh more than others.
136
        After the calculations the mean hub height is assigned to the attribute
137
        :py:attr:`~hub_height`.
138

139
        Returns
140
        -------
141
        :class:`~.wind_farm.WindFarm`
142
            self
143

144
        Notes
145
        -----
146
        The following equation is used [1]_:
147

148
        .. math:: h_{WF} = e^{\sum\limits_{k}{ln(h_{WT,k})}
149
                           \frac{P_{N,k}}{\sum\limits_{k}{P_{N,k}}}}
150

151
        with:
152
            :math:`h_{WF}`: mean hub height of wind farm,
153
            :math:`h_{WT,k}`: hub height of the k-th wind turbine of a wind
154
            farm, :math:`P_{N,k}`: nominal power of the k-th wind turbine
155

156
        References
157
        ----------
158
        .. [1]  Knorr, K.: "Modellierung von raum-zeitlichen Eigenschaften der
159
                 Windenergieeinspeisung f��r wetterdatenbasierte
160
                 Windleistungssimulationen". Universit��t Kassel, Diss., 2016,
161
                 p. 35
162

163
        """
164
        self.hub_height = np.exp(
3×
165
            sum(np.log(wind_dict['wind_turbine'].hub_height) *
166
                wind_dict['wind_turbine'].nominal_power *
167
                wind_dict['number_of_turbines']
168
                for wind_dict in self.wind_turbine_fleet) /
169
            self.get_installed_power())
170
        return self
3×
171

172
    def get_installed_power(self):
3×
173
        r"""
174
        Calculates :py:attr:`~nominal_power` of the wind farm.
175

176
        Returns
177
        -------
178
        float
179
            Nominal power of the wind farm in W. See :py:attr:`~nominal_power`
180
            for further information.
181

182
        """
183
        return sum(
3×
184
            wind_dict['wind_turbine'].nominal_power *
185
            wind_dict['number_of_turbines']
186
            for wind_dict in self.wind_turbine_fleet)
187

188
    def assign_power_curve(self, wake_losses_model='wind_farm_efficiency',
3×
189
                           smoothing=False, block_width=0.5,
190
                           standard_deviation_method='turbulence_intensity',
191
                           smoothing_order='wind_farm_power_curves',
192
                           turbulence_intensity=None, **kwargs):
193
        r"""
194
        Calculates the power curve of a wind farm.
195

196
        The wind farm power curve is calculated by aggregating the power curves
197
        of all wind turbines in the wind farm. Depending on the parameters the
198
        power curves are smoothed (before or after the aggregation) and/or a
199
        wind farm efficiency (power efficiency curve or constant efficiency) is
200
        applied after the aggregation.
201
        After the calculations the power curve is assigned to the attribute
202
        :py:attr:`~power_curve`.
203

204
        Parameters
205
        ----------
206
        wake_losses_model : str
207
            Defines the method for taking wake losses within the farm into
208
            consideration. Options: 'wind_farm_efficiency' or None.
209
            Default: 'wind_farm_efficiency'.
210
        smoothing : bool
211
            If True the power curves will be smoothed before or after the
212
            aggregation of power curves depending on `smoothing_order`.
213
            Default: False.
214
        block_width : float
215
            Width between the wind speeds in the sum of the equation in
216
            :py:func:`~.power_curves.smooth_power_curve`. Default: 0.5.
217
        standard_deviation_method : str
218
            Method for calculating the standard deviation for the Gauss
219
            distribution. Options: 'turbulence_intensity',
220
            'Staffell_Pfenninger'. Default: 'turbulence_intensity'.
221
        smoothing_order : str
222
            Defines when the smoothing takes place if `smoothing` is True.
223
            Options: 'turbine_power_curves' (to the single turbine power
224
            curves), 'wind_farm_power_curves'.
225
            Default: 'wind_farm_power_curves'.
226
        turbulence_intensity : float
227
            Turbulence intensity at hub height of the wind farm for power curve
228
            smoothing with 'turbulence_intensity' method. Can be calculated
229
            from `roughness_length` instead. Default: None.
230
        roughness_length : float (optional)
231
            Roughness length. If `standard_deviation_method` is
232
            'turbulence_intensity' and `turbulence_intensity` is not given
233
            the turbulence intensity is calculated via the roughness length.
234

235
        Returns
236
        -------
237
        :class:`~.wind_farm.WindFarm`
238
            self
239

240
        """
241
        # Check if all wind turbines have a power curve as attribute
242
        for item in self.wind_turbine_fleet:
3×
243
            if item['wind_turbine'].power_curve is None:
3×
244
                raise ValueError("For an aggregated wind farm power curve " +
!
245
                                 "each wind turbine needs a power curve " +
246
                                 "but `power_curve` of '{}' is None.".format(
247
                                     item['wind_turbine']))
248
        # Initialize data frame for power curve values
249
        df = pd.DataFrame()
3×
250
        for turbine_type_dict in self.wind_turbine_fleet:
3×
251
            # Check if needed parameters are available and/or assign them
252
            if smoothing:
3×
253
                if (standard_deviation_method == 'turbulence_intensity' and
3×
254
                        turbulence_intensity is None):
255
                    if 'roughness_length' in kwargs and \
3×
256
                            kwargs['roughness_length'] is not None:
257
                        # Calculate turbulence intensity and write to kwargs
258
                        turbulence_intensity = (
3×
259
                            tools.estimate_turbulence_intensity(
260
                                turbine_type_dict['wind_turbine'].hub_height,
261
                                kwargs['roughness_length']))
262
                        kwargs['turbulence_intensity'] = turbulence_intensity
3×
263
                    else:
264
                        raise ValueError(
3×
265
                            "`roughness_length` must be defined for using " +
266
                            "'turbulence_intensity' as " +
267
                            "`standard_deviation_method` if " +
268
                            "`turbulence_intensity` is not given")
269
            # Get original power curve
270
            power_curve = pd.DataFrame(
3×
271
                turbine_type_dict['wind_turbine'].power_curve)
272
            # Editions to the power curves before the summation
273
            if smoothing and smoothing_order == 'turbine_power_curves':
3×
274
                power_curve = power_curves.smooth_power_curve(
3×
275
                    power_curve['wind_speed'], power_curve['value'],
276
                    standard_deviation_method=standard_deviation_method,
277
                    block_width=block_width, **kwargs)
278
            else:
279
                # Add value zero to start and end of curve as otherwise
280
                # problems can occur during the aggregation
281
                if power_curve.iloc[0]['wind_speed'] != 0.0:
3×
282
                    power_curve = pd.concat(
3×
283
                        [pd.DataFrame(data={
284
                            'value': [0.0], 'wind_speed': [0.0]}),
285
                         power_curve], sort=True)
286
                if power_curve.iloc[-1]['value'] != 0.0:
3×
287
                    power_curve = pd.concat(
3×
288
                        [power_curve, pd.DataFrame(data={
289
                            'value': [0.0], 'wind_speed': [
290
                                power_curve['wind_speed'].loc[
291
                                    power_curve.index[-1]] + 0.5]})],
292
                        sort=True)
293
            # Add power curves of all turbine types to data frame
294
            # (multiplied by turbine amount)
295
            df = pd.concat(
3×
296
                [df, pd.DataFrame(power_curve.set_index(['wind_speed']) *
297
                 turbine_type_dict['number_of_turbines'])], axis=1)
298
        # Aggregate all power curves
299
        wind_farm_power_curve = pd.DataFrame(
3×
300
            df.interpolate(method='index').sum(axis=1))
301
        wind_farm_power_curve.columns = ['value']
3×
302
        wind_farm_power_curve.reset_index('wind_speed', inplace=True)
3×
303
        # Apply power curve smoothing and consideration of wake losses
304
        # after the summation
305
        if smoothing and smoothing_order == 'wind_farm_power_curves':
3×
306
            wind_farm_power_curve = power_curves.smooth_power_curve(
3×
307
                wind_farm_power_curve['wind_speed'],
308
                wind_farm_power_curve['value'],
309
                standard_deviation_method=standard_deviation_method,
310
                block_width=block_width, **kwargs)
311
        if wake_losses_model == 'wind_farm_efficiency':
3×
312
            if self.efficiency is not None:
3×
313
                wind_farm_power_curve = (
3×
314
                    power_curves.wake_losses_to_power_curve(
315
                        wind_farm_power_curve['wind_speed'].values,
316
                        wind_farm_power_curve['value'].values,
317
                        wind_farm_efficiency=self.efficiency))
318
            else:
NEW
319
                logging.info("`wake_losses_model` is {} but wind farm ".format(
!
320
                    wake_losses_model) + "efficiency is NOT taken into "
321
                                         "account as it is None.")
322
        self.power_curve = wind_farm_power_curve
3×
323
        return self
3×
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