Skip to content
Snippets Groups Projects
wind_turbines.py 7.38 KiB
Newer Older
Mads M. Pedersen's avatar
Mads M. Pedersen committed
import numpy as np


class WindTurbines():
    """Set of wind turbines"""
Mads M. Pedersen's avatar
Mads M. Pedersen committed

    def __init__(self, names, diameters, hub_heights, ct_funcs, power_funcs, power_unit):
        """Initialize WindTurbines
Mads M. Pedersen's avatar
Mads M. Pedersen committed

        Parameters
        ----------
        names : array_like
            Wind turbine names
        diameters : array_like
            Diameter of wind turbines
        hub_heights : array_like
            Hub height of wind turbines
        ct_funcs : list of functions
            Wind turbine ct functions; func(ws) -> ct
        power_funcs : list of functions
            Wind turbine power functions; func(ws) -> power
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        power_unit : {'W', 'kW', 'MW', 'GW'}
            Unit of power_func output (case insensitive)
        """
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        self._names = names
        self._diameters = np.array(diameters)
        self._hub_heights = np.array(hub_heights)
        self.ct_funcs = ct_funcs
        self.power_scale = {'w': 1, 'kw': 1e3, 'mw': 1e6, 'gw': 1e9}[power_unit.lower()]
        if self.power_scale != 1:
            self.power_funcs = list([lambda ws, f=f: f(ws) * self.power_scale for f in power_funcs])
Mads M. Pedersen's avatar
Mads M. Pedersen committed

    def _info(self, var, types):
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        return var[np.asarray(types, np.int)]

Mads M. Pedersen's avatar
Mads M. Pedersen committed
    def hub_height(self, types=0):
        """Hub height of the specified type(s) of wind turbines
        """
        return self._info(self._hub_heights, types)
Mads M. Pedersen's avatar
Mads M. Pedersen committed

Mads M. Pedersen's avatar
Mads M. Pedersen committed
    def diameter(self, types=0):
        """Rotor diameter of the specified type(s) of wind turbines
        """
        return self._info(self._diameters, types)
Mads M. Pedersen's avatar
Mads M. Pedersen committed

Mads M. Pedersen's avatar
Mads M. Pedersen committed
    def name(self, types=0):
        """Name of the specified type(s) of wind turbines
        """
        return self._info(self._names, types)

    def power(self, ws_i, type_i=0):
        """Power in watt

        Parameters
        ----------
        ws_i : array_like, shape (i,...)
            Wind speed
        type_i : int or array_like, shape (i,)
            wind turbine type

Mads M. Pedersen's avatar
Mads M. Pedersen committed

        Returns
        -------
        power : array_like
            Power production for the specified wind turbine type(s) and wind speed
        """
        return self._ct_power(ws_i, type_i)[1]

    def ct(self, ws_i, type_i=0):
        """Thrust coefficient
        Parameters
        ----------
        ws_i : array_like, shape (i,...)
            Wind speed
        type_i : int or array_like, shape (i,)
            wind turbine type

        Returns
        -------
        ct : array_like
            Thrust coefficient for the specified wind turbine type(s) and wind speed
        """
        return self._ct_power(ws_i, type_i)[0]
    def _ct_power(self, ws_i, type_i=0):
            CT = np.zeros_like(ws_i, dtype=np.float)
            P = np.zeros_like(ws_i, dtype=np.float)
            type_i = np.zeros(np.asarray(ws_i).shape[0]) + type_i
Emre Barlas's avatar
Emre Barlas committed
            for t in np.unique(type_i).astype(np.int):
                m = type_i == t
                CT[m] = self.ct_funcs[t](ws_i[m])
                P[m] = self.power_funcs[t](ws_i[m])
            return CT, P
        else:
            return self.ct_funcs[0](ws_i), self.power_funcs[0](ws_i)
Mads M. Pedersen's avatar
Mads M. Pedersen committed

    def plot(self, x, y, types=None, ax=None):
        """Plot wind farm layout including type name and diameter

        Parameters
        ----------
        x : array_like
            x position of wind turbines
        y : array_like
            y position of wind turbines
        types : int or array_like
            type of the wind turbines
        ax : pyplot or matplotlib axes object, default None

        """
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        import matplotlib.pyplot as plt
        if types is None:
            types = np.zeros_like(x)
        if ax is None:
            ax = plt.gca()
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        markers = np.array(list("213v^<>o48spP*hH+xXDd|_"))

        from matplotlib.patches import Circle
        assert len(x) == len(y)
        types = np.zeros_like(x) + types  # ensure same length as x
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        for i, (x_, y_, d) in enumerate(zip(x, y, self.diameter(types))):
Mads M. Pedersen's avatar
Mads M. Pedersen committed
            circle = Circle((x_, y_), d / 2, color='gray', alpha=.5)
