def test_interp_at_point(test_x, test_y, expected):

    X = np.array([0, 1, 2, 3, 4])
    Y = np.array([0, 1, 2])

    U = np.array([[np.nan, 1, 0, -1, np.nan], [np.nan, 1, 0, -1, np.nan],
                  [np.nan, 1, 0, -1, np.nan]])
    Q = [U]

    result = interp_at_point(test_x, test_y, X, Y, Q)

    assert np.isclose(result[0], expected)
    def _makeHalfStreamline(self, x0, y0, sign):
        """
        Compute a streamline extending in one direction from the given point.
        """

        xmin = self.x[0]
        xmax = self.x[-1]
        ymin = self.y[0]
        ymax = self.y[-1]

        sx = []
        sy = []

        x = x0
        y = y0
        i = 0
        while xmin < x < xmax and ymin < y < ymax:
            [u, v] = interp_at_point(x, y, self.x, self.y, [self.u, self.v])
            theta = np.arctan2(v, u)

            x += sign * self.dr * np.cos(theta)
            y += sign * self.dr * np.sin(theta)

            # Check if out on domain
            # if self.detectLoops and i % 10 == 0 and self._detectLoop(sx, sy):
            if not sx == []:
                if self.detectLoops and self._detectLoop(sx, sy):
                    break

            # Check if x or y == nan
            if np.isnan(x) or np.isnan(y):
                break
            else:
                sx.append(x)
                sy.append(y)

                i += 1

        return sx, sy
예제 #3
0
def transec_surf(hydro, array, debug=False):
    """
    Computes transect surface (m2) and first row of the array

    Args:
      hydro (dtocean_tidal.main.Hydro): dtocean_tidal's Hydro object
      array (dtocean_tidal.main.Array): dtocean_tidal's Array object

    Kwargs:
      debug (bool): debug flag

    Returns:
      transect (float): lease's transect surface (m2), float
      first_row (list): first row of the array, list of ID numbers
      speed (float): averaged speed over transect (m/s), float

    """
    if debug: module_logger.info("Computing relative blockage ratio RBR...")
    Nturb = len(array.positions.keys())
    (xm, ym, xM, yM) = hydro.lease.bounds
    l = []
    ref = np.arange(Nturb)

    # In case there is only one turbine
    if Nturb == 1:
        l = array.positions.keys()[7:]  # removing 'turbine' from key
    else:
        for k1 in array.distances.keys():
            for k2 in array.distances[k1].keys():
                # find turbine away from 1 diam
                diam = array.features[k1]['Diam']
                if array.distances[k1][k2][
                        0] > diam:  # check distance along streamline
                    l.append(k2)

    # unique occurrence
    L = np.asarray(l).astype(int)
    un = np.unique(L)
    # first row composed of
    first_row = list(set(ref) - set(un))

    # Fix for odd cases/flows where no obvious first raw
    # First_row = to turbine with the least interactions (n.b.: first raw should not have any)
    if first_row == []:
        unique, counts = np.unique(L, return_counts=True)
        first_row = list(unique[np.where(counts == counts.min())])

    # check for missing turbine in the first row within a diam radius
    iterlist = first_row[:]
    for ii in iterlist:
        for jj in range(Nturb):
            diam = array.features['turbine' + str(ii)]['Diam']
            xdist = np.abs(array.positions['turbine' + str(ii)][0] -
                           array.positions['turbine' + str(jj)][0])
            ydist = np.abs(array.positions['turbine' + str(ii)][1] -
                           array.positions['turbine' + str(jj)][1])
            if np.sqrt(xdist**2.0 + ydist**2.0) < diam:
                first_row.append(jj)
    first_row = np.unique(first_row)

    # define linear function representative on the 1st row's ray line
    x1 = array.positions['turbine' + str(first_row[0])][0]
    y1 = array.positions['turbine' + str(first_row[0])][1]
    x2 = array.positions['turbine' + str(first_row[-1])][0]
    y2 = array.positions['turbine' + str(first_row[-1])][1]
    a = np.array([[x1, 1], [x2, 1]])
    b = np.array([y1, y2])
    try:
        coeffs = np.linalg.solve(a, b)
        ybm = coeffs[0] * xm + coeffs[1]
        ybM = coeffs[0] * xM + coeffs[1]
        xbm = xm
        xbM = xM
    except LinAlgError:  # error when row parallel of perpendicular to x axis
        if x1 == x2:
            ybm = ym
            ybM = yM
            xbm = x1
            xbM = x1
        if y1 == y2:
            ybm = y1
            ybM = y1
            xbm = xm
            xbM = xM

    # define lineString within lease
    box = hydro.lease
    line = LineString([[xbm, ybm], [xbM, ybM]])
    inter_line = box.intersection(line)

    # calculate ratio between rotors surface and transect
    diam = array.features['turbine' + str(first_row[-1])]['Diam']
    n = inter_line.length // diam
    dl = inter_line.length / (n - 1)
    pts = map(inter_line.interpolate,
              np.arange(n) * dl)  # define points uniformly along line
    #  interpolate bathymetry at those points
    Q = [hydro.SSH, hydro.bathy, hydro.U, hydro.V]
    wh = 0.0  # water column height
    speed = 0.0  # speed over transect
    for pt in pts:
        [el, h, u, v] = interp_at_point(pt.x, pt.y, hydro.X, hydro.Y, Q)
        # Don't allow NaNs
        if np.isnan([el, h, u, v]).any(): continue
        # quantity formatting
        if h < 0.0: h *= -1.0
        wh += (h + el)
        speed += np.sqrt(u**2.0 + v**2.0)
    # relative blockage ratio
    transect = (wh / n) * inter_line.length  # average transect surface
    speed = speed / n

    return transect, first_row, speed
