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



[docs]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)