pyart.retrieve.vad — pyart-mch 0.4.1 documentation

# Source code for pyart.retrieve.vad

    """
    pyart.retrieve.velocity_azimuth_display
    =======================================

    Retrieval of VADs from a radar object.

    .. autosummary::
        :toctreeL generated/
        :template: dev_template.rst

        velocity_azimuth_display
        _vad_calculation
        _interval_mean
        _sd_to_uv

    """

    import numpy as np

    from ..config import get_field_name
    from ..core import HorizontalWindProfile

    def velocity_azimuth_display(radar, vel_field=None, z_want=None,
                                 gatefilter=None):
        """
        Velocity azimuth display.

        Creates a VAD object containing U Wind, V Wind and height that
        can then be used to plot and produce the velocity azimuth display.

        Parameters
        ----------
        radar : Radar
            Radar object used.
        vel_field : string, optional
            Velocity field to use for VAD calculation.
        z_want : array, optional
            Heights for where to sample vads from.
            None will result in np.linespace(0, 10000, 100).
        gatefilter : GateFilter, optional
            A GateFilter indicating radar gates that should be excluded
            from the import vad calculation.

        Returns
        -------
        vad: HorizontalWindProfile
    	A velocity azimuth display object containing height, speed, direction,
            u_wind, v_wind from a radar object.

        Reference
        ---------
        Michelson, D. B., Andersson, T., Koistinen, J., Collier, C. G., Riedl, J.,
        Szturc, J., Gjertsen, U., Nielsen, A. and Overgaard, S. (2000) BALTEX Radar
        Data Centre Products and their Methodologies. In SMHI Reports. Meteorology
        and Climatology. Swedish Meteorological and Hydrological Institute,
        Norrkoping.

        """
        speeds = []
        angles = []
        heights = []

        # Pulling z data from radar
        z_gate_data = radar.gate_z['data']

        # Setting parameters
        if z_want is None:
            z_want = np.linspace(0, 1000, 100)

        # Parse field parameters
        if vel_field is None:
            radar.check_field_exists('velocity')
            vel_field = get_field_name('velocity')

        # Selecting what velocity data to use based on gatefilter
        if gatefilter is not None:
            velocities = np.ma.masked_where(
                gatefilter.gate_excluded,
                radar.fields[vel_field]['data'])
        else:
            velocities = radar.fields[vel_field]['data']

        # Getting radar sweep index values
        for i in range(len(radar.sweep_start_ray_index['data'])):
            index_start = radar.sweep_start_ray_index['data'][i]
            index_end = radar.sweep_end_ray_index['data'][i]
            if not (index_end - index_start) % 2 == 0:
                index_end = index_end - 1

            used_velocities = velocities[index_start:index_end]
            azimuth = radar.azimuth['data'][index_start:index_end]
            elevation = radar.fixed_angle['data'][i]

            # Calculating speed and angle
            speed, angle = _vad_calculation(
                used_velocities, azimuth, elevation)

            print('max height', z_gate_data[index_start, :].max(),
                  'meters')

            # Filling empty arrays with data
            speeds.append(speed)
            angles.append(angle)
            heights.append(z_gate_data[index_start, :])

        # Combining arrays and sorting
        speed_array = np.concatenate(speeds)
        angle_array = np.concatenate(angles)
        height_array = np.concatenate(heights)
        arg_order = height_array.argsort()
        speed_ordered = speed_array[arg_order]
        height_ordered = height_array[arg_order]
        angle_ordered = angle_array[arg_order]

        # Calculating U and V wind
        u_ordered, v_ordered = _sd_to_uv(speed_ordered, angle_ordered)
        u_mean = _interval_mean(u_ordered, height_ordered, z_want)
        v_mean = _interval_mean(v_ordered, height_ordered, z_want)
        vad = HorizontalWindProfile.from_u_and_v(
            z_want, u_mean, v_mean)
        return vad

    def _vad_calculation(velocity_field, azimuth, elevation):
        """ Calculates VAD for a scan, returns speed and angle
        outdic = vad_algorithm(velocity_field, azimuth, elevation)
        velocity_field is a 2D array, azimuth is a 1D array,
        elevation is a number. All in degrees, m outdic contains
        speed and angle. """

        # Creating array with radar velocity data
        nrays, nbins = velocity_field.shape
        nrays2 = nrays // 2
        velocity_count = np.ma.empty((nrays2, nbins, 2))
        velocity_count[:, :, 0] = velocity_field[0:nrays2, :]
        velocity_count[:, :, 1] = velocity_field[nrays2:, :]

        # Converting from degress to radians
        sinaz = np.sin(np.deg2rad(azimuth))
        cosaz = np.cos(np.deg2rad(azimuth))

        # Masking array and testing for nan values
        sumv = np.ma.sum(velocity_count, 2)
        vals = np.isnan(sumv)
        vals2 = np.vstack((vals, vals))

        # Summing non-nan data and creating new array with summed data
        count = np.sum(np.isnan(sumv) == False, 0)
        count = np.float64(count)
        u_m = np.array([np.nansum(sumv, 0) // (2 * count)])

        # Creating 0 value arrays
        cminusu_mcos = np.zeros((nrays, nbins))
        cminusu_msin = np.zeros((nrays, nbins))
        sincos = np.zeros((nrays, nbins))
        sin2 = np.zeros((nrays, nbins))
        cos2 = np.zeros((nrays, nbins))

        # Summing all sin and cos and setting select entires to nan
        for i in range(nbins):
            cminusu_mcos[:, i] = cosaz * (velocity_field[:, i] - u_m[:, i])
            cminusu_msin[:, i] = sinaz * (velocity_field[:, i] - u_m[:, i])
            sincos[:, i] = sinaz * cosaz
            sin2[:, i] = sinaz**2
            cos2[:, i] = cosaz**2

        cminusu_mcos[vals2] = np.nan
        cminusu_msin[vals2] = np.nan
        sincos[vals2] = np.nan
        sin2[vals2] = np.nan
        cos2[vals2] = np.nan
        sumcminu_mcos = np.nansum(cminusu_mcos, 0)
        sumcminu_msin = np.nansum(cminusu_msin, 0)
        sumsincos = np.nansum(sincos, 0)
        sumsin2 = np.nansum(sin2, 0)
        sumcos2 = np.nansum(cos2, 0)

        # Calculating speed and angle values
        b_value = (sumcminu_mcos - (sumsincos*sumcminu_msin / sumsin2)) / (
            sumcos2 - (sumsincos**2) / sumsin2)
        a_value = (sumcminu_msin - b_value*sumsincos) / sumsin2
        speed = np.sqrt(a_value**2 + b_value**2) / np.cos(
            np.deg2rad(elevation))
        angle = np.arctan2(a_value, b_value)
        return speed, angle

    def _interval_mean(data, current_z, wanted_z):
        """ Find the mean of data indexed by current_z
            at wanted_z on intervals wanted_z+/- delta
            wanted_z. """
        delta = wanted_z[1] - wanted_z[0]
        pos_lower = [np.argsort((current_z - (
            wanted_z[i] - delta / 2.0))**2)[0]
                     for i in range(len(wanted_z))]
        pos_upper = [np.argsort((current_z - (
            wanted_z[i] + delta / 2.0))**2)[0]
                     for i in range(len(wanted_z))]
        mean_values = np.array([data[pos_lower[i]:pos_upper[i]].mean()
                                for i in range(len(pos_upper))])
        return mean_values

    def _sd_to_uv(speed, direction):
        """ Takes speed and direction to create u_mean and v_mean. """
        return (np.sin(direction) * speed), (np.cos(direction) * speed)