Source code for pyart.io.mdv_radar

"""
Utilities for reading of MDV radar files.

"""

import numpy as np
from netCDF4 import date2num

from ..config import FileMetadata, get_fillvalue
from ..core.radar import Radar
from ..lazydict import LazyLoadDict
from . import mdv_common
from .common import _test_arguments, make_time_unit_str, prepare_for_read


[docs]def read_mdv( filename, field_names=None, additional_metadata=None, file_field_names=False, exclude_fields=None, include_fields=None, delay_field_loading=False, **kwargs ): """ Read a MDV file. Parameters ---------- filename : str Name of MDV file to read or file-like object pointing to the beginning of such a file. field_names : dict, optional Dictionary mapping MDV data type names to radar field names. If a data type found in the file does not appear in this dictionary or has a value of None it will not be placed in the radar.fields dictionary. A value of None, the default, will use the mapping defined in the Py-ART configuration file. additional_metadata : dict of dicts, optional Dictionary of dictionaries to retrieve metadata from during this read. This metadata is not used during any successive file reads unless explicitly included. A value of None, the default, will not introduct any addition metadata and the file specific or default metadata as specified by the Py-ART configuration file will be used. file_field_names : bool, optional True to use the MDV data type names for the field names. If this case the field_names parameter is ignored. The field dictionary will likely only have a 'data' key, unless the fields are defined in `additional_metadata`. exclude_fields : list or None, optional List of fields to exclude from the radar object. This is applied after the `file_field_names` and `field_names` parameters. Set to None to include all fields specified by include_fields. include_fields : list or None, optional List of fields to include from the radar object. This is applied after the `file_field_names` and `field_names` parameters. Set to None to include all fields not specified by exclude_fields. delay_field_loading : bool True to delay loading of field data from the file until the 'data' key in a particular field dictionary is accessed. In this case the field attribute of the returned Radar object will contain LazyLoadDict objects not dict objects. Not all file types support this parameter. Returns ------- radar : Radar Radar object containing data from MDV file. Notes ----- Currently this function can only read polar MDV files with fields compressed with gzip or zlib. """ # test for non empty kwargs _test_arguments(kwargs) # create metadata retrieval object filemetadata = FileMetadata( "mdv", field_names, additional_metadata, file_field_names, exclude_fields, include_fields, ) mdvfile = mdv_common.MdvFile(prepare_for_read(filename)) # value attributes az_deg, range_km, el_deg = mdvfile._calc_geometry() naz = len(az_deg) nele = len(el_deg) scan_type = mdvfile.projection if scan_type not in ["ppi", "rhi"]: raise NotImplementedError("No support for scan_type %s." % scan_type) # time time = filemetadata("time") units = make_time_unit_str(mdvfile.times["time_begin"]) time["units"] = units time_start = date2num(mdvfile.times["time_begin"], units) time_end = date2num(mdvfile.times["time_end"], units) time["data"] = np.linspace(time_start, time_end, naz * nele) # range _range = filemetadata("range") _range["data"] = np.array(range_km * 1000.0, dtype="float32") _range["meters_to_center_of_first_gate"] = _range["data"][0] _range["meters_between_gates"] = _range["data"][1] - _range["data"][0] # fields fields = {} for mdv_field in set(mdvfile.fields): field_name = filemetadata.get_field_name(mdv_field) if field_name is None: continue # create and store the field dictionary field_dic = filemetadata(field_name) field_dic["_FillValue"] = get_fillvalue() dataextractor = mdv_common._MdvVolumeDataExtractor( mdvfile, mdvfile.fields.index(mdv_field), get_fillvalue() ) if delay_field_loading: field_dic = LazyLoadDict(field_dic) field_dic.set_lazy("data", dataextractor) else: field_dic["data"] = dataextractor() fields[field_name] = field_dic # metadata metadata = filemetadata("metadata") for meta_key, mdv_key in mdv_common.MDV_METADATA_MAP.items(): metadata[meta_key] = mdvfile.master_header[mdv_key] # latitude latitude = filemetadata("latitude") latitude["data"] = np.array([mdvfile.radar_info["latitude_deg"]], dtype="float64") # longitude longitude = filemetadata("longitude") longitude["data"] = np.array([mdvfile.radar_info["longitude_deg"]], dtype="float64") # altitude altitude = filemetadata("altitude") altitude["data"] = np.array( [mdvfile.radar_info["altitude_km"] * 1000.0], dtype="float64" ) # sweep_number, sweep_mode, fixed_angle, sweep_start_ray_index, # sweep_end_ray_index sweep_number = filemetadata("sweep_number") sweep_mode = filemetadata("sweep_mode") fixed_angle = filemetadata("fixed_angle") sweep_start_ray_index = filemetadata("sweep_start_ray_index") sweep_end_ray_index = filemetadata("sweep_end_ray_index") len_time = len(time["data"]) if scan_type == "ppi": nsweeps = nele sweep_number["data"] = np.arange(nsweeps, dtype="int32") sweep_mode["data"] = np.array(nsweeps * ["azimuth_surveillance"], dtype="S") fixed_angle["data"] = np.array(el_deg, dtype="float32") sweep_start_ray_index["data"] = np.arange(0, len_time, naz, dtype="int32") sweep_end_ray_index["data"] = np.arange(naz - 1, len_time, naz, dtype="int32") elif scan_type == "rhi": nsweeps = naz sweep_number["data"] = np.arange(nsweeps, dtype="int32") sweep_mode["data"] = np.array(nsweeps * ["rhi"], dtype="S") fixed_angle["data"] = np.array(az_deg, dtype="float32") sweep_start_ray_index["data"] = np.arange(0, len_time, nele, dtype="int32") sweep_end_ray_index["data"] = np.arange(nele - 1, len_time, nele, dtype="int32") # azimuth, elevation azimuth = filemetadata("azimuth") elevation = filemetadata("elevation") if scan_type == "ppi": azimuth["data"] = np.tile(az_deg, nele) elevation["data"] = np.array(el_deg).repeat(naz) elif scan_type == "rhi": azimuth["data"] = np.array(az_deg).repeat(nele) elevation["data"] = np.tile(el_deg, naz) # instrument parameters # we will set 4 parameters in the instrument_parameters dict # prt, prt_mode, unambiguous_range, and nyquist_velocity # TODO prt mode: Need to fix this.. assumes dual if two prts if mdvfile.radar_info["prt2_s"] == 0.0: prt_mode_str = "fixed" else: prt_mode_str = "dual" prt_mode = filemetadata("prt_mode") prt = filemetadata("prt") unambiguous_range = filemetadata("unambiguous_range") nyquist_velocity = filemetadata("nyquist_velocity") beam_width_h = filemetadata("radar_beam_width_h") beam_width_v = filemetadata("radar_beam_width_v") prt_mode["data"] = np.array([prt_mode_str] * nsweeps, dtype="S") prt["data"] = np.array([mdvfile.radar_info["prt_s"]] * nele * naz, dtype="float32") urange_m = mdvfile.radar_info["unambig_range_km"] * 1000.0 unambiguous_range["data"] = np.array([urange_m] * naz * nele, dtype="float32") uvel_mps = mdvfile.radar_info["unambig_vel_mps"] nyquist_velocity["data"] = np.array([uvel_mps] * naz * nele, dtype="float32") beam_width_h["data"] = np.array( [mdvfile.radar_info["horiz_beam_width_deg"]], dtype="float32" ) beam_width_v["data"] = np.array( [mdvfile.radar_info["vert_beam_width_deg"]], dtype="float32" ) instrument_parameters = { "prt_mode": prt_mode, "prt": prt, "unambiguous_range": unambiguous_range, "nyquist_velocity": nyquist_velocity, "radar_beam_width_h": beam_width_h, "radar_beam_width_v": beam_width_v, } if not delay_field_loading: mdvfile.close() return Radar( time, _range, fields, metadata, scan_type, latitude, longitude, altitude, sweep_number, sweep_mode, fixed_angle, sweep_start_ray_index, sweep_end_ray_index, azimuth, elevation, instrument_parameters=instrument_parameters, )