def test_smooth_power_curve(self):
        test_curve = wt.WindTurbine(**self.test_turbine).power_curve
        parameters = {
            'power_curve_wind_speeds': test_curve['wind_speed'],
            'power_curve_values': test_curve['value'],
            'standard_deviation_method': 'turbulence_intensity'
        }

        # Raise ValueError - `turbulence_intensity` missing
        with pytest.raises(ValueError):
            parameters['standard_deviation_method'] = 'turbulence_intensity'
            smooth_power_curve(**parameters)

        # Test turbulence_intensity method
        parameters['turbulence_intensity'] = 0.5
        wind_speed_values_exp = pd.Series([6.0, 7.0, 8.0, 9.0, 10.0],
                                          name='wind_speed')
        power_values_exp = pd.Series([
            1141906.9806766496, 1577536.8085282773, 1975480.993355767,
            2314059.4022704284, 2590216.6802602503
        ],
                                     name='value')
        smoothed_curve_exp = pd.DataFrame(
            data=pd.concat([wind_speed_values_exp, power_values_exp], axis=1))
        smoothed_curve_exp.index = np.arange(5, 10, 1)
        assert_frame_equal(
            smooth_power_curve(**parameters)[5:10], smoothed_curve_exp)

        # Test Staffel_Pfenninger method
        parameters['standard_deviation_method'] = 'Staffell_Pfenninger'
        power_values_exp = pd.Series([
            929405.1348918702, 1395532.5468724659, 1904826.6851982325,
            2402659.118305521, 2844527.1732449625
        ],
                                     name='value')
        smoothed_curve_exp = pd.DataFrame(
            data=pd.concat([wind_speed_values_exp, power_values_exp], axis=1))
        smoothed_curve_exp.index = np.arange(5, 10, 1)
        assert_frame_equal(
            smooth_power_curve(**parameters)[5:10], smoothed_curve_exp)

        # Raise ValueError - misspelling
        with pytest.raises(ValueError):
            parameters['standard_deviation_method'] = 'misspelled'
            smooth_power_curve(**parameters)
