Source code for

Automatic reading of radar files by detecting format.


import bz2
import gzip

import netCDF4

from .cfradial import read_cfradial
from .chl import read_chl
from .mdv_radar import read_mdv
from .nexrad_archive import read_nexrad_archive
from .nexrad_cdm import read_nexrad_cdm
from .nexradl3_read import read_nexrad_level3
from .rsl import _RSL_AVAILABLE, read_rsl
from .sigmet import read_sigmet
from .uf import read_uf

[docs]def read(filename, use_rsl=False, **kwargs): """ Read a radar file and return a radar object. Additional parameters are passed to the underlying read_* function. Parameters ---------- filename : str Name of radar file to read. use_rsl : bool True will use the TRMM RSL library to read files which are supported both natively and by RSL. False will choose the native read function. RSL will always be used to read a file if it is not supported natively. Other Parameters ------------------- field_names : dict, optional Dictionary mapping file 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 metadata 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 metadata configuration file will be used. file_field_names : bool, optional True to use the file 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. 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. A TypeError is raised if the format cannot be determined. """ filetype = determine_filetype(filename) # Bzip, uncompress and see if we can determine the type if filetype == "BZ2": bzfile = bz2.BZ2File(filename) try: radar = read(bzfile, use_rsl, **kwargs) except: raise ValueError( "Bzip file cannot be read compressed, uncompress and try again" ) finally: bzfile.close() return radar # Gzip, uncompress and see if we can determine the type if filetype == "GZ": gzfile =, "rb") try: radar = read(gzfile, use_rsl, **kwargs) except: raise ValueError( "Gzip file cannot be read compressed, uncompress and try again" ) finally: gzfile.close() return radar # Py-ART only supported formats if filetype == "MDV": return read_mdv(filename, **kwargs) if filetype == "NETCDF3" or filetype == "NETCDF4": dset = netCDF4.Dataset(filename) if "cdm_data_type" in dset.ncattrs(): # NEXRAD CDM dset.close() return read_nexrad_cdm(filename, **kwargs) else: dset.close() return read_cfradial(filename, **kwargs) # CF/Radial if filetype == "WSR88D": return read_nexrad_archive(filename, **kwargs) if filetype == "CHL": return read_chl(filename, **kwargs) if filetype == "NEXRADL3": return read_nexrad_level3(filename, **kwargs) # RSL supported formats which are also supported natively in Py-ART if filetype == "SIGMET": if use_rsl: return read_rsl(filename, **kwargs) else: return read_sigmet(filename, **kwargs) if filetype == "UF": if use_rsl: return read_rsl(filename, **kwargs) else: return read_uf(filename, **kwargs) # RSL only supported file formats rsl_formats = ["HDF4", "RSL", "DORAD", "LASSEN"] if filetype in rsl_formats and _RSL_AVAILABLE: return read_rsl(filename, **kwargs) raise TypeError("Unknown or unsupported file format: " + filetype)
def determine_filetype(filename): """ Return the filetype of a given file by examining the first few bytes. The following filetypes are detected: * 'MDV' * 'NETCDF3' * 'NETCDF4' * 'WSR88D' * 'NEXRADL3' * 'UF' * 'HDF4' * 'RSL' * 'DORAD' * 'SIGMET' * 'LASSEN' * 'BZ2' * 'GZ' * 'UNKNOWN' Parameters ---------- filename : str Name of file to examine. Returns ------- filetype : str Type of file. """ # TODO # detect the following formats, those supported by RSL # 'RADTEC', the SPANDAR radar at Wallops Island, VA # 'MCGILL', McGill S-band # 'TOGA', DYNAMO project's radar # 'RAPIC', Berrimah Australia # 'RAINBOW' # read the first 12 bytes from the file try: f = open(filename, "rb") begin = f.close() except TypeError: f = filename begin =, 1) # MDV, read with read_mdv # MDV format signature from MDV FORMAT Interface Control Document (ICD) # recond_len1, struct_id, revision_number # 1016, 14142, 1 # import struct # mdv_signature = struct.pack('>3i', 1016, 14142, 1) mdv_signature = b"\x00\x00\x03\xf8\x00\x007>\x00\x00\x00\x01" if begin[:12] == mdv_signature: return "MDV" # CSU-CHILL # begins with ARCH_ID_FILE_HDR = 0x5aa80004 # import struct # struct.pack('<i', 0x5aa80004) chl_signature = b"\x04\x00\xa8Z" if begin[:4] == chl_signature: return "CHL" # NetCDF3, read with read_cfradial if begin[:3] == b"CDF": return "NETCDF3" # NetCDF4, read with read_cfradial, contained in a HDF5 container # HDF5 format signature from HDF5 specification documentation hdf5_signature = b"\x89\x48\x44\x46\x0d\x0a\x1a\x0a" if begin[:8] == hdf5_signature: return "NETCDF4" # NEXRAD LEVEL 3 begin with SDUSXX KXXX nexrad_l3_signature = b"SDUS" if begin[:4] == nexrad_l3_signature: return "NEXRADL3" # NEXRAD LEVEL 3 with NOAAPORT record seperator # Start of heading (x01) \r\r\nXXX \r\r\nSDUSXX KXXX if begin[:4] == b"\x01\r\r\n": return "NEXRADL3" # Other files should be read with read_rsl # WSR-88D begin with ARCHIVE2. or AR2V000 if begin[:9] == b"ARCHIVE2." or begin[:7] == b"AR2V000": return "WSR88D" # Universal format has UF in bytes 0,1 or 2,3 or 4,5 if begin[:2] == b"UF" or begin[2:4] == b"UF" or begin[4:6] == b"UF": return "UF" # DORADE files if begin[:4] == b"SSWB" or begin[:4] == b"VOLD" or begin[:4] == b"COMM": return "DORADE" # LASSEN if begin[4:11] == b"SUNRISE": return "LASSEN" # RSL file if begin[:3] == b"RSL": return "RSL" # HDF4 file # HDF4 format signature from HDF4 specification documentation hdf4_signature = b"\x0e\x03\x13\x01" if begin[:4] == hdf4_signature: return "HDF4" # SIGMET files # SIGMET format is a structure_header with a Product configuration # indicator (see section 4.2.47) # sigmet_signature = chr(27) sigmet_signature = b"\x1b" if begin[0:1] == sigmet_signature: return "SIGMET" # bzip2 compressed files bzip2_signature = b"BZh" if begin[:3] == bzip2_signature: return "BZ2" gzip_signature = b"\x1f\x8b" if begin[:2] == gzip_signature: return "GZ" # Cannot determine filetype return "UNKNOWN"