Mads M. Pedersen's avatar
Mads M. Pedersen committed
            ax.add_artist(circle)
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        for t, m in zip(np.unique(types), markers):
            ax.plot(np.asarray(x)[types == t], np.asarray(y)[types == t], '%sk' % m, label=self._names[int(t)])

Mads M. Pedersen's avatar
Mads M. Pedersen committed
        for i, (x_, y_, d) in enumerate(zip(x, y, self.diameter(types))):
            ax.annotate(i, (x_ + d / 2, y_ + d / 2), fontsize=7)
        ax.legend(loc=1)
        ax.axis('equal')
Mads M. Pedersen's avatar
Mads M. Pedersen committed


class OneTypeWindTurbines(WindTurbines):

    def __init__(self, name, diameter, hub_height, ct_func, power_func, power_unit):
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        """Initialize OneTypeWindTurbine

        Parameters
        ----------
        name : str
            Wind turbine name
        diameter : int or float
            Diameter of wind turbine
        hub_height : int or float
            Hub height of wind turbine
        ct_func : function
            Wind turbine ct function; func(ws) -> ct
        power_func : function
            Wind turbine power function; func(ws) -> power
        power_unit : {'W', 'kW', 'MW', 'GW'}
            Unit of power_func output (case insensitive)
        """
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        WindTurbines.__init__(self, [name], [diameter], [hub_height],
                              [ct_func],
                              [power_func],
Mads M. Pedersen's avatar
Mads M. Pedersen committed

Emre Barlas's avatar
Emre Barlas committed
def cube_power(ws_cut_in=3, ws_cut_out=25, ws_rated=12, power_rated=5000):
    def power_func(ws):
        ws = np.asarray(ws)
        power = np.zeros_like(ws, dtype=np.float)
Emre Barlas's avatar
Emre Barlas committed
        m = (ws >= ws_cut_in) & (ws < ws_rated)
        power[m] = power_rated * ((ws[m] - ws_cut_in) / (ws_rated - ws_cut_in))**3
        power[(ws >= ws_rated) & (ws <= ws_cut_out)] = power_rated
        return power
    return power_func

Mads M. Pedersen's avatar
Mads M. Pedersen committed

def dummy_thrust(ws_cut_in=3, ws_cut_out=25, ws_rated=12, ct_rated=8 / 9):
Emre Barlas's avatar
Emre Barlas committed
    # temporary thrust curve fix
    def ct_func(ws):
        ws = np.asarray(ws)
        ct = np.zeros_like(ws, dtype=np.float)
        if ct_rated > 0:
            # ct = np.ones_like(ct)*ct_rated
            m = (ws >= ws_cut_in) & (ws < ws_rated)
            ct[m] = ct_rated
            idx = (ws >= ws_rated) & (ws <= ws_cut_out)
            # second order polynomial fit for above rated
            ct[idx] = np.polyval(np.polyfit([ws_rated, (ws_rated + ws_cut_out) / 2,
                                             ws_cut_out], [ct_rated, 0.4, 0.03], 2), ws[idx])
Emre Barlas's avatar
Emre Barlas committed
        return ct
    return ct_func


Mads M. Pedersen's avatar
Mads M. Pedersen committed
def main():
    if __name__ == '__main__':

        wts = WindTurbines(names=['tb1', 'tb2'],
                           diameters=[80, 120],
                           hub_heights=[70, 110],
                           ct_funcs=[lambda ws: ws * 0 + 8 / 9,
                                     dummy_thrust()],
                           power_funcs=[cube_power(ws_cut_in=3, ws_cut_out=25, ws_rated=12, power_rated=2000),
                                        cube_power(ws_cut_in=3, ws_cut_out=25, ws_rated=12, power_rated=3000)],
Mads M. Pedersen's avatar
Mads M. Pedersen committed

        ws = np.arange(25)
        import matplotlib.pyplot as plt
        plt.plot(ws, wts.power(ws, 0), label=wts.name(0))
        plt.plot(ws, wts.power(ws, 1), label=wts.name(1))
        plt.legend()
        plt.show()
        plt.plot(ws, wts.ct(ws, 0), label=wts.name(0))
        plt.plot(ws, wts.ct(ws, 1), label=wts.name(1))
Mads M. Pedersen's avatar
Mads M. Pedersen committed
        plt.legend()
        plt.show()

        wts.plot([0, 100], [0, 100], [0, 1])
        plt.xlim([-50, 150])
        plt.ylim([-50, 150])
        plt.show()


main()