Example #2
0
    def assign_power_curve(self, wake_losses_model='power_efficiency_curve',
                           smoothing=False, block_width=0.5,
                           standard_deviation_method='turbulence_intensity',
                           smoothing_order='wind_farm_power_curves',
                           turbulence_intensity=None, **kwargs):
        r"""
        Calculates the power curve of a wind farm.

        The wind farm power curve is calculated by aggregating the power curves
        of all wind turbines in the wind farm. Depending on the parameters the
        power curves are smoothed (before or after the aggregation) and/or a
        wind farm efficiency (power efficiency curve or constant efficiency) is
        applied after the aggregation. After the calculations the power curve
        is assigned to the wind farm object.

        Parameters
        ----------
        wake_losses_model : string
            Defines the method for taking wake losses within the farm into
            consideration. Options: 'power_efficiency_curve',
            'constant_efficiency' or None. Default: 'power_efficiency_curve'.
        smoothing : boolean
            If True the power curves will be smoothed before or after the
            aggregation of power curves depending on `smoothing_order`.
            Default: False.
        block_width : float
            Width between the wind speeds in the sum of the equation in
            :py:func:`~.power_curves.smooth_power_curve`. Default: 0.5.
        standard_deviation_method : string
            Method for calculating the standard deviation for the Gauss
            distribution. Options: 'turbulence_intensity',
            'Staffell_Pfenninger'. Default: 'turbulence_intensity'.
        smoothing_order : string
            Defines when the smoothing takes place if `smoothing` is True.
            Options: 'turbine_power_curves' (to the single turbine power
            curves), 'wind_farm_power_curves'.
            Default: 'wind_farm_power_curves'.
        turbulence_intensity : float
            Turbulence intensity at hub height of the wind farm for power curve
            smoothing with 'turbulence_intensity' method. Can be calculated
            from `roughness_length` instead. Default: None.

        Other Parameters
        ----------------
        roughness_length : float, optional.
            Roughness length. If `standard_deviation_method` is
            'turbulence_intensity' and `turbulence_intensity` is not given
            the turbulence intensity is calculated via the roughness length.

        Returns
        -------
        self

        """
        # Check if all wind turbines have a power curve as attribute
        for item in self.wind_turbine_fleet:
            if item['wind_turbine'].power_curve is None:
                raise ValueError("For an aggregated wind farm power curve " +
                                 "each wind turbine needs a power curve " +
                                 "but `power_curve` of wind turbine " +
                                 "{} is {}.".format(
                                     item['wind_turbine'].name,
                                     item['wind_turbine'].power_curve))
        # Initialize data frame for power curve values
        df = pd.DataFrame()
        for turbine_type_dict in self.wind_turbine_fleet:
            # Check if all needed parameters are available and/or assign them
            if smoothing:
                if (standard_deviation_method == 'turbulence_intensity' and
                        turbulence_intensity is None):
                    if 'roughness_length' in kwargs:
                        # Calculate turbulence intensity and write to kwargs
                        turbulence_intensity = (
                            tools.estimate_turbulence_intensity(
                                turbine_type_dict['wind_turbine'].hub_height,
                                kwargs['roughness_length']))
                        kwargs['turbulence_intensity'] = turbulence_intensity
                    else:
                        raise ValueError(
                            "`roughness_length` must be defined for using " +
                            "'turbulence_intensity' as " +
                            "`standard_deviation_method` if " +
                            "`turbulence_intensity` is not given")
            if wake_losses_model is not None:
                if self.efficiency is None:
                    raise KeyError(
                        "`efficiency` is needed if " +
                        "`wake_losses_modelĀ“ is '{0}', but ".format(
                            wake_losses_model) +
                        "`efficiency` of {0} is {1}.".format(
                            self.name, self.efficiency))
            # Get original power curve
            power_curve = pd.DataFrame(
                turbine_type_dict['wind_turbine'].power_curve)
            # Editions to the power curves before the summation
            if smoothing and smoothing_order == 'turbine_power_curves':
                power_curve = power_curves.smooth_power_curve(
                    power_curve['wind_speed'], power_curve['value'],
                    standard_deviation_method=standard_deviation_method,
                    block_width=block_width, **kwargs)
            else:
                # Add value zero to start and end of curve as otherwise there
                # can occure problems during the aggregation
                if power_curve.iloc[0]['wind_speed'] != 0.0:
                    power_curve = pd.concat(
                        [pd.DataFrame(data={
                            'value': [0.0], 'wind_speed': [0.0]}),
                         power_curve])
                if power_curve.iloc[-1]['value'] != 0.0:
                    power_curve = pd.concat(
                        [power_curve, pd.DataFrame(data={
                            'value': [0.0], 'wind_speed': [
                                power_curve['wind_speed'].loc[
                                    power_curve.index[-1]] + 0.5]})])
            # Add power curves of all turbine types to data frame
            # (multiplied by turbine amount)
            df = pd.concat(
                [df, pd.DataFrame(power_curve.set_index(['wind_speed']) *
                 turbine_type_dict['number_of_turbines'])], axis=1)
        # Aggregate all power curves
        wind_farm_power_curve = pd.DataFrame(
            df.interpolate(method='index').sum(axis=1))
        wind_farm_power_curve.columns = ['value']
        wind_farm_power_curve.reset_index('wind_speed', inplace=True)
        # Editions to the power curve after the summation
        if smoothing and smoothing_order == 'wind_farm_power_curves':
            wind_farm_power_curve = power_curves.smooth_power_curve(
                wind_farm_power_curve['wind_speed'],
                wind_farm_power_curve['value'],
                standard_deviation_method=standard_deviation_method,
                block_width=block_width, **kwargs)
        if (wake_losses_model == 'constant_efficiency' or
                wake_losses_model == 'power_efficiency_curve'):
            wind_farm_power_curve = (
                power_curves.wake_losses_to_power_curve(
                    wind_farm_power_curve['wind_speed'].values,
                    wind_farm_power_curve['value'].values,
                    wake_losses_model=wake_losses_model,
                    wind_farm_efficiency=self.efficiency))
        self.power_curve = wind_farm_power_curve
        return self
