"""
pyrad.prod.process_vol_products
===============================
Functions for obtaining Pyrad products from a radar volume dataset
.. autosummary::
:toctree: generated/
generate_vol_products
"""
from copy import deepcopy
from ..util import warn
import os
import numpy as np
import pyart
from netCDF4 import num2date
import importlib
from ..io.io_aux import get_save_dir, make_filename, get_fieldname_pyart
from ..io.io_aux import generate_field_name_str
from ..io.trajectory import Trajectory
from ..io.write_data import write_cdf, write_rhi_profile, write_field_coverage
from ..io.write_data import write_last_state, write_histogram, write_quantiles
from ..io.write_data import write_fixed_angle, write_monitoring_ts
from ..io.write_data import write_alarm_msg, write_timeseries_point, send_msg
from ..io.write_data import write_vol_kml, write_vol_csv
from ..io.read_data_dem import read_dem
from ..io.read_data_other import read_monitoring_ts
from ..graph.plots_vol import plot_ppi, plot_ppi_map, plot_rhi, plot_cappi
from ..graph.plots_vol import plot_bscope, plot_rhi_profile, plot_along_coord
from ..graph.plots_vol import plot_field_coverage, plot_time_range
from ..graph.plots_vol import plot_rhi_contour, plot_ppi_contour
from ..graph.plots_vol import plot_fixed_rng, plot_fixed_rng_span
from ..graph.plots_vol import plot_roi_contour, plot_ray
from ..graph.plots_vol import plot_xsection
from ..graph.plots import plot_quantiles, plot_histogram
from ..graph.plots import plot_selfconsistency_instrument
from ..graph.plots import plot_selfconsistency_instrument2
from ..graph.plots_aux import get_colobar_label, get_field_name
from ..graph.plots_timeseries import plot_monitoring_ts, plot_timeseries
from ..util.radar_utils import get_ROI, compute_profile_stats
from ..util.radar_utils import compute_histogram, compute_quantiles
from ..util.radar_utils import get_data_along_rng, get_data_along_azi
from ..util.radar_utils import get_data_along_ele
from ..util.stat_utils import quantiles_weighted
if importlib.util.find_spec("simplekml"):
_SIMPLEKML_AVAILABLE = True
else:
_SIMPLEKML_AVAILABLE = False
[docs]
def generate_vol_products(dataset, prdcfg):
"""
Generates radar volume products. Accepted product types:
'ANTENNA_POS': Plots time series of the antenna position with respect
to elevation or azimuth
User defined parameters:
dpi: float
dpi of the plot
datatype: str
type of data to plot. Can be AZ or EL
'CDF': plots and writes the cumulative density function of data
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
quantiles: list of floats
The quantiles to compute in percent. Default None
sector: dict
dictionary defining the sector where to compute the CDF.
Default is None and the CDF is computed over all the data
May contain:
rmin, rmax: float
min and max range [m]
azmin, azmax: float
min and max azimuth angle [deg]
elmin, elmax: float
min and max elevation angle [deg]
hmin, hmax: float
min and max altitude [m MSL]
vismin: float
The minimum visibility to use the data. Default None
absolute: Bool
If true the absolute values of the data will be used.
Default False
use_nans: Bool
If true NaN values will be used. Default False
nan_value: Bool
The value by which the NaNs are substituted if NaN values
are to be used in the computation
filterclt: Bool
If True the gates containing clutter are filtered
filterprec: list of ints
The hydrometeor types that are filtered from the analysis.
Default empty list.
'BSCOPE_IMAGE': Creates a B-scope image (azimuth, range)
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
anglenr : int
The elevation angle number to use
ray_dim : str
the ray dimension. Can be 'ang' or 'time'. Default 'ang'
xaxis_rng : bool
if True the range will be in the x-axis. Otherwise it will
be in the y-axis. Default True
vmin, vmax: float or None
The minimum and maximum values of the color scale. If None
the scale is going to be set according to the Py-ART
config file
'CAPPI_IMAGE': Creates a CAPPI image
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
altitude: flt
CAPPI altitude [m MSL]
wfunc: str
The function used to produce the CAPPI as defined in
pyart.map.grid_from_radars. Default 'NEAREST'
cappi_res: float
The CAPPI resolution [m]. Default 500.
'CROSS_SECTION' : Plots a cross-section of polar data through
arbitrary coordinates
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
coord1, coord2, ..., coordN: dict
The two lat-lon coordinates marking the limits. They have
the keywords 'lat' and 'lon' [degree].
step : int
Step in meters to use between reference points to calculate
the cross-section (i.e horizontal resolution).
vert_res : int
Vertical resolution in meters used to calculate the
cross-section
alt_max : int
Maximum altitude of the vertical cross-section
beamwidth : float
3dB beamwidth in degrees to be used in the calculations,
if not provided will be read from the loc file
demfile : str
Name of the DEM file to use to plot the topography, it
must be in the dempath specified in the main config file
'FIELD_COVERAGE': Gets the field coverage over a certain sector
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
threshold: float or None
Minimum value to consider the data valid. Default None
nvalid_min: float
Minimum number of valid gates in the ray to consider it
valid. Default 5
ele_res, azi_res: float
Elevation and azimuth resolution of the sectors [deg].
Default 1. and 2.
ele_min, ele_max: float
Min and max elevation angle defining the sector [deg].
Default 0. and 30.
ele_step: float
Elevation step [deg]. Default 5.
ele_sect_start, ele_sect_stop: float or None
start and stop angles of the sector coverage. Default None
quantiles: list of floats
The quantiles to compute in the sector. Default 10. to 90.
by steps of 10.
AngTol: float
The tolerance in elevation angle when putting the data in
a fixed grid
'FIXED_RNG_IMAGE': Plots a fixed range image
User defined parameters:
voltype: str or list of str
Name of the PyRAD variable to use. It must be either a
voltype available in the dataset or "RGB", which will make
an RGB plot of Zh, Zdr and RhoHV if they are available.
AngTol : float
The tolerance between the nominal angles and the actual
radar angles. Default 1.
ele_res, azi_res : float or None
The resolution of the fixed grid [deg]. If None, it will be
obtained from the separation between angles.
vmin, vmax : float or None
Minimum and maximum values of the color scale. If None, the
values are taken from the Py-ART configuration file.
plot_max : bool
If True, marks the maximum value with a red dot and annotates
its azimuth, elevation, and value. Default False.
'FIXED_RNG_SPAN_IMAGE': Plots a user-defined statistic over a fixed
range image
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
AngTol : float
The tolerance between the nominal angles and the actual
radar angles. Default 1.
ele_res, azi_res: float or None
The resolution of the fixed grid [deg]. If None it will be
obtained from the separation between angles
stat : str
The statistic to compute. Can be 'min', 'max', 'mean',
'mode'. Default 'max'
'HISTOGRAM': Computes a histogram of the radar volume data
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
step: float or None
the data quantization step. If none it will be obtained
from the Py-ART configuration file
write_data: Bool
If true the histogram data is written in a csv file
'PLOT_ALONG_COORD': Plots the radar volume data along a particular
coordinate
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
colors: list of str or None
The colors of each ploted line
data_on_y : bool
If True the x-axis is the coordinates, and the y the data
values. False swaps the axis. Default True
plot_legend : bool
If True a legend will be plotted. Default True
mode: str
Ploting mode. Can be 'ALONG_RNG', 'ALONG_AZI' or
'ALONG_ELE'
value_start, value_stop: float
The starting and ending points of the data to plot.
According to the mode it may refer to the range, azimuth
or elevation. If not specified the minimum and maximum
possible values are used
fix_elevations, fix_azimuths, fix_ranges: list of floats
The elevations, azimuths or ranges to plot for each mode.
'ALONG_RNG' would use fix_elevations and fix_azimuths
'ALONG_AZI' fix_ranges and fix_elevations
'ALONG_ELE' fix_ranges and fix_azimuths
AngTol: float
The tolerance to match the radar angle to the fixed angles
Default 1.
RngTol: float
The tolerance to match the radar range to the fixed ranges
Default 50.
use_altitude : bool
If true and in ALON_RNG mode the coordinate used is the
gate altitude. Otherwise is the range. Default False
'PLOT_TXH': Plots the transmitted signal power (H) for a standard
sunscan.
'PPI_CONTOUR': Plots a PPI countour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
anglenr: float
The elevation angle number
'PPI_CONTOUR_OVERPLOT': Plots a PPI of a field with another field
overplotted as a contour plot.
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
anglenr: float
The elevation angle number
'PPI_IMAGE': Plots a PPI image. It can also plot the histogram and the
quantiles of the data in the PPI.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
anglenr: float
The elevation angle number
plot_type: str
The type of plot to perform. Can be 'PPI', 'QUANTILES' or
'HISTOGRAM'
write_data: Bool
If True the histrogram will be also written in a csv
file
step: float or None
If the plot type is 'HISTOGRAM', the width of the
histogram bin. If None it will be obtained from the Py-ART
config file
quantiles: list of float or None
If the plot type is 'QUANTILES', the list of quantiles to
compute. If None a default list of quantiles will be
computed
vmin, vmax: float or None
The minimum and maximum values of the color scale. If None
the scale is going to be set according to the Py-ART
config file
'PPI_MAP': Plots a PPI image over a map. The map resolution and the
type of maps used are defined in the variables 'mapres' and 'maps'
in 'ppiMapImageConfig' in the loc config file.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
anglenr: float
The elevation angle number
vmin, vmax : float or None
Min and Max values of the color scale. If None the values
are taken from the Py-ART config file
'PPIMAP_ROI_OVERPLOT': Over plots a polygon delimiting a region of
interest on a PPI map. The map resolution and the
type of maps used are defined in the variables 'mapres' and 'maps'
in 'ppiMapImageConfig' in the loc config file.
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
anglenr: float
The elevation angle number
'PROFILE_STATS': Computes and plots a vertical profile statistics.
The statistics are saved in a csv file
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
heightResolution: float
The height resolution of the profile [m]. Default 100.
heightMin, heightMax: float or None
The minimum and maximum altitude of the profile [m MSL].
If None the values will be obtained from the minimum and
maximum gate altitude.
quantity: str
The type of statistics to plot. Can be 'quantiles',
'mode', 'reqgression_mean' or 'mean'.
quantiles: list of floats
If quantity type is 'quantiles' the list of quantiles to
compute. Default 25., 50., 75.
nvalid_min: int
The minimum number of valid points to consider the
statistic valid. Default 4
make_linear: Bool
If true the data is converted from log to linear before
computing the stats
include_nans: Bool
If true NaN values are included in the statistics
fixed_span: Bool
If true the profile plot has a fix X-axis
vmin, vmax: float or None
If fixed_span is set, the minimum and maximum values of
the X-axis. If None, they are obtained from the Py-ART
config file
'PSEUDOPPI_CONTOUR': Plots a pseudo-PPI countour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
angle: float
The elevation angle at which compute the PPI
EleTol: float
The tolerance between the actual radar elevation angle and
the nominal pseudo-PPI elevation angle.
'PSEUDOPPI_CONTOUR_OVERPLOT': Plots a pseudo-PPI of a field with
another field over-plotted as a contour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
angle: float
The elevation angle at which compute the PPI
EleTol: float
The tolerance between the actual radar elevation angle and
the nominal pseudo-PPI elevation angle.
'PSEUDOPPI_IMAGE': Plots a pseudo-PPI image. It can also plot the
histogram and the quantiles of the data in the pseudo-PPI.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
angle: float
The elevation angle of the pseudo-PPI
EleTol: float
The tolerance between the actual radar elevation angle and
the nominal pseudo-PPI elevation angle.
plot_type: str
The type of plot to perform. Can be 'PPI', 'QUANTILES' or
'HISTOGRAM'
step: float or None
If the plot type is 'HISTOGRAM', the width of the
histogram bin. If None it will be obtained from the Py-ART
config file
quantiles: list of float or None
If the plot type is 'QUANTILES', the list of quantiles to
compute. If None a default list of quantiles will be
computed
vmin, vmax : float or None
Min and Max values of the color scale. If None the values
are taken from the Py-ART config file
'PSEUDOPPI_MAP': Plots a pseudo-PPI image over a map. The map
resolution and the type of maps used are defined in the variables
'mapres' and 'maps' in 'ppiMapImageConfig' in the loc config file.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
angle: float
The elevation angle of the pseudo-PPI
EleTol: float
The tolerance between the actual radar elevation angle and
the nominal pseudo-PPI elevation angle.
vmin, vmax : float or None
Min and Max values of the color scale. If None the values
are taken from the Py-ART config file
'PSEUDORHI_CONTOUR': Plots a pseudo-RHI countour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
angle: float
The azimuth angle at which to compute the RPI
AziTol: float
The tolerance between the actual radar azimuth angle and
the nominal pseudo-RHI azimuth angle.
'PSEUDORHI_CONTOUR_OVERPLOT': Plots a pseudo-RHI of a field with
another field over-plotted as a contour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
angle: float
The azimuth angle at which to compute the RPI
AziTol: float
The tolerance between the actual radar azimuth angle and
the nominal pseudo-RHI azimuth angle.
'PSEUDORHI_IMAGE': Plots a pseudo-RHI image. It can also plot the
histogram and the quantiles of the data in the pseudo-RHI.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
angle: float
The azimuth angle at which to compute the RPI
AziTol: float
The tolerance between the actual radar azimuth angle and
the nominal pseudo-RHI azimuth angle.
plot_type: str
The type of plot to perform. Can be 'RHI', 'QUANTILES' or
'HISTOGRAM'
step: float or None
If the plot type is 'HISTOGRAM', the width of the
histogram bin. If None it will be obtained from the Py-ART
config file
quantiles: list of float or None
If the plot type is 'QUANTILES', the list of quantiles to
compute. If None a default list of quantiles will be
computed
vmin, vmax : float or None
Min and Max values of the color scale. If None the values
are taken from the Py-ART config file
'QUANTILES': Plots and writes the quantiles of a radar volume
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
quantiles: list of floats or None
the list of quantiles to compute. If None a default list
of quantiles will be computed.
write_data: Bool
If True the computed data will be also written in a csv
file
fixed_span: Bool
If true the quantile plot has a fix Y-axis
vmin, vmax: float or None
If fixed_span is set, the minimum and maximum values of
the Y-axis. If None, they are obtained from the Py-ART
config file
'RHI_CONTOUR': Plots an RHI countour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
anglenr: int
The azimuth angle number
'RHI_CONTOUR_OVERPLOT': Plots an RHI of a field with another field
over-plotted as a contour plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
contour_values: list of floats or None
The list of contour values to plot. If None the contour
values are going to be obtained from the Py-ART config
file either with the dictionary key 'contour_values' or
from the minimum and maximum values of the field with an
assumed division of 10 levels.
anglenr: int
The azimuth angle number
'RHI_IMAGE': Plots an RHI image. It can also plot the
histogram and the quantiles of the data in the RHI.
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
anglenr: int
The azimuth angle number
plot_type: str
The type of plot to perform. Can be 'RHI', 'QUANTILES' or
'HISTOGRAM'
step: float or None
If the plot type is 'HISTOGRAM', the width of the
histogram bin. If None it will be obtained from the Py-ART
config file
quantiles: list of float or None
If the plot type is 'QUANTILES', the list of quantiles to
compute. If None a default list of quantiles will be
computed
vmin, vmax: float or None
The minimum and maximum values of the color scale. If None
the scale is going to be set according to the Py-ART
config file
'RHI_PROFILE': Computes and plots a vertical profile statistics out of
an RHI.
The statistics are saved in a csv file
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
rangeStart, rangeStop: float
The range start and stop of the data to extract from the
RHI to compute the statistics [m]. Default 0., 25000.
heightResolution: float
The height resolution of the profile [m]. Default 100.
heightMin, heightMax: float or None
The minimum and maximum altitude of the profile [m MSL].
If None the values will be obtained from the minimum and
maximum gate altitude.
quantity: str
The type of statistics to plot. Can be 'quantiles',
'mode', 'reqgression_mean' or 'mean'.
quantiles: list of floats
If quantity type is 'quantiles' the list of quantiles to
compute. Default 25., 50., 75.
nvalid_min: int
The minimum number of valid points to consider the
statistic valid. Default 4
make_linear: Bool
If true the data is converted from log to linear before
computing the stats
include_nans: Bool
If true NaN values are included in the statistics
fixed_span: Bool
If true the profile plot has a fix X-axis
vmin, vmax: float or None
If fixed_span is set, the minimum and maximum values of
the X-axis. If None, they are obtained from the Py-ART
config file
'SAMPLES_HISTOGRAM': Computes a histogram of the number of samples used
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
step: float or None
the data quantization step. If none it will be obtained
from the Py-ART configuration file
write_data: Bool
If true the histogram data is written in a csv file
'SAVEALL': Saves radar volume data including all or a list of user-
defined fields in a C/F radial or ODIM file
User defined parameters:
file_type: str
The type of file used to save the data. Can be 'nc' or
'h5'. Default 'nc'
datatypes: list of str or None
The list of data types to save. If it is None, all fields
in the radar object will be saved
physical: Bool
If True the data will be saved in physical units (floats).
Otherwise it will be quantized and saved as binary
compression: str
For ODIM file formats, the type of compression. Can be any
of the allowed compression types for hdf5 files. Default
gzip
compression_opts: any
The compression options allowed by the hdf5. Depends on
the type of compression. Default 6 (The gzip compression
level).
'SAVEALL_VOL' : Same as before but can be used in a mixed GRID/VOL
dataset, as there is no ambiguity with SAVEALL for VOL datasets
'SAVESTATE': Saves the last processed data in a file. Used for real-
time data processing
'SAVEPSEUDORHI': Saves one field of a pseudo-RHI computed from a
volume scan in C/F radial or ODIM file
User defined parameters:
file_type: str
The type of file used to save the data. Can be 'nc' or
'h5'. Default 'nc'
physical: Bool
If True the data will be saved in physical units (floats).
Otherwise it will be quantized and saved as binary
compression: str
For ODIM file formats, the type of compression. Can be any
of the allowed compression types for hdf5 files. Default
gzip
compression_opts: any
The compression options allowed by the hdf5. Depends on
the type of compression. Default 6 (The gzip compression
level).
'SAVEPSEUDOPPI': Saves one field of a pseudo-PPI computed from a
volume scan in C/F radial or ODIM file
User defined parameters:
file_type: str
The type of file used to save the data. Can be 'nc' or
'h5'. Default 'nc'
physical: Bool
If True the data will be saved in physical units (floats).
Otherwise it will be quantized and saved as binary
compression: str
For ODIM file formats, the type of compression. Can be any
of the allowed compression types for hdf5 files. Default
gzip
compression_opts: any
The compression options allowed by the hdf5. Depends on
the type of compression. Default 6 (The gzip compression
level).
'SAVEVOL': Saves one field of a radar volume data in a C/F radial or
ODIM file
User defined parameters:
file_type: str
The type of file used to save the data. Can be 'nc' or
'h5'. Default 'nc'
physical: Bool
If True the data will be saved in physical units (floats).
Otherwise it will be quantized and saved as binary.
Default True
compression: str
For ODIM file formats, the type of compression. Can be any
of the allowed compression types for hdf5 files. Default
gzip
compression_opts: any
The compression options allowed by the hdf5. Depends on
the type of compression. Default 6 (The gzip compression
level).
'SAVEVOL_CSV': Saves one field of a radar volume data in a CSV file
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
ignore_masked: bool
If True masked values will not be saved. Default False
'SAVEVOL_KML': Saves one field of a radar volume data in a KML file
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
ignore_masked: bool
If True masked values will not be saved. Default False
azi_res : float or None
azimuthal resolution of the range bins. If None the
antenna beamwidth is going to be used to determine the
resolution
'SAVEVOL_VOL' : Same as before but can be used in a mixed GRID/VOL
dataset, as there is no ambiguity with SAVEVOL for GRID datasets
'SAVE_FIXED_ANGLE': Saves the position of the first fix angle in a csv file
User defined parameters:
voltype: str or list of str
Name of the pyrad variable to use, it must be either a voltype available in the dataset
or "RGB", which will make a RGB plot of Zh, Zdr and RhoHV (if they are available)
'SELFCONSISTENCY': Plots a ZDR versus KDP/ZH histogram of data.
User defined parameters:
retrieve_relation : bool
If True plots also the retrieved relationship. Default
True
plot_theoretical : bool
If True plots also the theoretical relationship. Default
True
normalize : bool
If True the occurrence density of ZK/KDP for each ZDR bin
is going to be represented. Otherwise it will show the
number of gates at each bin. Default True
'SELFCONSISTENCY2': Plots a ZH measured versus ZH inferred from a
self-consistency relation histogram of data.
User defined parameters:
normalize : bool
If True the occurrence density of ZK/KDP for each ZDR bin
is going to be represented. Otherwise it will show the
number of gates at each bin. Default True
'TIME_RANGE': Plots a time-range/azimuth/elevation plot
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
anglenr: float
The number of the fixed angle to plot
vmin, vmax: float or None
The minimum and maximum values of the color scale. If None
the scale is going to be set according to the Py-ART
config file
'VOL_TS': Writes and plots a value corresponding to a time series.
Meant primarily for writing and plotting the results of the
SELFCONSISTENCY2 algorithm
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
ref_value: float
The reference value. Default 0
sort_by_date: Bool
If true when reading the csv file containing the
statistics the data is sorted by date. Default False
rewrite: Bool
If true the csv file containing the statistics is
rewritten
add_data_in_fname: Bool
If true and the data used is cumulative the year is
written in the csv file name and the plot file name
npoints_min: int
Minimum number of points to use the data point in the
plotting and to send an alarm. Default 0
vmin, vmax: float or None
Limits of the Y-axis (data value). If None the limits
are obtained from the Py-ART config file
alarm: Bool
If true an alarm is sent
tol_abs: float
Margin of tolerance from the reference value. If the
current value is above this margin an alarm is sent. If
the margin is not specified it is not possible to send any
alarm
tol_trend: float
Margin of tolerance from the reference value. If the
trend of the last X events is above this margin an alarm
is sent. If the margin is not specified it is not possible
to send any alarm
nevents_min: int
Minimum number of events with sufficient points to send an
alarm related to the trend. If not specified it is not
possible to send any alarm
sender: str
The mail of the alarm sender. If not specified it is not
possible to send any alarm
receiver_list: list of str
The list of emails of the people that will receive the
alarm.. If not specified it is not possible to send any
alarm
'WIND_PROFILE': Plots vertical profile of wind data (U, V, W
components and wind velocity and direction) out of a radar
volume containing the retrieved U,V and W components of the wind,
the standard deviation of the retrieval and the velocity
difference between the estimated radial velocity (assuming the
wind to be uniform) and the actual measured radial velocity.
User defined parameters:
heightResolution: float
The height resolution of the profile [m]. Default 100.
heightMin, heightMax: float or None
The minimum and maximum altitude of the profile [m MSL].
If None the values will be obtained from the minimum and
maximum gate altitude.
min_ele: float
The minimum elevation to be used in the computation of the
vertical velocities. Default 5.
max_ele: float
The maximum elevation to be used in the computation of the
horizontal velocities. Default 85.
fixed_span: Bool
If true the profile plot has a fix X-axis
vmin, vmax: float or None
If fixed_span is set, the minimum and maximum values of
the X-axis. If None, they are obtained from the span of
the U component defined in the Py-ART config file
'WRITE_STATS': write statistics about the statistics of a field within a certain
sector (mean, median, stddev, nsamples, nvalid) and optionally min, max and
additional quantiles
User defined parameters:
voltype: str
Name of the pyrad variable to use, it must be a voltype available in the dataset
ele_min: float
Max elevation angle defining the sector [deg].
Default 0.
ele_max: float
Max elevation angle defining the sector [deg].
Default 90.
azi_min: float
Min azimuth angle defining the sector [deg].
Default 0.
azi_max: float
Max azimuth angle defining the sector [deg].
Default 360.
rmin: float
Min range defining the sector [km].
Default 0.
rmax: float
Max range defining the sector [km].
Default 50.
write_min_max: Bool
If true will also write min and max values within sector
quantiles: list of int
Additional quantiles (apart from median) to compute within the sector and
write to file
Parameters
----------
dataset : dict
dictionary with key radar_out containing a radar object
prdcfg : dictionary of dictionaries
product configuration dictionary of dictionaries
Returns
-------
The list of created fields or None
"""
dssavedir = prdcfg["dsname"]
if "dssavename" in prdcfg:
dssavedir = prdcfg["dssavename"]
prdsavedir = prdcfg["prdname"]
if "prdsavedir" in prdcfg:
prdsavedir = prdcfg["prdsavedir"]
if prdcfg["type"] == "ANTENNA_POS":
dpi = prdcfg.get("dpi", 72)
datatype = prdcfg.get("datatype", "AZ")
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ts",
prdcfg["dstype"],
"ANTENNA_POS",
prdcfg["imgformat"],
prdcfginfo=datatype,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
if datatype == "EL":
value = dataset["radar_out"].elevation["data"]
labely = "antenna elevation (deg)"
elif datatype == "AZ":
value = dataset["radar_out"].azimuth["data"]
labely = "antenna azimuth (deg)"
titl = (
f"antenna position " f'{prdcfg["timeinfo"].strftime("%Y-%m-%d %H:%M:%S")}'
)
ray_time = pyart.util.datetimes_from_radar(
dataset["radar_out"],
only_use_cftime_datetimes=False,
only_use_python_datetimes=True,
)
ind = np.argsort(ray_time)
ray_time = ray_time[ind]
value = value[ind]
plot_timeseries(
ray_time,
[value],
fname_list,
labelx="Time UTC",
labely=labely,
title=titl,
dpi=dpi,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PPI_IMAGE":
fields = dataset["radar_out"].fields
field_name = get_fieldname_pyart(prdcfg["voltype"])
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
el_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
el = el_vec[prdcfg["anglenr"]]
ind_el = np.where(dataset["radar_out"].fixed_angle["data"] == el)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
step = prdcfg.get("step", None)
quantiles = prdcfg.get("quantiles", None)
plot_type = prdcfg.get("plot_type", "PPI")
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
write_data = prdcfg.get("write_data", 0)
fname_hist = None
if write_data:
fname_hist = (
savedir
+ make_filename(
"ppi",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
["csv"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
)
fname_list = plot_ppi(
dataset["radar_out"],
field_name,
ind_el,
prdcfg,
fname_list,
plot_type=plot_type,
vmin=vmin,
vmax=vmax,
step=step,
quantiles=quantiles,
fname_hist=fname_hist,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDOPPI_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
plot_type = prdcfg.get("plot_type", "PPI")
step = prdcfg.get("step", None)
quantiles = prdcfg.get("quantiles", None)
ele_tol = prdcfg.get("EleTol", 1.0)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
try:
xsect = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=ele_tol
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_ppi(
xsect,
field_name,
0,
prdcfg,
fname_list,
plot_type=plot_type,
vmin=vmin,
vmax=vmax,
step=step,
quantiles=quantiles,
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
"No data found at elevation "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "PPI_MAP":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
el_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
el = el_vec[prdcfg["anglenr"]]
ind_el = np.where(dataset["radar_out"].fixed_angle["data"] == el)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi_map",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_ppi_map(
dataset["radar_out"],
field_name,
ind_el,
prdcfg,
fname_list,
vmin=vmin,
vmax=vmax,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PPI_CONTOUR_OVERPLOT":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_name = get_fieldname_pyart(prdcfg["contourtype"])
if contour_name not in dataset["radar_out"].fields:
warn(
"Contour type "
+ contour_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
el_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
el = el_vec[prdcfg["anglenr"]]
ind_el = np.where(dataset["radar_out"].fixed_angle["data"] == el)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
prdcfg["voltype"] + "-" + prdcfg["contourtype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_title(dataset["radar_out"], field_name, ind_el)
+ " - "
+ pyart.graph.common.generate_field_name(dataset["radar_out"], contour_name)
)
fig, ax = plot_ppi(
dataset["radar_out"],
field_name,
ind_el,
prdcfg,
fname_list,
titl=titl,
save_fig=False,
)
fname_list = plot_ppi_contour(
dataset["radar_out"],
contour_name,
ind_el,
prdcfg,
fname_list,
contour_values=contour_values,
ax=ax,
fig=fig,
save_fig=True,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PPIMAP_ROI_OVERPLOT":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
if "roi_dict" in dataset:
roi_dict = dataset["roi_dict"]
elif "roi_file" in prdcfg:
traj = Trajectory(prdcfg["roi_file"])
roi_dict = {"lon": traj.wgs84_lon_deg, "lat": traj.wgs84_lat_deg}
else:
warn("unable to plot ROI over PPI MAP. ROI data not found")
return None
el_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
el = el_vec[prdcfg["anglenr"]]
ind_el = np.where(dataset["radar_out"].fixed_angle["data"] == el)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi_map",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fig, ax, _ = plot_ppi_map(
dataset["radar_out"], field_name, ind_el, prdcfg, fname_list, save_fig=False
)
fname_list = plot_roi_contour(
roi_dict, prdcfg, fname_list, ax=ax, fig=fig, save_fig=True
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDOPPI_CONTOUR_OVERPLOT":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_name = get_fieldname_pyart(prdcfg["contourtype"])
if contour_name not in dataset["radar_out"].fields:
warn(
"Contour type "
+ contour_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
try:
xsect = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=prdcfg["EleTol"]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
prdcfg["voltype"] + "-" + prdcfg["contourtype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_title(xsect, field_name, 0)
+ " - "
+ pyart.graph.common.generate_field_name(xsect, contour_name)
)
fig, ax = plot_ppi(
xsect, field_name, 0, prdcfg, fname_list, titl=titl, save_fig=False
)
fname_list = plot_ppi_contour(
xsect,
contour_name,
0,
prdcfg,
fname_list,
contour_values=contour_values,
ax=ax,
fig=fig,
save_fig=True,
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
"No data found at elevation "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "PPI_CONTOUR":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
el_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
el = el_vec[prdcfg["anglenr"]]
ind_el = np.where(dataset["radar_out"].fixed_angle["data"] == el)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(el),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_ppi_contour(
dataset["radar_out"],
field_name,
ind_el,
prdcfg,
fname_list,
contour_values=contour_values,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDOPPI_CONTOUR":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
try:
xsect = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=prdcfg["EleTol"]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_ppi_contour(
xsect, field_name, 0, prdcfg, fname_list, contour_values=contour_values
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
"No data found at elevation "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "RHI_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
az_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
az = az_vec[prdcfg["anglenr"]]
ind_az = np.where(dataset["radar_out"].fixed_angle["data"] == az)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(az),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
step = prdcfg.get("step", None)
quantiles = prdcfg.get("quantiles", None)
plot_type = prdcfg.get("plot_type", "RHI")
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
plot_rhi(
dataset["radar_out"],
field_name,
ind_az,
prdcfg,
fname_list,
plot_type=plot_type,
step=step,
vmin=vmin,
vmax=vmax,
quantiles=quantiles,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDORHI_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
plot_type = prdcfg.get("plot_type", "RHI")
step = prdcfg.get("step", None)
quantiles = prdcfg.get("quantiles", None)
azi_tol = prdcfg.get("AziTol", 1.0)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
try:
xsect = pyart.util.cross_section_ppi(
dataset["radar_out"], [prdcfg["angle"]], az_tol=azi_tol
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
(
"RGB"
if isinstance(prdcfg["voltype"], (tuple, list))
else prdcfg["voltype"]
),
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi(
xsect,
field_name,
0,
prdcfg,
fname_list,
vmin=vmin,
vmax=vmax,
plot_type=plot_type,
step=step,
quantiles=quantiles,
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
" No data found at azimuth "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "RHI_CONTOUR_OVERPLOT":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_name = get_fieldname_pyart(prdcfg["contourtype"])
if contour_name not in dataset["radar_out"].fields:
warn(
"Contour type "
+ contour_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
az_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
az = az_vec[prdcfg["anglenr"]]
ind_az = np.where(dataset["radar_out"].fixed_angle["data"] == az)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
prdcfg["voltype"] + "-" + prdcfg["contourtype"],
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(az),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_title(dataset["radar_out"], field_name, ind_az)
+ " - "
+ pyart.graph.common.generate_field_name(dataset["radar_out"], contour_name)
)
fig, ax = plot_rhi(
dataset["radar_out"],
field_name,
ind_az,
prdcfg,
fname_list,
titl=titl,
save_fig=False,
)
fname_list = plot_rhi_contour(
dataset["radar_out"],
contour_name,
ind_az,
prdcfg,
fname_list,
contour_values=contour_values,
ax=ax,
fig=fig,
save_fig=True,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDORHI_CONTOUR_OVERPLOT":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_name = get_fieldname_pyart(prdcfg["contourtype"])
if contour_name not in dataset["radar_out"].fields:
warn(
"Contour type "
+ contour_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
try:
xsect = pyart.util.cross_section_ppi(
dataset["radar_out"], [prdcfg["angle"]], az_tol=prdcfg["AziTol"]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
prdcfg["voltype"] + "-" + prdcfg["contourtype"],
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_title(xsect, field_name, 0)
+ " - "
+ pyart.graph.common.generate_field_name(xsect, contour_name)
)
fig, ax = plot_rhi(
xsect, field_name, 0, prdcfg, fname_list, titl=titl, save_fig=False
)
fname_list = plot_rhi_contour(
xsect,
contour_name,
0,
prdcfg,
fname_list,
contour_values=contour_values,
ax=ax,
fig=fig,
save_fig=True,
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
" No data found at azimuth "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "RHI_CONTOUR":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
az_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
az = az_vec[prdcfg["anglenr"]]
ind_az = np.where(dataset["radar_out"].fixed_angle["data"] == az)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(az),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_rhi_contour(
dataset["radar_out"],
field_name,
ind_az,
prdcfg,
fname_list,
contour_values=contour_values,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PSEUDORHI_CONTOUR":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
contour_values = prdcfg.get("contour_values", None)
try:
xsect = pyart.util.cross_section_ppi(
dataset["radar_out"], [prdcfg["angle"]], az_tol=prdcfg["AziTol"]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"rhi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="az" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_rhi_contour(
xsect, field_name, 0, prdcfg, fname_list, contour_values=contour_values
)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
" No data found at azimuth "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "RHI_PROFILE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# user defined parameters
rangeStart = prdcfg.get("rangeStart", 0.0)
rangeStop = prdcfg.get("rangeStop", 25000.0)
heightResolution = prdcfg.get("heightResolution", 500.0)
hmin_user = prdcfg.get("heightMin", None)
hmax_user = prdcfg.get("heightMax", None)
quantity = prdcfg.get("quantity", "quantiles")
quantiles = prdcfg.get("quantiles", np.array([25.0, 50.0, 75.0]))
nvalid_min = prdcfg.get("nvalid_min", 4)
make_linear = prdcfg.get("make_linear", 0)
include_nans = prdcfg.get("include_nans", 0)
fixed_span = prdcfg.get("fixed_span", 1)
vmin = None
vmax = None
if fixed_span:
vmin, vmax = pyart.config.get_field_limits(field_name)
if "vmin" in prdcfg:
vmin = prdcfg["vmin"]
if "vmax" in prdcfg:
vmax = prdcfg["vmax"]
# create new radar object with only data for the given rhi and range
az_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
az = az_vec[prdcfg["anglenr"]]
ind_az = np.where(dataset["radar_out"].fixed_angle["data"] == az)[0][0]
new_dataset = dataset["radar_out"].extract_sweeps([ind_az])
field = new_dataset.fields[field_name]
rng_mask = np.logical_and(
new_dataset.range["data"] >= rangeStart,
new_dataset.range["data"] <= rangeStop,
)
field["data"] = field["data"][:, rng_mask]
new_dataset.range["data"] = new_dataset.range["data"][rng_mask]
new_dataset.ngates = len(new_dataset.range["data"])
new_dataset.init_gate_x_y_z()
new_dataset.init_gate_longitude_latitude()
new_dataset.init_gate_altitude()
new_dataset.fields = dict()
new_dataset.add_field(field_name, field)
# compute quantities
if hmin_user is None:
minheight = (
round(
np.min(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
- heightResolution
)
else:
minheight = hmin_user
if hmax_user is None:
maxheight = (
round(
np.max(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
+ heightResolution
)
else:
maxheight = hmax_user
nlevels = int((maxheight - minheight) / heightResolution)
h_vec = (
minheight + np.arange(nlevels) * heightResolution + heightResolution / 2.0
)
vals, val_valid = compute_profile_stats(
field["data"],
new_dataset.gate_altitude["data"],
h_vec,
heightResolution,
quantity=quantity,
quantiles=quantiles / 100.0,
nvalid_min=nvalid_min,
make_linear=make_linear,
include_nans=include_nans,
)
# plot data
if quantity == "mean":
data = [vals[:, 0], vals[:, 1], vals[:, 2]]
labels = ["Mean", "Min", "Max"]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
elif quantity == "mode":
data = [vals[:, 0], vals[:, 2], vals[:, 4]]
labels = ["Mode", "2nd most common", "3rd most common"]
colors = ["b", "k", "r"]
linestyles = ["-", "--", "--"]
else:
data = [vals[:, 1], vals[:, 0], vals[:, 2]]
labels = [
str(quantiles[1]) + "-percentile",
str(quantiles[0]) + "-percentile",
str(quantiles[2]) + "-percentile",
]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
labelx = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "az" + "{:.1f}".format(az) + "hres" + str(int(heightResolution))
fname_list = make_filename(
"rhi_profile",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
)
print("----- save to " + " ".join(fname_list))
fname = make_filename(
"rhi_profile",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
if quantity == "mode":
data.append(vals[:, 1])
labels.append("% points mode")
data.append(vals[:, 3])
labels.append("% points 2nd most common")
data.append(vals[:, 5])
labels.append("% points 3rd most common")
sector = {"rmin": rangeStart, "rmax": rangeStop, "az": az}
write_rhi_profile(
h_vec,
data,
val_valid,
labels,
fname,
datatype=labelx,
timeinfo=prdcfg["timeinfo"],
sector=sector,
)
print("----- save to " + fname)
# TODO: add Cartesian interpolation option
return fname
if prdcfg["type"] == "PROFILE_STATS":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# mask unclassified data
field = deepcopy(dataset["radar_out"].fields[field_name]["data"])
if prdcfg["voltype"] in ("hydro", "hydroc"):
field = np.ma.masked_equal(field, 1)
# user defined parameters
heightResolution = prdcfg.get("heightResolution", 100.0)
hmin_user = prdcfg.get("heightMin", None)
hmax_user = prdcfg.get("heightMax", None)
quantity = prdcfg.get("quantity", "quantiles")
quantiles = prdcfg.get("quantiles", np.array([25.0, 50.0, 75.0]))
nvalid_min = prdcfg.get("nvalid_min", 4)
make_linear = prdcfg.get("make_linear", 0)
include_nans = prdcfg.get("include_nans", 0)
fixed_span = prdcfg.get("fixed_span", 1)
vmin = None
vmax = None
if fixed_span:
vmin, vmax = pyart.config.get_field_limits(field_name)
if "vmin" in prdcfg:
vmin = prdcfg["vmin"]
if "vmax" in prdcfg:
vmax = prdcfg["vmax"]
# compute quantities
if hmin_user is None:
minheight = (
round(
np.min(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
- heightResolution
)
else:
minheight = hmin_user
if hmax_user is None:
maxheight = (
round(
np.max(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
+ heightResolution
)
else:
maxheight = hmax_user
nlevels = int((maxheight - minheight) / heightResolution)
h_vec = (
minheight + np.arange(nlevels) * heightResolution + heightResolution / 2.0
)
vals, val_valid = compute_profile_stats(
field,
dataset["radar_out"].gate_altitude["data"],
h_vec,
heightResolution,
quantity=quantity,
quantiles=quantiles / 100.0,
nvalid_min=nvalid_min,
make_linear=make_linear,
include_nans=include_nans,
)
# plot data
if quantity == "mean":
data = [vals[:, 0], vals[:, 1], vals[:, 2]]
labels = ["Mean", "Min", "Max"]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
elif quantity == "mode":
data = [vals[:, 0], vals[:, 2], vals[:, 4]]
labels = ["Mode", "2nd most common", "3rd most common"]
colors = ["b", "k", "r"]
linestyles = ["-", "--", "--"]
else:
data = [vals[:, 1], vals[:, 0], vals[:, 2]]
labels = [
str(quantiles[1]) + "-percentile",
str(quantiles[0]) + "-percentile",
str(quantiles[2]) + "-percentile",
]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
labelx = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"rhi_profile",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=vmin,
vmax=vmax,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
fname = make_filename(
"rhi_profile",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
if quantity == "mode":
data.append(vals[:, 1])
labels.append("% points mode")
data.append(vals[:, 3])
labels.append("% points 2nd most common")
data.append(vals[:, 5])
labels.append("% points 3rd most common")
write_rhi_profile(
h_vec,
data,
val_valid,
labels,
fname,
datatype=labelx,
timeinfo=prdcfg["timeinfo"],
)
print("----- save to " + fname)
# TODO: add Cartesian interpolation option
return fname
if prdcfg["type"] == "WIND_PROFILE":
# user defined parameters
heightResolution = prdcfg.get("heightResolution", 100.0)
hmin_user = prdcfg.get("heightMin", None)
hmax_user = prdcfg.get("heightMax", None)
min_ele = prdcfg.get("min_ele", 5.0)
max_ele = prdcfg.get("max_ele", 85.0)
fixed_span = prdcfg.get("fixed_span", 1)
vmin = None
vmax = None
if fixed_span:
vmin, vmax = pyart.config.get_field_limits("eastward_wind_component")
if "vmin" in prdcfg:
vmin = prdcfg["vmin"]
if "vmax" in prdcfg:
vmax = prdcfg["vmax"]
u_vel = deepcopy(dataset["radar_out"].fields["eastward_wind_component"]["data"])
v_vel = deepcopy(
dataset["radar_out"].fields["northward_wind_component"]["data"]
)
w_vel = deepcopy(dataset["radar_out"].fields["vertical_wind_component"]["data"])
std_vel = deepcopy(
dataset["radar_out"].fields["retrieved_velocity_std"]["data"]
)
diff_vel = deepcopy(dataset["radar_out"].fields["velocity_difference"]["data"])
# remove azimuth information
u_vel_aux = np.ma.masked_all(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=float
)
v_vel_aux = np.ma.masked_all(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=float
)
w_vel_aux = np.ma.masked_all(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=float
)
std_vel_aux = np.ma.masked_all(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=float
)
ngates_aux = np.zeros(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=int
)
gate_altitude_aux = np.empty(
(dataset["radar_out"].nsweeps, dataset["radar_out"].ngates), dtype=float
)
for ind_sweep in range(dataset["radar_out"].nsweeps):
ind_start = dataset["radar_out"].sweep_start_ray_index["data"][ind_sweep]
ind_end = dataset["radar_out"].sweep_end_ray_index["data"][ind_sweep]
for ind_rng in range(dataset["radar_out"].ngates):
u_vel_aux[ind_sweep, ind_rng] = u_vel[ind_start, ind_rng]
v_vel_aux[ind_sweep, ind_rng] = v_vel[ind_start, ind_rng]
w_vel_aux[ind_sweep, ind_rng] = w_vel[ind_start, ind_rng]
std_vel_aux[ind_sweep, ind_rng] = std_vel[ind_start, ind_rng]
gate_altitude_aux[ind_sweep, ind_rng] = dataset[
"radar_out"
].gate_altitude["data"][ind_start, ind_rng]
ngates_aux[ind_sweep, ind_rng] = (
diff_vel[ind_start:ind_end, ind_rng].compressed().size
)
# exclude low elevations in the computation of vertical velocities
std_w_vel_aux = deepcopy(std_vel_aux)
ngates_w_aux = deepcopy(ngates_aux)
ind = np.where(dataset["radar_out"].fixed_angle["data"] < min_ele)[0]
if ind.size > 0:
w_vel_aux[ind, :] = np.ma.masked
std_w_vel_aux[ind, :] = np.ma.masked
ngates_w_aux[ind, :] = 0
# exclude hig elevations in the computation of horizontal velocities
ind = np.where(dataset["radar_out"].fixed_angle["data"] > max_ele)[0]
if ind.size > 0:
u_vel_aux[ind, :] = np.ma.masked
v_vel_aux[ind, :] = np.ma.masked
std_vel_aux[ind, :] = np.ma.masked
ngates_aux[ind, :] = 0
# compute quantities
if hmin_user is None:
minheight = (
round(
np.min(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
- heightResolution
)
else:
minheight = hmin_user
if hmax_user is None:
maxheight = (
round(
np.max(dataset["radar_out"].gate_altitude["data"])
/ heightResolution
)
* heightResolution
+ heightResolution
)
else:
maxheight = hmax_user
nlevels = int((maxheight - minheight) / heightResolution)
h_vec = (
minheight + np.arange(nlevels) * heightResolution + heightResolution / 2.0
)
u_vals, val_valid = compute_profile_stats(
u_vel_aux,
gate_altitude_aux,
h_vec,
heightResolution,
quantity="regression_mean",
std_field=std_vel_aux,
np_field=ngates_aux,
)
v_vals, val_valid = compute_profile_stats(
v_vel_aux,
gate_altitude_aux,
h_vec,
heightResolution,
quantity="regression_mean",
std_field=std_vel_aux,
np_field=ngates_aux,
)
w_vals, w_val_valid = compute_profile_stats(
w_vel_aux,
gate_altitude_aux,
h_vec,
heightResolution,
quantity="regression_mean",
std_field=std_w_vel_aux,
np_field=ngates_w_aux,
)
# plot u wind data
u_data = [
u_vals[:, 0],
u_vals[:, 0] + u_vals[:, 1],
u_vals[:, 0] - u_vals[:, 1],
]
labels = ["Regression mean", "+std", "-std"]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
labelx = get_colobar_label(
dataset["radar_out"].fields["eastward_wind_component"],
"eastward_wind_component",
)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(
dataset["radar_out"].fields["eastward_wind_component"],
"eastward_wind_component",
)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"wind_profile",
prdcfg["dstype"],
"wind_vel_h_u",
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
u_data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=vmin,
vmax=vmax,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
# plot v wind data
v_data = [
v_vals[:, 0],
v_vals[:, 0] + v_vals[:, 1],
v_vals[:, 0] - v_vals[:, 1],
]
labels = ["Regression mean", "+std", "-std"]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
labelx = get_colobar_label(
dataset["radar_out"].fields["northward_wind_component"],
"northward_wind_component",
)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(
dataset["radar_out"].fields["northward_wind_component"],
"northward_wind_component",
)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"wind_profile",
prdcfg["dstype"],
"wind_vel_h_v",
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
v_data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=vmin,
vmax=vmax,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
# plot vertical wind data
w_data = [
w_vals[:, 0],
w_vals[:, 0] + w_vals[:, 1],
w_vals[:, 0] - w_vals[:, 1],
]
labels = ["Regression mean", "+std", "-std"]
colors = ["b", "k", "k"]
linestyles = ["-", "--", "--"]
labelx = get_colobar_label(
dataset["radar_out"].fields["vertical_wind_component"],
"vertical_wind_component",
)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(
dataset["radar_out"].fields["vertical_wind_component"],
"vertical_wind_component",
)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"wind_profile",
prdcfg["dstype"],
"wind_vel_v",
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
w_data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=vmin,
vmax=vmax,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
# plot horizontal wind magnitude
mag = np.ma.sqrt(
np.ma.power(u_vals[:, 0], 2.0) + np.ma.power(v_vals[:, 0], 2.0)
)
mag_data = [mag]
labels = ["Regression mean"]
colors = ["b"]
linestyles = ["-"]
field_dict = pyart.config.get_metadata("wind_speed")
labelx = get_colobar_label(field_dict, "wind_speed")
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(field_dict, "wind_speed")
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"wind_profile",
prdcfg["dstype"],
"WIND_SPEED",
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
mag_data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=vmin,
vmax=vmax,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
# plot horizontal wind direction
wind_dir = (
90.0
- np.ma.arctan2(u_vals[:, 0] / mag, v_vals[:, 0] / mag) * 180.0 / np.pi
+ 180.0
)
wind_dir[wind_dir >= 360.0] = wind_dir[wind_dir >= 360.0] - 360.0
dir_data = [wind_dir]
labels = ["Regression mean"]
colors = ["b"]
linestyles = ["-"]
field_dict = pyart.config.get_metadata("wind_direction")
labelx = get_colobar_label(field_dict, "wind_direction")
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(field_dict, "wind_direction")
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
prdcfginfo = "hres" + str(int(heightResolution))
fname_list = make_filename(
"wind_profile",
prdcfg["dstype"],
"WIND_DIRECTION",
prdcfg["imgformat"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_rhi_profile(
dir_data,
h_vec,
fname_list,
labelx=labelx,
labely="Height (m MSL)",
labels=labels,
title=titl,
colors=colors,
linestyles=linestyles,
vmin=0.0,
vmax=360.0,
hmin=minheight,
hmax=maxheight,
)
print("----- save to " + " ".join(fname_list))
fname = make_filename(
"wind_profile",
prdcfg["dstype"],
"WIND",
["csv"],
prdcfginfo=prdcfginfo,
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
data = [
u_vals[:, 0],
u_vals[:, 1],
np.ma.asarray(val_valid),
v_vals[:, 0],
v_vals[:, 1],
np.ma.asarray(val_valid),
w_vals[:, 0],
w_vals[:, 1],
np.ma.asarray(w_val_valid),
mag,
wind_dir,
]
labels = [
"u_wind",
"std_u_wind",
"np_u_wind",
"v_wind",
"std_v_wind",
"np_v_wind",
"w_wind",
"std_w_wind",
"np_w_wind",
"mag_h_wind",
"dir_h_wind",
]
write_rhi_profile(
h_vec,
data,
val_valid,
labels,
fname,
datatype=None,
timeinfo=prdcfg["timeinfo"],
)
print("----- save to " + fname)
return fname
if prdcfg["type"] == "PSEUDOPPI_MAP":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
try:
xsect = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=prdcfg["EleTol"]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"ppi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="el" + "{:.1f}".format(prdcfg["angle"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_ppi_map(xsect, field_name, 0, prdcfg, fname_list)
print("----- save to " + " ".join(fname_list))
return fname_list
except EnvironmentError:
warn(
"No data found at elevation "
+ str(prdcfg["angle"])
+ ". Skipping product "
+ prdcfg["type"]
)
return None
if prdcfg["type"] == "CAPPI_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"cappi",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="alt" + "{:.1f}".format(prdcfg["altitude"]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_cappi(
dataset["radar_out"], field_name, prdcfg["altitude"], prdcfg, fname_list
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "CROSS_SECTION":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
step = prdcfg.get("step", 1000)
vert_res = prdcfg.get("vert_res", 100)
alt_max = prdcfg.get("alt_max", 10000)
beamwidth = prdcfg.get("beamwidth", None)
if beamwidth is None:
if "RadarBeamwidth" in prdcfg:
beamwidth = prdcfg["RadarBeamwidth"]
else:
warn("Radar beamwidth not provided, assuming 1 deg")
beamwidth = 1
demfile = prdcfg.get("demfile", None)
if demfile is not None:
demproj = None
if "demproj" in prdcfg.keys():
demproj = prdcfg["demproj"]
try:
demproj = int(demproj)
except ValueError:
# demproj is not an EPSG int
pass
fname = prdcfg["dempath"][0] + prdcfg["demfile"]
dem = read_dem(fname, projparams=demproj)
else:
dem = None
# user defined values
ref_pts = []
i = 1
while True:
coord = "coord{:d}".format(i)
coord_pt = []
if coord in prdcfg:
if "lon" in prdcfg[coord]:
coord_pt.append(prdcfg[coord]["lon"])
if "lat" in prdcfg[coord]:
coord_pt.append(prdcfg[coord]["lat"])
ref_pts.append(coord_pt)
else:
break
i += 1
ref_pts_str = "_".join(
["{:2.1f}-{:2.1f}".format(pt[0], pt[1]) for pt in ref_pts]
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"cross_section",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="refpts_" + "{:s}".format(ref_pts_str),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_xsection(
dataset["radar_out"],
field_name,
ref_pts,
step,
vert_res,
alt_max,
beamwidth,
dem,
prdcfg,
fname_list,
vmin=vmin,
vmax=vmax,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "FIXED_RNG_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ str(field_name)
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# User-defined parameters
ang_tol = prdcfg.get("AngTol", 1.0)
azi_res = prdcfg.get("azi_res", None)
ele_res = prdcfg.get("ele_res", None)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
plot_max = prdcfg.get("plot_max", False)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"fixed_rng",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo=("rng" + "{:.1f}".format(dataset["radar_out"].range["data"][0])),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
return plot_fixed_rng(
dataset["radar_out"],
field_name,
prdcfg,
fname_list,
azi_res=azi_res,
ele_res=ele_res,
ang_tol=ang_tol,
vmin=vmin,
vmax=vmax,
plot_max=plot_max,
)
if prdcfg["type"] == "FIXED_RNG_SPAN_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(field in fields for field in names):
warn(
"Field type "
+ str(field_name)
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# User-defined parameters
ang_tol = prdcfg.get("AngTol", 1.0)
azi_res = prdcfg.get("azi_res", None)
ele_res = prdcfg.get("ele_res", None)
stat = prdcfg.get("stat", "max")
plot_type = prdcfg.get("plot_type", "field")
plot_max = prdcfg.get("plot_max", False)
if plot_type not in ("field", "range"):
warn(
f"Invalid plot_type '{plot_type}'. "
"It must be either 'field' or 'range'. "
"Skipping product FIXED_RNG_SPAN_IMAGE."
)
return None
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
stat,
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo=(
"rng"
+ "{:.1f}".format(dataset["radar_out"].range["data"][0])
+ "-"
+ "{:.1f}".format(dataset["radar_out"].range["data"][-1])
),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
output_fname_list = plot_fixed_rng_span(
dataset["radar_out"],
field_name,
prdcfg,
fname_list,
azi_res=azi_res,
ele_res=ele_res,
ang_tol=ang_tol,
stat=stat,
plot_type=plot_type,
plot_max=plot_max,
)
print("----- save to " + " ".join(output_fname_list))
return output_fname_list
if prdcfg["type"] == "PLOT_ALONG_COORD":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
if dataset["radar_out"].scan_type not in ("ppi", "rhi", "vertical_pointing"):
warn(
"This product is only available for PPI, RHI"
" or vertically pointing volumes"
)
return None
colors = prdcfg.get("colors", None)
data_on_y = prdcfg.get("data_on_y", True)
plot_legend = prdcfg.get("plot_legend", True)
if prdcfg["mode"] == "ALONG_RNG":
use_altitude = prdcfg.get("use_altitude", False)
value_start = prdcfg.get("value_start", 0.0)
fix_elevations = prdcfg.get("fix_elevations", None)
fix_azimuths = prdcfg.get("fix_azimuths", None)
if fix_elevations is None and fix_azimuths is None:
warn(
"At least one fixed elevation or fixed azimuth"
" has to be specified"
)
return None
if use_altitude:
value_stop = prdcfg.get(
"value_stop", np.max(dataset["radar_out"].gate_altitude["data"])
)
else:
value_stop = prdcfg.get(
"value_stop", np.max(dataset["radar_out"].range["data"])
)
ang_tol = prdcfg.get("AngTol", 1.0)
xvals, yvals, valid_azi, valid_ele = get_data_along_rng(
dataset["radar_out"],
field_name,
fix_elevations,
fix_azimuths,
ang_tol=ang_tol,
rmin=value_start,
rmax=value_stop,
use_altitude=use_altitude,
)
if not yvals:
warn("No data found")
return None
if use_altitude:
labelx = "Altitude (m MSL)"
else:
labelx = "Range (m)"
labels = list()
for ele, azi in zip(valid_ele, valid_azi):
labels.append(
"azi " + "{:.1f}".format(azi) + " ele " + "{:.1f}".format(ele)
)
elif prdcfg["mode"] == "ALONG_AZI":
value_start = prdcfg.get(
"value_start", np.min(dataset["radar_out"].azimuth["data"])
)
value_stop = prdcfg.get(
"value_stop", np.max(dataset["radar_out"].azimuth["data"])
)
ang_tol = prdcfg.get("AngTol", 1.0)
rng_tol = prdcfg.get("RngTol", 50.0)
xvals, yvals, valid_rng, valid_ele = get_data_along_azi(
dataset["radar_out"],
field_name,
prdcfg["fix_ranges"],
prdcfg["fix_elevations"],
rng_tol=rng_tol,
ang_tol=ang_tol,
azi_start=value_start,
azi_stop=value_stop,
)
if not yvals:
warn("No data found")
return None
labelx = "Azimuth Angle (deg)"
labels = list()
for ele, rng in zip(valid_ele, valid_rng):
labels.append(
"rng " + "{:.1f}".format(rng) + " ele " + "{:.1f}".format(ele)
)
elif prdcfg["mode"] == "ALONG_ELE":
value_start = prdcfg.get(
"value_start", np.min(dataset["radar_out"].elevation["data"])
)
value_stop = prdcfg.get(
"value_stop", np.max(dataset["radar_out"].elevation["data"])
)
ang_tol = prdcfg.get("AngTol", 1.0)
rng_tol = prdcfg.get("RngTol", 50.0)
xvals, yvals, valid_rng, valid_azi = get_data_along_ele(
dataset["radar_out"],
field_name,
prdcfg["fix_ranges"],
prdcfg["fix_azimuths"],
rng_tol=rng_tol,
ang_tol=ang_tol,
ele_min=value_start,
ele_max=value_stop,
)
if not yvals:
warn("No data found")
return None
labelx = "Elevation Angle (deg)"
labels = list()
for azi, rng in zip(valid_azi, valid_rng):
labels.append(
"rng " + "{:.1f}".format(rng) + " azi " + "{:.1f}".format(azi)
)
else:
warn("Unknown plotting mode " + prdcfg["mode"])
return None
labely = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
prdcfg["mode"],
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_along_coord(
xvals,
yvals,
fname_list,
labelx=labelx,
labely=labely,
labels=labels,
title=titl,
colors=colors,
data_on_y=data_on_y,
plot_legend=plot_legend,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "PLOT_TXH":
radar = dataset["radar_out"]
field_name = "transmitted_signal_power_h"
if field_name not in radar.fields:
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# user defined parameters
azi_res = prdcfg.get("azi_res", None)
ele_res = prdcfg.get("ele_res", None)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
angtol = prdcfg.get("ang_tol", 0.5)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdcfg["prdname"],
prdcfg["timeinfo"],
)
fname_list = make_filename(
"constr",
prdcfg["dstype"],
prdcfg["dsname"],
prdcfg["imgformat"],
prdcfginfo="rng" + "{:.1f}".format(dataset["radar_out"].range["data"][0]),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
plot_fixed_rng(
radar,
field_name,
prdcfg,
fname_list,
azi_res=None,
ele_res=None,
ang_tol=angtol,
vmin=vmin,
vmax=vmax,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "BSCOPE_IMAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
ray_dim = prdcfg.get("ray_dim", "ang")
xaxis_rng = prdcfg.get("xaxis_rng", True)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
ang_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
ang = ang_vec[prdcfg["anglenr"]]
ind_ang = np.where(dataset["radar_out"].fixed_angle["data"] == ang)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"b-scope",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="ang" + "{:.1f}".format(ang),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
if dataset["radar_out"].rays_per_sweep["data"][ind_ang] > 1:
plot_bscope(
dataset["radar_out"],
field_name,
ind_ang,
prdcfg,
fname_list,
vmin=vmin,
vmax=vmax,
ray_dim=ray_dim,
xaxis_rng=xaxis_rng,
)
else:
plot_ray(
dataset["radar_out"].extract_sweeps([ind_ang]),
field_name,
0,
prdcfg,
fname_list,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "TIME_RANGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
ang_vec = np.sort(dataset["radar_out"].fixed_angle["data"])
ang = ang_vec[prdcfg["anglenr"]]
ind_ang = np.where(dataset["radar_out"].fixed_angle["data"] == ang)[0][0]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"time-range",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
prdcfginfo="ang" + "{:.1f}".format(ang),
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
if dataset["radar_out"].scan_type == "ALONG_AZI":
ylabel = "azimuth (deg)"
elif dataset["radar_out"].scan_type == "ALONG_RNG":
ylabel = "range (km)"
elif dataset["radar_out"].scan_type == "ALONG_ELE":
ylabel = "elevation (deg)"
else:
ylabel = "range (km)"
plot_time_range(
dataset["radar_out"],
field_name,
ind_ang,
prdcfg,
fname_list,
vmin=vmin,
vmax=vmax,
ylabel=ylabel,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "HISTOGRAM":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
step = prdcfg.get("step", None)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
write_data = prdcfg.get("write_data", 0)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"histogram",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
bin_edges, values = compute_histogram(
dataset["radar_out"].fields[field_name]["data"],
field_name,
step=step,
vmin=vmin,
vmax=vmax,
)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
labelx = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
plot_histogram(
bin_edges,
values,
fname_list,
labelx=labelx,
labely="Number of Samples",
titl=titl,
)
print("----- save to " + " ".join(fname_list))
if write_data:
fname = (
savedir
+ make_filename(
"histogram",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
)
hist, _ = np.histogram(values, bins=bin_edges)
write_histogram(
bin_edges, hist, fname, datatype=prdcfg["voltype"], step=step
)
print("----- save to " + fname)
return fname
return fname_list
if prdcfg["type"] == "SAMPLES_HISTOGRAM":
field_name = get_fieldname_pyart(prdcfg["voltype"])
if field_name not in dataset:
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
if "samples" not in dataset[field_name]:
warn("Unable to compute histogram. No samples")
return None
step = prdcfg.get("step", None)
write_data = prdcfg.get("write_data", 0)
timeformat = "%Y%m%d"
if dataset[field_name]["bias_type"] == "instant":
timeformat = "%Y%m%d%H%M%S"
field_metadata = pyart.config.get_metadata(field_name)
titl = (
dataset[field_name]["timeinfo"].strftime(timeformat)
+ "\n"
+ get_field_name(field_metadata, field_name)
)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=dataset[field_name]["timeinfo"],
)
fname_list = make_filename(
"histogram",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=dataset[field_name]["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
bin_edges, values = compute_histogram(
dataset[field_name]["samples"], field_name, step=step
)
labelx = get_colobar_label(field_metadata, field_name)
plot_histogram(
bin_edges,
values,
fname_list,
labelx=labelx,
labely="Number of Samples",
titl=titl,
)
print("----- save to " + " ".join(fname_list))
if write_data:
fname = (
savedir
+ make_filename(
"histogram",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
)
hist, _ = np.histogram(values, bins=bin_edges)
write_histogram(
bin_edges, hist, fname, datatype=prdcfg["voltype"], step=step
)
print("----- save to " + fname)
return fname
return fname_list
if prdcfg["type"] == "QUANTILES":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# mask unclassified data
field = deepcopy(dataset["radar_out"].fields[field_name]["data"])
if prdcfg["voltype"] in ("hydro", "hydroc"):
field = np.ma.masked_equal(field, 1)
# user defined variables
quantiles = prdcfg.get("quantiles", None)
write_data = prdcfg.get("write_data", 0)
fixed_span = prdcfg.get("fixed_span", 1)
vmin = None
vmax = None
if fixed_span:
vmin, vmax = pyart.config.get_field_limits(field_name)
if "vmin" in prdcfg:
vmin = prdcfg["vmin"]
if "vmax" in prdcfg:
vmax = prdcfg["vmax"]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"quantiles",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
quantiles, values = compute_quantiles(field, quantiles=quantiles)
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
labely = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
plot_quantiles(
quantiles,
values,
fname_list,
labelx="quantile",
labely=labely,
titl=titl,
vmin=vmin,
vmax=vmax,
)
print("----- save to " + " ".join(fname_list))
if write_data:
fname = (
savedir
+ make_filename(
"quantiles",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
)
write_quantiles(quantiles, values, fname, datatype=prdcfg["voltype"])
print("----- save to " + fname)
return fname
return fname_list
if prdcfg["type"] == "WRITE_STATS" or prdcfg["type"] == "WRITE_MEAN":
if prdcfg["type"] == "WRITE_MEAN":
warn("WRITE_MEAN product is deprecated, please use 'WRITE_STATS' instead")
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
ele_min = prdcfg.get("ele_min", 0.0)
ele_max = prdcfg.get("ele_max", 90.0)
azi_min = prdcfg.get("azi_min", 0.0)
azi_max = prdcfg.get("azi_max", 360.0)
rmin = prdcfg.get("rmin", 0.0)
rmax = prdcfg.get("rmax", 50.0)
write_min_max = prdcfg.get("write_min_max", False)
quantiles = prdcfg.get("quantiles", [])
field_data = dataset["radar_out"].fields[field_name]["data"]
el_data = dataset["radar_out"].elevation["data"]
az_data = dataset["radar_out"].azimuth["data"]
rng_data = dataset["radar_out"].range["data"]
units = dataset["radar_out"].fields[field_name]["units"]
ind_ele = np.where((el_data >= ele_min) & (el_data <= ele_max))
ind_azi = np.where((az_data >= azi_min) & (az_data <= azi_max))
ind_rng = np.where((rng_data >= rmin) & (rng_data <= rmax))
azmin = dataset["radar_out"].get_azimuth(0)[0]
azmax = dataset["radar_out"].get_azimuth(0)[-1]
elmin = dataset["radar_out"].fixed_angle["data"][0]
elmax = dataset["radar_out"].fixed_angle["data"][-1]
field_data_process = field_data[np.intersect1d(ind_ele, ind_azi), :]
field_data_process = field_data_process[:, ind_rng]
countzero = np.size(np.where(field_data_process == 0.0))
meanval = np.nanmean(field_data_process)
if write_min_max:
minval = np.nanmin(field_data_process)
maxval = np.nanmax(field_data_process)
if len(quantiles):
quantilesvals = np.nanpercentile(field_data_process, quantiles)
stdval = np.nanstd(field_data_process)
medianval = np.nanmedian(field_data_process)
ntotal = np.size(field_data_process)
nvalid = ntotal - countzero
text = [
"Statistics of a region in a volume.",
" Name : " + field_name,
" Azimuth : " + str(azmin) + " - " + str(azmax) + " [deg]",
" Elevation : " + str(elmin) + " - " + str(elmax) + " [deg]",
" Range : " + str(rmin) + " - " + str(rmax) + " [m]",
]
# Generate labels
labels = ["Mean", "Median", "Stddev"]
if write_min_max:
labels.extend(["Min", "Max"])
if len(quantiles):
labels.extend([f"Q{q}" for q in quantiles])
labels.extend(["Nsamples", "Nvalid"])
# Generate values
values = [meanval, medianval, stdval]
if write_min_max:
values.extend([minval, maxval])
if len(quantiles):
values.extend(quantilesvals)
values.extend([ntotal, nvalid])
data = {
"dstype": prdcfg["dstype"],
"unit": units,
"time": prdcfg["timeinfo"],
"label": labels,
"value": values,
}
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"ts",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
timeformat="%Y%m%d",
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
write_timeseries_point(
fname, data, field_name, text, timeformat=None, timeinfo=prdcfg["timeinfo"]
)
print("----- save to " + fname)
return fname
if prdcfg["type"] == "FIELD_COVERAGE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
threshold = prdcfg.get("threshold", None)
nvalid_min = prdcfg.get("nvalid_min", 5.0)
ele_res = prdcfg.get("ele_res", 1.0)
azi_res = prdcfg.get("azi_res", 2.0)
ele_min = prdcfg.get("ele_min", 0.0)
ele_max = prdcfg.get("ele_max", 30.0)
ele_step = prdcfg.get("ele_step", 5.0)
ele_sect_start = prdcfg.get("ele_sect_start", None)
ele_sect_stop = prdcfg.get("ele_sect_stop", None)
quantiles = prdcfg.get(
"quantiles",
np.array([10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0]),
)
# get coverage per ray
field_coverage = np.ma.masked_all(dataset["radar_out"].nrays)
for i in range(dataset["radar_out"].nrays):
mask = np.ma.getmaskarray(
dataset["radar_out"].fields[field_name]["data"][i, :]
)
if threshold is not None:
ind = np.where(
np.logical_and(
~mask,
dataset["radar_out"].fields[field_name]["data"][i, :]
>= threshold,
)
)[0]
else:
ind = np.where(~mask)[0]
if len(ind) > nvalid_min:
field_coverage[i] = (
dataset["radar_out"].range["data"][ind[-1]]
- dataset["radar_out"].range["data"][ind[0]]
)
# group coverage per elevation sectors
nsteps = int((ele_max - ele_min) / ele_step) # number of steps
nele = int(ele_step / ele_res) # number of elev per step
ele_steps_vec = np.arange(nsteps) * ele_step + ele_min
yval = []
xval = []
labels = []
for i in range(nsteps - 1):
yval_aux = np.ma.array([])
xval_aux = np.array([])
for j in range(nele):
ele_target = ele_steps_vec[i] + j * ele_res
d_ele = np.abs(dataset["radar_out"].elevation["data"] - ele_target)
ind_ele = np.where(d_ele < prdcfg["AngTol"])[0]
if ind_ele.size == 0:
continue
yval_aux = np.ma.concatenate([yval_aux, field_coverage[ind_ele]])
xval_aux = np.concatenate(
[xval_aux, dataset["radar_out"].azimuth["data"][ind_ele]]
)
yval.append(yval_aux)
xval.append(xval_aux)
labels.append(
"ele "
+ "{:.1f}".format(ele_steps_vec[i])
+ "-"
+ "{:.1f}".format(ele_steps_vec[i + 1])
+ " deg"
)
# get mean value per azimuth for a specified elevation sector
xmeanval = None
ymeanval = None
quantval = None
labelmeanval = None
if ele_sect_start is not None and ele_sect_stop is not None:
ind_ele = np.where(
np.logical_and(
dataset["radar_out"].elevation["data"] >= ele_sect_start,
dataset["radar_out"].elevation["data"] <= ele_sect_stop,
)
)
field_coverage_sector = field_coverage[ind_ele]
azi_sector = dataset["radar_out"].azimuth["data"][ind_ele]
nazi = int(
(
np.max(dataset["radar_out"].azimuth["data"])
- np.min(dataset["radar_out"].azimuth["data"])
)
/ azi_res
+ 1
)
xmeanval = np.arange(nazi) * azi_res + np.min(
dataset["radar_out"].azimuth["data"]
)
ymeanval = np.ma.masked_all(nazi)
for i in range(nazi):
d_azi = np.abs(azi_sector - xmeanval[i])
ind_azi = np.where(d_azi < prdcfg["AngTol"])[0]
if ind_azi.size == 0:
continue
ymeanval[i] = np.ma.mean(field_coverage_sector[ind_azi])
labelmeanval = (
"ele "
+ "{:.1f}".format(ele_sect_start)
+ "-"
+ "{:.1f}".format(ele_sect_stop)
+ " deg mean val"
)
_, quantval, _ = quantiles_weighted(
field_coverage_sector, quantiles=quantiles / 100.0
)
# plot field coverage
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"coverage",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
plot_field_coverage(
xval,
yval,
fname_list,
labels=labels,
title=titl,
ymin=0.0,
ymax=np.max(dataset["radar_out"].range["data"]) + 60000.0,
xmeanval=xmeanval,
ymeanval=ymeanval,
labelmeanval=labelmeanval,
)
print("----- save to " + " ".join(fname_list))
fname = make_filename(
"coverage",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
if quantval is not None:
data_type = get_colobar_label(
dataset["radar_out"].fields[field_name], field_name
)
write_field_coverage(
quantiles,
quantval,
ele_sect_start,
ele_sect_stop,
np.min(xmeanval),
np.max(xmeanval),
threshold,
nvalid_min,
data_type,
prdcfg["timeinfo"],
fname,
)
print("----- save to " + fname)
return fname
if prdcfg["type"] == "CDF":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
quantiles = prdcfg.get("quantiles", None)
sector = {
"rmin": None,
"rmax": None,
"azmin": None,
"azmax": None,
"elmin": None,
"elmax": None,
"hmin": None,
"hmax": None,
}
if "sector" in prdcfg:
if "rmin" in prdcfg["sector"]:
sector["rmin"] = prdcfg["sector"]["rmin"]
if "rmax" in prdcfg["sector"]:
sector["rmax"] = prdcfg["sector"]["rmax"]
if "azmin" in prdcfg["sector"]:
sector["azmin"] = prdcfg["sector"]["azmin"]
if "azmax" in prdcfg["sector"]:
sector["azmax"] = prdcfg["sector"]["azmax"]
if "elmin" in prdcfg["sector"]:
sector["elmin"] = prdcfg["sector"]["elmin"]
if "elmax" in prdcfg["sector"]:
sector["elmax"] = prdcfg["sector"]["elmax"]
if "hmin" in prdcfg["sector"]:
sector["hmin"] = prdcfg["sector"]["hmin"]
if "hmax" in prdcfg["sector"]:
sector["hmax"] = prdcfg["sector"]["hmax"]
vismin = prdcfg.get("vismin", None)
absolute = prdcfg.get("absolute", False)
use_nans = prdcfg.get("use_nans", False)
nan_value = prdcfg.get("nan_value", 0.0)
filterclt = prdcfg.get("filterclt", False)
filterprec = prdcfg.get("filterprec", np.array([], dtype=int))
data = deepcopy(dataset["radar_out"].fields[field_name]["data"])
# define region of interest
roi_flag = get_ROI(dataset["radar_out"], field_name, sector)
data = data[roi_flag == 1]
ntot = np.size(roi_flag[roi_flag == 1])
if ntot == 0:
warn("No radar gates found in sector")
return None
# get number of gates with clutter and mask them
nclut = -1
if filterclt:
echoID_field = get_fieldname_pyart("echoID")
if echoID_field in dataset["radar_out"].fields:
echoID_ROI = dataset["radar_out"].fields[echoID_field]["data"][
roi_flag == 1
]
nclut = len(echoID_ROI[echoID_ROI == 2])
data[echoID_ROI == 2] = np.ma.masked
# get number of blocked gates and filter according to visibility
nblocked = -1
if vismin is not None:
vis_field = get_fieldname_pyart("VIS")
if vis_field in dataset["radar_out"].fields:
vis_ROI = dataset["radar_out"].fields[vis_field]["data"][roi_flag == 1]
nblocked = len(vis_ROI[vis_ROI < vismin])
data[vis_ROI < vismin] = np.ma.masked
# filter according to precip type
nprec_filter = -1
if filterprec.size > 0:
hydro_field = get_fieldname_pyart("hydro")
if hydro_field in dataset["radar_out"].fields:
hydro_ROI = dataset["radar_out"].fields[hydro_field]["data"][
roi_flag == 1
]
nprec_filter = 0
for ind_hydro in filterprec:
nprec_filter += len(hydro_ROI[hydro_ROI == ind_hydro])
data[hydro_ROI == ind_hydro] = np.ma.masked
if absolute:
data = np.ma.abs(data)
mask = np.ma.getmaskarray(data)
nnan = np.count_nonzero(mask)
if nnan == ntot:
warn("No valid radar gates found in sector")
return None
if use_nans:
data[mask] = nan_value
# count and filter outliers
_, values_lim = compute_quantiles(data, quantiles=[0.2, 99.8])
if values_lim.mask[0] or values_lim.mask[1]:
warn("No valid radar gates found in sector")
return None
nsmall = np.count_nonzero(data.compressed() < values_lim[0])
nlarge = np.count_nonzero(data.compressed() > values_lim[1])
noutliers = nlarge + nsmall
data = data[np.logical_and(data >= values_lim[0], data <= values_lim[1])]
# number of values used for cdf computation
ncdf = np.size(data.compressed())
quantiles, values = compute_quantiles(data, quantiles=quantiles)
# plot CDF
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname_list = make_filename(
"cdf",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
titl = (
pyart.graph.common.generate_radar_time_begin(
dataset["radar_out"]
).isoformat()
+ "Z"
+ "\n"
+ get_field_name(dataset["radar_out"].fields[field_name], field_name)
)
labelx = get_colobar_label(dataset["radar_out"].fields[field_name], field_name)
plot_quantiles(
values,
quantiles / 100.0,
fname_list,
labelx=labelx,
labely="Cumulative probability",
titl=titl,
)
print("----- save to " + " ".join(fname_list))
# store cdf values
fname = make_filename(
"cdf",
prdcfg["dstype"],
prdcfg["voltype"],
["txt"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
write_cdf(
quantiles,
values,
ntot,
nnan,
nclut,
nblocked,
nprec_filter,
noutliers,
ncdf,
fname,
use_nans=use_nans,
nan_value=nan_value,
filterprec=filterprec,
vismin=vismin,
sector=sector,
datatype=labelx,
timeinfo=prdcfg["timeinfo"],
)
print("----- save to " + fname)
return fname
if prdcfg["type"] == "SELFCONSISTENCY":
if "selfconsistency_points" not in dataset:
return None
retrieve_relation = prdcfg.get("retrieve_relation", True)
plot_theoretical = prdcfg.get("plot_theoretical", True)
normalize = prdcfg.get("normalize", True)
timeinfo = dataset["selfconsistency_points"]["timeinfo"]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=timeinfo,
)
fname_list = make_filename(
"selfconsistency",
prdcfg["dstype"],
"selfconsistency",
prdcfg["imgformat"],
timeinfo=timeinfo,
runinfo=prdcfg["runinfo"],
timeformat="%Y%m%d",
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_selfconsistency_instrument(
np.array(dataset["selfconsistency_points"]["zdr"]),
np.array(dataset["selfconsistency_points"]["kdp"]),
np.array(dataset["selfconsistency_points"]["zh"]),
fname_list,
parametrization=dataset["selfconsistency_points"]["parametrization"],
zdr_kdpzh_dict=dataset["selfconsistency_points"]["zdr_kdpzh_dict"],
normalize=normalize,
retrieve_relation=retrieve_relation,
plot_theoretical=plot_theoretical,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "SELFCONSISTENCY2":
if "selfconsistency_points" not in dataset:
return None
normalize = prdcfg.get("normalize", True)
timeinfo = dataset["selfconsistency_points"]["timeinfo"]
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=timeinfo,
)
fname_list = make_filename(
"selfconsistency2",
prdcfg["dstype"],
"selfconsistency2",
prdcfg["imgformat"],
timeinfo=timeinfo,
runinfo=prdcfg["runinfo"],
timeformat="%Y%m%d",
)
for i, fname in enumerate(fname_list):
fname_list[i] = savedir + fname
fname_list = plot_selfconsistency_instrument2(
np.array(dataset["selfconsistency_points"]["zdr"]),
np.array(dataset["selfconsistency_points"]["kdp"]),
10.0 * np.ma.log10(np.array(dataset["selfconsistency_points"]["zh"])),
fname_list,
parametrization=dataset["selfconsistency_points"]["parametrization"],
zdr_kdpzh_dict=dataset["selfconsistency_points"]["zdr_kdpzh_dict"],
normalize=normalize,
)
print("----- save to " + " ".join(fname_list))
return fname_list
if prdcfg["type"] == "VOL_TS":
# Time series of a value
field_name = get_fieldname_pyart(prdcfg["voltype"])
if field_name not in dataset:
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
# check the type of dataset required
bias_type = prdcfg.get("bias_type", "cumulative")
if dataset[field_name]["bias_type"] != bias_type:
return None
# put time info in file path and name
csvtimeinfo_path = None
csvtimeinfo_file = None
timeformat = None
if bias_type == "instant":
csvtimeinfo_path = dataset[field_name]["timeinfo"]
csvtimeinfo_file = dataset[field_name]["timeinfo"]
timeformat = "%Y%m%d"
if prdcfg.get("add_date_in_fname", False):
csvtimeinfo_file = dataset[field_name]["timeinfo"]
timeformat = "%Y"
quantiles = prdcfg.get("quantiles", np.array([25.0, 75.0]))
ref_value = prdcfg.get("ref_value", 0.0)
sort_by_date = prdcfg.get("sort_by_date", False)
rewrite = prdcfg.get("rewrite", False)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdcfg["prdname"],
timeinfo=csvtimeinfo_path,
)
csvfname = make_filename(
"ts",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=csvtimeinfo_file,
timeformat=timeformat,
runinfo=prdcfg["runinfo"],
)[0]
csvfname = savedir + csvfname
start_time = dataset[field_name]["timeinfo"]
values = np.ma.masked_all(3)
values[1] = dataset[field_name]["value"]
if "samples" in dataset[field_name]:
values[0] = np.percentile(
dataset[field_name]["samples"].compressed(), quantiles[0]
)
values[2] = np.percentile(
dataset[field_name]["samples"].compressed(), quantiles[1]
)
write_monitoring_ts(
start_time,
dataset[field_name]["npoints"],
values,
[quantiles[0], "value", quantiles[1]],
prdcfg["voltype"],
csvfname,
)
print("saved CSV file: " + csvfname)
date, np_t_vec, cquant_vec, lquant_vec, hquant_vec = read_monitoring_ts(
csvfname, sort_by_date=sort_by_date
)
if date is None:
warn("Unable to plot time series. No valid data")
return None
if rewrite:
val_vec = np.ma.asarray([lquant_vec, cquant_vec, hquant_vec]).T
write_monitoring_ts(
date,
np_t_vec,
val_vec,
quantiles,
prdcfg["voltype"],
csvfname,
rewrite=True,
)
figtimeinfo = None
titldate = ""
if bias_type == "instant":
figtimeinfo = date[0]
titldate = date[0].strftime("%Y-%m-%d")
else:
titldate = date[0].strftime("%Y%m%d") + "-" + date[-1].strftime("%Y%m%d")
if prdcfg.get("add_date_in_fname", False):
figtimeinfo = date[0]
timeformat = "%Y"
figfname_list = make_filename(
"ts",
prdcfg["dstype"],
prdcfg["voltype"],
prdcfg["imgformat"],
timeinfo=figtimeinfo,
timeformat=timeformat,
runinfo=prdcfg["runinfo"],
)
for i, figfname in enumerate(figfname_list):
figfname_list[i] = savedir + figfname
titl = prdcfg["runinfo"] + " Monitoring " + titldate
labely = generate_field_name_str(prdcfg["voltype"])
np_min = prdcfg.get("npoints_min", 0)
vmin = prdcfg.get("vmin", None)
vmax = prdcfg.get("vmax", None)
plot_monitoring_ts(
date,
np_t_vec,
cquant_vec,
lquant_vec,
hquant_vec,
field_name,
figfname_list,
ref_value=ref_value,
vmin=vmin,
vmax=vmax,
np_min=np_min,
labelx="Time UTC",
labely=labely,
titl=titl,
)
print("----- save to " + " ".join(figfname_list))
# generate alarms if needed
alarm = prdcfg.get("alarm", False)
if not alarm:
return figfname_list
if "tol_abs" not in prdcfg:
warn("unable to send alarm. Missing tolerance on target")
return None
if "tol_trend" not in prdcfg:
warn("unable to send alarm. Missing tolerance in trend")
return None
if "nevents_min" not in prdcfg:
warn(
"unable to send alarm. "
+ "Missing minimum number of events to compute trend"
)
return None
if "sender" not in prdcfg:
warn("unable to send alarm. Missing email sender")
return None
if "receiver_list" not in prdcfg:
warn("unable to send alarm. Missing email receivers")
return None
tol_abs = prdcfg["tol_abs"]
tol_trend = prdcfg["tol_trend"]
nevents_min = prdcfg["nevents_min"]
sender = prdcfg["sender"]
receiver_list = prdcfg["receiver_list"]
np_last = np_t_vec[-1]
value_last = cquant_vec[-1]
if np_last < np_min:
warn("No valid data on day " + date[-1].strftime("%d-%m-%Y"))
return None
# check if absolute value exceeded
abs_exceeded = False
if (value_last > ref_value + tol_abs) or (value_last < ref_value - tol_abs):
warn(
"Value "
+ str(value_last)
+ " exceeds target "
+ str(ref_value)
+ " +/- "
+ str(tol_abs)
)
abs_exceeded = True
# compute trend and check if last value exceeds it
mask = np.ma.getmaskarray(cquant_vec)
ind = np.where(np.logical_and(np.logical_not(mask), np_t_vec >= np_min))[0]
nvalid = len(ind)
if nvalid <= nevents_min:
warn("Not enough points to compute reliable trend")
np_trend = 0
value_trend = np.ma.masked
else:
np_trend_vec = np_t_vec[ind][-(nevents_min + 1) : -1]
data_trend_vec = cquant_vec[ind][-(nevents_min + 1) : -1]
np_trend = np.sum(np_trend_vec)
value_trend = np.sum(data_trend_vec * np_trend_vec) / np_trend
trend_exceeded = False
if np_trend > 0:
if (value_last > value_trend + tol_trend) or (
value_last < value_trend - tol_trend
):
warn(
"Value "
+ str(value_last)
+ "exceeds trend "
+ str(value_trend)
+ " +/- "
+ str(tol_trend)
)
trend_exceeded = True
if abs_exceeded is False and trend_exceeded is False:
return None
alarm_dir = savedir + "/alarms/"
if not os.path.isdir(alarm_dir):
os.makedirs(alarm_dir)
alarm_fname = make_filename(
"alarm",
prdcfg["dstype"],
prdcfg["voltype"],
["txt"],
timeinfo=start_time,
timeformat="%Y%m%d",
)[0]
alarm_fname = alarm_dir + alarm_fname
field_dict = pyart.config.get_metadata(field_name)
param_name = get_field_name(field_dict, field_name)
param_name_unit = param_name + " [" + field_dict["units"] + "]"
write_alarm_msg(
prdcfg["RadarName"][0],
param_name_unit,
start_time,
ref_value,
tol_abs,
np_trend,
value_trend,
tol_trend,
nevents_min,
np_last,
value_last,
alarm_fname,
)
print("----- saved monitoring alarm to " + alarm_fname)
subject = (
"NO REPLY: "
+ param_name
+ " monitoring alarm for radar "
+ prdcfg["RadarName"][0]
+ " on day "
+ start_time.strftime("%d-%m-%Y")
)
send_msg(sender, receiver_list, subject, alarm_fname)
return alarm_fname
if prdcfg["type"] == "SAVEVOL_CSV":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
ignore_masked = prdcfg.get("ignore_masked", False)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savevol",
prdcfg["dstype"],
prdcfg["voltype"],
["csv"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
fname = write_vol_csv(
fname, dataset["radar_out"], field_name, ignore_masked=ignore_masked
)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEVOL_KML":
if not _SIMPLEKML_AVAILABLE:
warn("simplekml needed to output kml file")
return None
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
ignore_masked = prdcfg.get("ignore_masked", False)
azi_res = prdcfg.get("azi_res", None)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savevol",
prdcfg["dstype"],
prdcfg["voltype"],
["kml"],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
if azi_res is None:
azi_res = 1.0
if dataset["radar_out"].instrument_parameters is None:
warn(
f"radar beamwidth not specified."
f" Default {azi_res} deg will be used"
)
elif "radar_beam_width_h" not in dataset["radar_out"].instrument_parameters:
warn(
f"radar beamwidth not specified."
f" Default {azi_res} deg will be used"
)
else:
azi_res = dataset["radar_out"].instrument_parameters[
"radar_beam_width_h"
]["data"][0]
rng_res_km = dataset["rng_res"] / 1000.0
fname = write_vol_kml(
fname,
dataset["radar_out"],
field_name,
ignore_masked=ignore_masked,
rng_res_km=rng_res_km,
azi_res=azi_res,
)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEVOL" or prdcfg["type"] == "SAVEVOL_VOL":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
file_type = prdcfg.get("file_type", "nc")
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
new_dataset = deepcopy(dataset["radar_out"])
new_dataset.fields = dict()
new_dataset.add_field(field_name, dataset["radar_out"].fields[field_name])
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savevol",
prdcfg["dstype"],
prdcfg["voltype"],
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
if file_type == "nc":
pyart.io.write_cfradial(fname, new_dataset)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
new_dataset,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
return None
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEALL" or prdcfg["type"] == "SAVEALL_VOL":
file_type = prdcfg.get("file_type", "nc")
datatypes = prdcfg.get("datatypes", None)
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savevol",
prdcfg["dstype"],
"all_fields",
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
field_names = None
if datatypes is not None:
field_names = []
for datatype in datatypes:
field_names.append(get_fieldname_pyart(datatype))
if file_type == "nc":
if field_names is not None:
radar_aux = deepcopy(dataset["radar_out"])
radar_aux.fields = dict()
for field_name in field_names:
if field_name not in dataset["radar_out"].fields:
warn(field_name + " not in radar object")
else:
radar_aux.add_field(
field_name, dataset["radar_out"].fields[field_name]
)
else:
radar_aux = dataset["radar_out"]
pyart.io.write_cfradial(fname, radar_aux)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
dataset["radar_out"],
field_names=field_names,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVESTATE":
if prdcfg["lastStateFile"] is None:
warn("Unable to save last state file. File name not specified")
return None
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
max_time = np.max(dataset["radar_out"].time["data"])
units = dataset["radar_out"].time["units"]
calendar = dataset["radar_out"].time["calendar"]
last_date = num2date(max_time, units, calendar)
write_last_state(last_date, prdcfg["lastStateFile"])
print("saved file: " + prdcfg["lastStateFile"])
return prdcfg["lastStateFile"]
if prdcfg["type"] == "SAVEPSEUDORHI":
file_type = prdcfg.get("file_type", "nc")
datatypes = prdcfg.get("datatypes", None)
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savepseudorhi",
prdcfg["dstype"],
"all_fields",
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
field_names = None
if datatypes is not None:
field_names = []
for datatype in datatypes:
field_names.append(get_fieldname_pyart(datatype))
pseudorhi = pyart.util.cross_section_ppi(
dataset["radar_out"], [prdcfg["angle"]], az_tol=prdcfg["AziTol"]
)
if file_type == "nc":
if field_names is not None:
radar_aux = deepcopy(pseudorhi)
radar_aux.fields = dict()
for field_name in field_names:
if field_name not in pseudorhi.fields:
warn(field_name + " not in radar object")
else:
radar_aux.add_field(field_name, pseudorhi.fields[field_name])
else:
radar_aux = pseudorhi
pyart.io.write_cfradial(
fname,
radar_aux,
)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
pseudorhi,
field_names=field_names,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEPSEUDOPPI":
file_type = prdcfg.get("file_type", "nc")
datatypes = prdcfg.get("datatypes", None)
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savepseudorhi",
prdcfg["dstype"],
"all_fields",
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
field_names = None
if datatypes is not None:
field_names = []
for datatype in datatypes:
field_names.append(get_fieldname_pyart(datatype))
pseudoppi = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=prdcfg["EleTol"]
)
if file_type == "nc":
if field_names is not None:
radar_aux = deepcopy(pseudoppi)
radar_aux.fields = dict()
for field_name in field_names:
if field_name not in pseudoppi.fields:
warn(field_name + " not in radar object")
else:
radar_aux.add_field(field_name, pseudoppi.fields[field_name])
else:
radar_aux = pseudoppi
pyart.io.write_cfradial(
fname,
radar_aux,
)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
pseudoppi,
field_names=field_names,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEPSEUDORHI":
file_type = prdcfg.get("file_type", "nc")
datatypes = prdcfg.get("datatypes", None)
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savepseudorhi",
prdcfg["dstype"],
"all_fields",
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
field_names = None
if datatypes is not None:
field_names = []
for datatype in datatypes:
field_names.append(get_fieldname_pyart(datatype))
pseudorhi = pyart.util.cross_section_ppi(
dataset["radar_out"], [prdcfg["angle"]], az_tol=prdcfg["AziTol"]
)
if file_type == "nc":
if field_names is not None:
radar_aux = deepcopy(pseudorhi)
radar_aux.fields = dict()
for field_name in field_names:
if field_name not in pseudorhi.fields:
warn(field_name + " not in radar object")
else:
radar_aux.add_field(field_name, pseudorhi.fields[field_name])
else:
radar_aux = pseudorhi
pyart.io.write_cfradial(
fname,
radar_aux,
)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
pseudorhi,
field_names=field_names,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVEPSEUDOPPI":
file_type = prdcfg.get("file_type", "nc")
datatypes = prdcfg.get("datatypes", None)
prdcfg.get("physical", True)
compression = prdcfg.get("compression", "gzip")
compression_opts = prdcfg.get("compression_opts", 6)
savedir = get_save_dir(
prdcfg["basepath"],
prdcfg["procname"],
dssavedir,
prdsavedir,
timeinfo=prdcfg["timeinfo"],
)
fname = make_filename(
"savepseudorhi",
prdcfg["dstype"],
"all_fields",
[file_type],
timeinfo=prdcfg["timeinfo"],
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
field_names = None
if datatypes is not None:
field_names = []
for datatype in datatypes:
field_names.append(get_fieldname_pyart(datatype))
pseudoppi = pyart.util.cross_section_rhi(
dataset["radar_out"], [prdcfg["angle"]], el_tol=prdcfg["EleTol"]
)
if file_type == "nc":
if field_names is not None:
radar_aux = deepcopy(pseudoppi)
radar_aux.fields = dict()
for field_name in field_names:
if field_name not in pseudoppi.fields:
warn(field_name + " not in radar object")
else:
radar_aux.add_field(field_name, pseudoppi.fields[field_name])
else:
radar_aux = pseudoppi
pyart.io.write_cfradial(fname, radar_aux)
elif file_type == "h5":
pyart.aux_io.write_odim_h5(
fname,
pseudoppi,
field_names=field_names,
compression=compression,
compression_opts=compression_opts,
)
else:
warn("Data could not be saved. " + "Unknown saving file type " + file_type)
print("saved file: " + fname)
return fname
if prdcfg["type"] == "SAVE_FIXED_ANGLE":
field_name = get_fieldname_pyart(prdcfg["voltype"])
fields = dataset["radar_out"].fields
names = field_name if isinstance(field_name, (list, tuple)) else [field_name]
if not all(f in fields for f in names):
warn(
" Field type "
+ field_name
+ " not available in data set. Skipping product "
+ prdcfg["type"]
)
return None
savedir = get_save_dir(
prdcfg["basepath"], prdcfg["procname"], dssavedir, prdsavedir, timeinfo=None
)
fname = make_filename(
"ts",
prdcfg["dstype"],
"fixed_angle",
["csv"],
timeinfo=None,
runinfo=prdcfg["runinfo"],
)[0]
fname = savedir + fname
write_fixed_angle(
prdcfg["timeinfo"],
dataset["radar_out"].fixed_angle["data"][0],
dataset["radar_out"].latitude["data"][0],
dataset["radar_out"].longitude["data"][0],
dataset["radar_out"].altitude["data"][0],
fname,
)
print("saved file: " + fname)
return fname
warn(" Unsupported product type: " + prdcfg["type"])
return None