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