Example #3
0
    def assign_power_curve(
        self,
        wake_losses_model="wind_farm_efficiency",
        smoothing=False,
        block_width=0.5,
        standard_deviation_method="turbulence_intensity",
        smoothing_order="wind_farm_power_curves",
        turbulence_intensity=None,
        **kwargs,
    ):
        r"""
        Calculates the power curve of a wind farm.

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

        Parameters
        ----------
        wake_losses_model : str
            Defines the method for taking wake losses within the farm into
            consideration. Options: 'wind_farm_efficiency' or None.
            Default: 'wind_farm_efficiency'.
        smoothing : bool
            If True the power curves will be smoothed before or after the
            aggregation of power curves depending on `smoothing_order`.
            Default: False.
        block_width : float
            Width between the wind speeds in the sum of the equation in
            :py:func:`~.power_curves.smooth_power_curve`. Default: 0.5.
        standard_deviation_method : str
            Method for calculating the standard deviation for the Gauss
            distribution. Options: 'turbulence_intensity',
            'Staffell_Pfenninger'. Default: 'turbulence_intensity'.
        smoothing_order : str
            Defines when the smoothing takes place if `smoothing` is True.
            Options: 'turbine_power_curves' (to the single turbine power
            curves), 'wind_farm_power_curves'.
            Default: 'wind_farm_power_curves'.
        turbulence_intensity : float
            Turbulence intensity at hub height of the wind farm for power curve
            smoothing with 'turbulence_intensity' method. Can be calculated
            from `roughness_length` instead. Default: None.
        roughness_length : float (optional)
            Roughness length. If `standard_deviation_method` is
            'turbulence_intensity' and `turbulence_intensity` is not given
            the turbulence intensity is calculated via the roughness length.

        Returns
        -------
        :class:`~.wind_farm.WindFarm`
            self

        """
        # Check if all wind turbines have a power curve as attribute
        for turbine in self.wind_turbine_fleet["wind_turbine"]:
            if turbine.power_curve is None:
                raise ValueError(
                    "For an aggregated wind farm power curve " +
                    "each wind turbine needs a power curve " +
                    "but `power_curve` of '{}' is None.".format(turbine))
        # Initialize data frame for power curve values
        df = pd.DataFrame()
        for ix, row in self.wind_turbine_fleet.iterrows():
            # Check if needed parameters are available and/or assign them
            if smoothing:
                if (standard_deviation_method == "turbulence_intensity"
                        and turbulence_intensity is None):
                    if ("roughness_length" in kwargs
                            and kwargs["roughness_length"] is not None):
                        # Calculate turbulence intensity and write to kwargs
                        turbulence_intensity = tools.estimate_turbulence_intensity(
                            row["wind_turbine"].hub_height,
                            kwargs["roughness_length"],
                        )
                        kwargs["turbulence_intensity"] = turbulence_intensity
                    else:
                        raise ValueError(
                            "`roughness_length` must be defined for using " +
                            "'turbulence_intensity' as " +
                            "`standard_deviation_method` if " +
                            "`turbulence_intensity` is not given")
            # Get original power curve
            power_curve = pd.DataFrame(row["wind_turbine"].power_curve)
            # Editions to the power curves before the summation
            if smoothing and smoothing_order == "turbine_power_curves":
                power_curve = power_curves.smooth_power_curve(
                    power_curve["wind_speed"],
                    power_curve["value"],
                    standard_deviation_method=standard_deviation_method,
                    block_width=block_width,
                    **kwargs,
                )
            else:
                # Add value zero to start and end of curve as otherwise
                # problems can occur during the aggregation
                if power_curve.iloc[0]["wind_speed"] != 0.0:
                    power_curve = pd.concat(
                        [
                            pd.DataFrame(data={
                                "value": [0.0],
                                "wind_speed": [0.0]
                            }),
                            power_curve,
                        ],
                        join="inner",
                    )
                if power_curve.iloc[-1]["value"] != 0.0:
                    power_curve = pd.concat(
                        [
                            power_curve,
                            pd.DataFrame(
                                data={
                                    "wind_speed": [
                                        power_curve["wind_speed"].loc[
                                            power_curve.index[-1]] + 0.5
                                    ],
                                    "value": [0.0],
                                }),
                        ],
                        join="inner",
                    )
            # Add power curves of all turbine types to data frame
            # (multiplied by turbine amount)
            df = pd.concat(
                [
                    df,
                    pd.DataFrame(
                        power_curve.set_index(["wind_speed"]) *
                        row["number_of_turbines"]),
                ],
                axis=1,
            )
        # Aggregate all power curves
        wind_farm_power_curve = pd.DataFrame(
            df.interpolate(method="index").sum(axis=1))
        wind_farm_power_curve.columns = ["value"]
        wind_farm_power_curve.reset_index(inplace=True)
        # Apply power curve smoothing and consideration of wake losses
        # after the summation
        if smoothing and smoothing_order == "wind_farm_power_curves":
            wind_farm_power_curve = power_curves.smooth_power_curve(
                wind_farm_power_curve["wind_speed"],
                wind_farm_power_curve["value"],
                standard_deviation_method=standard_deviation_method,
                block_width=block_width,
                **kwargs,
            )
        if wake_losses_model == "wind_farm_efficiency":
            if self.efficiency is not None:
                wind_farm_power_curve = power_curves.wake_losses_to_power_curve(
                    wind_farm_power_curve["wind_speed"].values,
                    wind_farm_power_curve["value"].values,
                    wind_farm_efficiency=self.efficiency,
                )
            else:
                msg = (
                    "If you use `wake_losses_model` '{model}' your WindFarm "
                    "needs an efficiency but `efficiency` is {eff}. \n\n"
                    "Failing farm:\n {farm}")
                raise ValueError(
                    msg.format(model=wake_losses_model,
                               farm=self,
                               eff=self.efficiency))
        self.power_curve = wind_farm_power_curve
        return self