Example #1
0
    def horizontal_wind_component(self, UV=None, UV_DIR=None,
                                  working_with_xarray=False, xarray_data=None, wind_name="Wind",
                                  wind_dir_name="Wind_DIR", verbose=True):
        """
        U = -np.sin(UV_DIR) * UV
        V = -np.cos(UV_DIR) * UV

        Computes U and V component from wind direction and wind speed

        Parameters
        ----------
        UV : dnarray
            Wind speed
        UV_DIR : dnarray
            Wind_direction
        working_with_xarray : boolean, optionnal
            If True, computes U and V on an xarray dataframe (provided with names of variables)
            and returns the dataframe

        Returns
        -------
        U : dnarray
            Horizontal wind speed component U
        V : string, optional
            Horizontal wind speed component V
        """
        if not (working_with_xarray):

            if self._numexpr:
                U = ne.evaluate("-sin(UV_DIR) * UV")
                V = ne.evaluate("-cos(UV_DIR) * UV")

            else:
                U = -np.sin(UV_DIR) * UV
                V = -np.cos(UV_DIR) * UV

            if verbose: print('__Horizontal wind component calculated')
            U = change_dtype_if_required(U, np.float32)
            V = change_dtype_if_required(V, np.float32)

            return (U, V)

        if working_with_xarray:
            xarray_data = xarray_data.assign(theta=lambda x: (np.pi / 180) * (x[wind_dir_name] % 360))
            xarray_data = xarray_data.assign(U=lambda x: -x[wind_name] * np.sin(x["theta"]))
            xarray_data = xarray_data.assign(V=lambda x: -x[wind_name] * np.cos(x["theta"]))
            if verbose: print('__Horizontal wind component calculated on xarray')
            return (xarray_data)
Example #2
0
    def direction_from_u_and_v(self, U, V, output_in_degree=True, verbose=True):
        """
        UV_DIR = 180 + (180/3.14159)*arctan2(U,V)) % 360

        Compute wind direction from U and V components

        Parameters
        ----------
        U : dnarray
            Horizontal wind speed component U
        V : string, optional
            Horizontal wind speed component V
        output_in_degree : boolean, optionnal
            If True, the wind direction is converted to degrees

        Returns
        -------
        UV_DIR : dnarray
            Wind direction
        """
        if output_in_degree:
            if self._numexpr:
                UV_DIR = ne.evaluate("(180 + (180/3.14159)*arctan2(U,V)) % 360")
            else:
                UV_DIR = np.mod(180 + np.rad2deg(np.arctan2(U, V)), 360)
            if verbose: print('__Wind_DIR calculated from U and V')
            UV_DIR = change_dtype_if_required(UV_DIR, np.float32)
            return (UV_DIR)
Example #3
0
    def angular_deviation(self, U, V, verbose=True):
        """
        Angular deviation from incoming flow.

        THe incoming flow is supposed from the West so that V=0. If deviated, V != 0.
        The angular deviation is then np.arctan(V / U)

        Parameters
        ----------
        U : dnarray
            Horizontal wind speed component U
        V : string, optional
            Horizontal wind speed component V

        Returns
        -------
        alpha : ndarray
            Angular deviation [rad]
        """
        if self._numexpr:
            alpha = ne.evaluate("where(U == 0, where(V == 0, 0, V/abs(V) * 3.14159 / 2), arctan(V / U))")
        else:
            alpha = np.where(U == 0,
                             np.where(V == 0, 0, np.sign(V) * np.pi / 2),
                             np.arctan(V / U))
        alpha = change_dtype_if_required(alpha, np.float32)
        if verbose: print("__Angular deviation calculated")
        return (alpha)
Example #4
0
    def direction_from_alpha(self, wind_dir, alpha, input_dir_in_degree=True, verbose=True):
        """
        wind_dir - alpha

        Wind direction modified by angular deviation due to wind/topography interaction.
        Warning: this function might return a new wind direction in a rotated coordinates.

        Parameters
        ----------
        wind_dir : dnarray
            Initial NWP wind direction
        alpha : dnarray
            Angular deviation
        input_dir_in_degree : boolean, optionnal
            If True, converts the input wind direction from radans to degrees (Default: True)

        Returns
        -------
        alpha : ndarray
            Modified wind direction
        """
        if input_dir_in_degree:
            if self._numexpr:
                UV_DIR = ne.evaluate("(3.14159/180) * wind_dir - alpha")
            else:
                UV_DIR = (np.pi / 180) * wind_dir - alpha
        UV_DIR = change_dtype_if_required(UV_DIR, np.float32)
        if verbose: print("__Wind_DIR calculated from alpha")
        return (UV_DIR)
