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
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
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