예제 #4
0
    def read_at_point(self, x, y, ct, ti, debug=False):
        """
        Interpolates CFD datasets stored in self._df based on Ct and TI values
        Args:
          x (float): relative distance along streamline, m
          y (float): relative distance across streamline, m
          ct (float): turbine's thrust coefficient, dimensionless
          ti (float): turbulence intensity at hub's location, dimensionless [0 ; 1]

        Returns:
          u (numpy array): 2D array, flow field, m/s
          tke (numpy array): 2D array, TKE filed, m2/s2
        """

        debug = debug or self._debug
        if debug: module_logger.info("Picking CFD datasets...")

        # Looking through available Ct's and TI's values
        ctbounds = []
        for ss, ee in zip(self._cts[:-1], self._cts[1:]):
            if ss <= ct <= ee:
                ctbounds = [ss, ee]

        tibounds = []
        for ss, ee in zip(self._tis[:-1], self._tis[1:]):
            if ss <= ti <= ee:
                tibounds = [ss, ee]

        # If requested values outside of range
        if ctbounds == []:
            module_logger.debug(("Requested Ct value {} is not covered by the "
                                 "current CFD database.").format(ct))
            idx = (np.abs(self._cts - ct)).argmin()
            try:
                ctbounds = [self._cts[idx-1], self._cts[idx]]
            except IndexError:
                ctbounds = [self._cts[idx], self._cts[idx + 1]]
            module_logger.debug(("Ct value of {} will be "
                                 "used.").format(self._cts[idx]))

        if tibounds == []:
            module_logger.debug(("Requested TI value {} is not covered by "
                                 "the current CFD database.").format(ti))
            idx = (np.abs(self._tis - ti)).argmin()
            try:
                tibounds = [self._tis[idx-1], self._tis[idx]]
            except IndexError:
                tibounds = [self._tis[idx], self._tis[idx+1]]
            module_logger.debug(("TI value of {} will be "
                                 "used.").format(self._tis[0]))

        # compute distance
        dist = np.zeros(4)
        dist[0] = (ct - ctbounds[0])**2.0 + (ti - tibounds[0])**2.0
        dist[1] = (ct - ctbounds[0])**2.0 + (ti - tibounds[1])**2.0
        dist[2] = (ct - ctbounds[1])**2.0 + (ti - tibounds[0])**2.0
        dist[3] = (ct - ctbounds[1])**2.0 + (ti - tibounds[1])**2.0
        mloc = dist.argmax()

        # computing weights
        nn = 0
        atmp = np.zeros(3)
        btmp = np.zeros(3)
        for n in range(4):
            if not n == mloc:
                if n==0:
                    atmp[nn] = ctbounds[0]
                    btmp[nn] = tibounds[0]
                elif n==1:
                    atmp[nn] = ctbounds[0]
                    btmp[nn] = tibounds[1]
                elif n==2:
                    atmp[nn] = ctbounds[1]
                    btmp[nn] = tibounds[0]
                elif n==3:
                    atmp[nn] = ctbounds[1]
                    btmp[nn] = tibounds[1]
                nn += 1

        wght = np.ones(3)
        wght[0] =(btmp[1]-btmp[2])*(ct-atmp[2]) + (atmp[2]-atmp[1])*(ti-btmp[2])
        wght[1]=(btmp[2]-btmp[0])*(ct-atmp[2]) + (atmp[0]-atmp[2])*(ti-btmp[2])
        wght[0:1] = wght[0:1] / ((btmp[1]-btmp[2])*(atmp[0]-atmp[2]) + (atmp[2]-atmp[1])*(btmp[0]-btmp[2]))
        wght[2] = 1.0 - wght[0] - wght[1]

        X = self._dfx
        Y = self._dfy

        if debug: module_logger.info("...interpolation...")
        u = 0.0
        v = 0.0
        tke = 0.0
        for n in range(3):
            tmpCt = atmp[n]
            tmpTi = btmp[n]
            umat = self._df['dfU']['ti'+str(tmpTi)]['ct'+str(tmpCt)] * wght[n]
            vmat = self._df['dfV']['ti'+str(tmpTi)]['ct'+str(tmpCt)] * wght[n]
            tkemat = self._df['dfTKE']['ti'+str(tmpTi)]['ct'+str(tmpCt)] * wght[n]
            tmp = interp_at_point(x, y, X, Y, [umat.T, vmat.T, tkemat.T])
            u += tmp[0]
            v += tmp[1]
            tke += tmp[2]

        return u, v, tke