Example #5
0
    def xsi_helbig_map(self, mnt, mu, idx_x, idx_y, reduce_mnt=True, nb_pixels_x=100, nb_pixels_y=100, librairie="numba", verbose=True):

        y_left, y_right, x_left, x_right = self._get_window_idx_boundaries(idx_x, idx_y, x_win=69//2, y_wind=79//2, reshape=False)

        if reduce_mnt:
            small_idx_y = idx_y[nb_pixels_y:-nb_pixels_y:, nb_pixels_x:-nb_pixels_x]
            small_idx_x = idx_x[nb_pixels_y:-nb_pixels_y:, nb_pixels_x:-nb_pixels_x]
            y_left, y_right, x_left, x_right = self._get_window_idx_boundaries(small_idx_x, small_idx_y)
            small_shape = small_idx_y.shape

        if librairie == "numba" and _numba:
            mnt, y_left, y_right, x_left, x_right = change_several_dtype_if_required([mnt, y_left, y_right, x_left, x_right], [np.float32, np.int32, np.int32, np.int32, np.int32])
            boundaries_mnt = [mnt.shape[0], mnt.shape[0], mnt.shape[1], mnt.shape[1]]
            y_left, y_right, x_left, x_right = self._control_idx_boundaries([y_left, y_right, x_left, x_right],
                                                                            min_idx=[0, 0, 0, 0],
                                                                            max_idx=boundaries_mnt)
            std_slicing_numba = jit([float32[:](float32[:, :], int32[:], int32[:], int32[:], int32[:])], cache=True, nopython=True)(self.std_slicing_numpy)
            std_flat = std_slicing_numba(mnt, y_left, y_right, x_left, x_right)
            librairie = "numba"
        else:
            std_flat = np.array([np.std(mnt[i1:j1, i2:j2]) for i1, j1, i2, j2 in zip(y_left, y_right, x_left, x_right)])
            librairie = "numpy"

        std = std_flat.reshape((small_shape[0], small_shape[1])) if reduce_mnt else std_flat
        if verbose: print(f"__Subgrid: computed average std. Output shape: {std.shape}. Librairie: {librairie}")

        xsi = np.sqrt(2) * std / mu

        xsi = change_dtype_if_required(xsi, np.float32)
        if verbose: print(f"__Subgrid: computed average xsi. Output shape: {xsi.shape}")
        return(xsi)
Example #6
0
    def wind_speed_scaling(self, scaling_wind, prediction, linear=True, verbose=True):
        """
        scaling_wind * prediction / 3

        Parameters
        ----------
        scaling_wind : dnarray
            Scaling wind (ex: NWP wind)
        prediction : ndarray
            CNN ouptut
        linear : boolean, optionnal
            Linear scaling (Default: True)

        Returns
        -------
        prediction : ndarray
            Scaled wind
        """
        if linear:
            if self._numexpr:
                prediction = ne.evaluate("scaling_wind * prediction / 3")
            else:
                prediction = scaling_wind * prediction / 3
        prediction = change_dtype_if_required(prediction, np.float32)
        if verbose: print('__Wind speed scaling done')
        return (prediction)
Example #7
0
    def x_dsc_topo_helbig(self, mnt, dx=25, idx_x=None, idx_y=None, type="map", librairie="numba", verbose=True):

        a = 17.0393
        b = 0.737
        c = 1.0234
        d = 0.3794
        e = 1.9821

        if type == "map":
            laplacian = self.laplacian_map(mnt, dx, librairie=librairie, helbig=True)
            mu = self.mu_helbig_map(mnt, dx)
        elif type == "indexes":
            idx_x, idx_y = change_several_dtype_if_required([idx_x, idx_y], [np.int32, np.int32])
            laplacian = self.laplacian_idx(mnt, idx_x, idx_y, dx, librairie=librairie, helbig=True)
            mu = self.mu_helbig_idx(mnt, dx, idx_x, idx_y)

        term_1 = 1 - a*laplacian/(1 + a*np.abs(laplacian)**b)
        term_2 = c / (1 + d*mu**e)
        x = term_1*term_2

        if verbose:
            print(f"__MNT shape: {mnt.shape}")
            print(f"__x_dsc_topo computed. x shape: {x.shape}")

        x = change_dtype_if_required(x, np.float32)
        return(x)
Example #8
0
    def mu_helbig_average(self, mnt, dx, idx_x, idx_y, reduce_mnt=True, type="map", nb_pixels_x=100, nb_pixels_y=100, librairie="numba", verbose=True):

        if reduce_mnt:
            small_idx_y = idx_y[nb_pixels_y:-nb_pixels_y, nb_pixels_x:-nb_pixels_x]
            small_idx_x = idx_x[nb_pixels_y:-nb_pixels_y, nb_pixels_x:-nb_pixels_x]
            shape = small_idx_y.shape
            y_left, y_right, x_left, x_right = self._get_window_idx_boundaries(small_idx_x, small_idx_y)
        else:
            y_left, y_right, x_left, x_right = self._get_window_idx_boundaries(idx_x, idx_y, reshape=False)

        if type == "map":
            mu = self.mu_helbig_map(mnt, dx)

            if librairie == 'numba' and _numba:
                mu, y_left, y_right, x_left, x_right = change_several_dtype_if_required(
                    [mnt, y_left, y_right, x_left, x_right], [np.float32, np.int32, np.int32, np.int32, np.int32])
                jit_mean = jit([float32[:](float32[:, :], int32[:], int32[:], int32[:], int32[:])], nopython=True, cache=True)(self.mean_slicing_numpy)
                mu_flat = jit_mean(mu, y_left, y_right, x_left, x_right)
                librairie = "numba"
            else:
                mu_flat = np.array([np.mean(mu[i1:j1, i2:j2]) for i1, j1, i2, j2 in zip(y_left, y_right, x_left, x_right)])
                librairie = "numpy"
        elif type == "indexes":
            boundaries_mnt = [mnt.shape[0], mnt.shape[0], mnt.shape[1], mnt.shape[1]]
            y_left, y_right, x_left, x_right = self._control_idx_boundaries([y_left, y_right, x_left, x_right],
                                                                            min_idx=[0, 0, 0, 0],
                                                                            max_idx=boundaries_mnt)
            mu_flat = np.array([np.mean(self.mu_helbig_map(mnt[i1:j1, i2:j2], dx)) for i1, j1, i2, j2 in zip(y_left, y_right, x_left, x_right)])

        mu = mu_flat.reshape((shape[0], shape[1])) if reduce_mnt else mu_flat

        mu = change_dtype_if_required(mu, np.float32)
        if verbose: print(f"__Subgrid: computed average mu. Output shape: {mu.shape}. Librairie: {librairie}")

        return(mu)
Example #9
0
    def mu_helbig_map(self, mnt, dx, verbose=True):
        """
        Adapted from I. Gouttevin

        From Helbig et al. 2017
        """
        mu = np.sqrt(np.sum(np.array(np.gradient(mnt, dx))**2, axis=0)/2)
        mu = change_dtype_if_required(mu, np.float32)
        if verbose: print("__mu calculation using numpy")
        return(mu)
Example #10
0
    def laplacian_idx(self, mnt, idx_x, idx_y, dx, verbose=True, librairie='numpy', helbig=True):
        """
        Discrete laplacian on a regular grid
        """

        if librairie == 'numba' and _numba:

            mnt = change_dtype_if_required(mnt, np.float32)
            idx_x = change_dtype_if_required(idx_x, np.int32)
            idx_y = change_dtype_if_required(idx_y, np.int32)

            laplacian = self._laplacian_numba_idx(mnt, idx_x, idx_y, dx, helbig=helbig)
            librairie = librairie

        else:
            laplacian = self._laplacian_numpy_idx(mnt, idx_x, idx_y, dx, helbig=helbig)
            librairie = "numpy"

        laplacian = change_dtype_if_required(laplacian, np.float32)
        if verbose: print(f"__Laplacian calculated. Librarie: {librairie}")
        return(laplacian)
Example #11
0
    def compute_wind_speed(self, U=None, V=None, W=None,
                           computing='num', out=None,
                           xarray_data=None, u_name="U", v_name="V", verbose=True):
        """
        Calculates wind speed from wind speed components.

        First detects the number of wind component then calculates wind speed.
        The calculation can be performed on nmexpr, numpy or xarray dataset

        Parameters
        ----------
        U : dnarray
            Horizontal wind speed component U
        V : string, optional
            Horizontal wind speed component V
        W : string, optional
            Vertical wind speed component V
        out : ndarray, optional
            If specified, the output of the calculation is directly written in out,
            which is best for memory consumption (Default: None)
        computing : str, optional
            Select the librairie to use for calculation. If 'num' first test numexpr, if not available select numpy.
            If 'xarray', a xarray dataframe needs to be specified with the corresponding names for wind components.
            (Default: 'num')

        Returns
        -------
        UV : ndarray
            Wind speed
        """
        # Numexpr or numpy
        if computing == 'num':
            if out is None:
                if W is None:
                    wind_speed = self._2D_wind_speed(U=U, V=V, verbose=verbose)
                else:
                    wind_speed = self._3D_wind_speed(U=U, V=V, W=W, verbose=verbose)
                wind_speed = change_dtype_if_required(wind_speed, np.float32)
                return (wind_speed)
            else:
                if W is None:
                    self._2D_wind_speed(U=U, V=V, out=out, verbose=verbose)
                else:
                    self._3D_wind_speed(U=U, V=V, W=W, out=out, verbose=verbose)

        if computing == 'xarray':
            xarray_data = xarray_data.assign(Wind=lambda x: np.sqrt(x[u_name] ** 2 + x[v_name] ** 2))
            xarray_data = xarray_data.assign(
                Wind_DIR=lambda x: np.mod(180 + np.rad2deg(np.arctan2(x[u_name], x[v_name])), 360))
            if verbose: print("__Wind and Wind_DIR calculated on xarray")
            return (xarray_data)
Example #12
0
 def mu_helbig_idx(self, mnt, dx, idx_x, idx_y, verbose=True):
     mu = self.mu_helbig_map(mnt, dx)
     mu = change_dtype_if_required(mu, np.float32)
     if verbose: print("__Selecting indexes on mu")
     return(mu[idx_y, idx_x])
Example #13
0
        if verbose: print(f"__Subgrid: computed average xsi. Output shape: {xsi.shape}")
        return(xsi)

    def x_sgp_topo_helbig_idx(self, mnt, idx_x, idx_y, dx, L=2_000, type="map", reduce_mnt=True, nb_pixels_x=100, nb_pixels_y=100, verbose=True):

        a = 3.354688
        b = 1.998767
        c = 0.20286
        d = 5.951

        mu = self.mu_helbig_average(mnt, dx, idx_x, idx_y, type=type, reduce_mnt=reduce_mnt)
        xsi = self.xsi_helbig_map(mnt, mu, idx_x, idx_y, reduce_mnt=reduce_mnt, nb_pixels_x=nb_pixels_x, nb_pixels_y=nb_pixels_y, librairie="numba")

        x = 1 - (1 - (1/(1+a*mu**b))**c)*np.exp(-d*(L/xsi)**(-2))

        x = change_dtype_if_required(x, np.float32)
        if verbose: print(f"__Subgrid: computed x_sgp_topo. Output shape: {x.shape}")

        return(x)

    def subgrid(self, mnt_large, dx=25, L=2_000, idx_x=None, idx_y=None, type="map", reduce_mnt=True, nb_pixels_x=100, nb_pixels_y=100, verbose=True):

        if type == "map":
            shape = mnt_large.shape
            all_x_idx = range(shape[1])
            all_y_idx = range(shape[0])
            idx_x, idx_y = np.array(np.meshgrid(all_x_idx, all_y_idx)).astype(np.int32)
            if verbose: print(f"Large mnt shape: {shape}. Size reduction on x: 2 * {nb_pixels_x}. Size reduction on x: 2 * {nb_pixels_y} ")

        reduce_mnt = False if type == "indexes" else reduce_mnt
        x_sgp_topo = self.x_sgp_topo_helbig_idx(mnt_large, idx_x, idx_y, dx,