Source code for pyrad.prod.process_vol_products

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