Skip to content
Snippets Groups Projects
shear.py 3.18 KiB
Newer Older
import numpy as np
from numpy import newaxis as na
from abc import abstractmethod, ABC


class Shear(ABC):
    @abstractmethod
    def __call__(self, WS_ilk, WD_ilk, h_i):
        """Get wind speed at height

        Parameters
        ----------
        WS_ilk : array_like
            wind speed
        WD_ilk : array_like
            wind direction
        h_i : array_like
            height
        Returns
        -------
        WS_ilk : array_like
            Wind speed at height h_i
        """


class NoShear(Shear):
    def __call__(self, WS_ilk, WD_ilk, h_i):
        return WS_ilk


class PowerShear():
    def __init__(self, h_ref, alpha, interp_method='piecewise'):
        self.h_ref = h_ref
        from py_wake.site._site import Sector2Subsector
        self.alpha = Sector2Subsector(np.atleast_1d(alpha), interp_method=interp_method)

    def __call__(self, WS_ilk, WD_ilk, h_i):
        WD_index_ilk = np.round(WD_ilk).astype(np.int)

        wind_shear_ratio = (np.asarray(h_i) / self.h_ref)[:, na, na] ** self.alpha[WD_index_ilk]
        return WS_ilk * wind_shear_ratio


# ======================================================================================================================
# Potentially the code below can be used to implement power/log shear interpolation between grid layers
# ======================================================================================================================
# class InterpolationShear(ABC):
#     @abstractmethod
#     def setup(self, ds):
#         """"""
#
#     @abstractmethod
#     def __call__(self):
#         """"""
#
#
# class LinearInterpolationShear():
#     def setup(self, ds):
#         pass
#
#     def __call__(self, WS_ilk, WD_ilk, h_i):
#         return WS_ilk
#
#
# class PowerInterpolationShear():
#     """Apply wind shear coefficient based on speed-up factor at different
#     # height and a reference far field wind shear coefficient (alpha_far)"""
#
#     def __init__(self, alpha_far=.143):
#         self.alpha_far = alpha_far
#
#     def setup(self, ds):
#         ds['wind_shear'] = copy.deepcopy(ds['spd'])
#
#         heights = ds['wind_shear'].coords['z'].data
#
#         # if there is only one layer, assign default value
#         if len(heights) == 1:
#
#             ds['wind_shear'].data = (np.zeros_like(ds['wind_shear'].data) + self.alpha_far)
#
#             print('Note there is only one layer of wind resource data, ' +
#                   'wind shear are assumed as uniform, i.e., {0}'.format(self.alpha_far))
#         else:
#             ds['wind_shear'].data[:, :, 0, :] = (self.alpha_far +
#                                                  np.log(ds['spd'].data[:, :, 0, :] / ds['spd'].data[:, :, 1, :]) /
#                                                  np.log(heights[0] / heights[1]))
#
#             for h in range(1, len(heights)):
#                 ds['wind_shear'].data[:, :, h, :] = (
#                     self.alpha_far +
#                     np.log(ds['spd'].data[:, :, h, :] / ds['spd'].data[:, :, h - 1, :]) /
#                     np.log(heights[h] / heights[h - 1]))
#
#     def __call__(self, WS_ilk, WD_ilk, h_i):
#         ????? WS_ilk = (WS_ilk * (H_hub / self.height_ref) ** wind_shear_il[i_wt, l_wd])