Source code for pyart.aux_io.rad4alp_gif_reader

"""
pyart.aux_io.rad4alp_gif_reader
======================================

Routines for putting MeteoSwiss operational radar data contained in gif files
into grid object.

.. autosummary::
    :toctree: generated/

    read_gif
    _get_metadata
    _get_datatype_from_file
    _get_physical_data

"""

import os
import datetime
from warnings import warn

import numpy as np

# check existence of imageio
try:
    from imageio import imread
    _IMAGEIO_AVAILABLE = True
except ImportError:
    _IMAGEIO_AVAILABLE = False

from ..config import FileMetadata
from ..io.common import _test_arguments
from ..core.grid import Grid
from ..exceptions import MissingOptionalDependency

GIF_FIELD_NAMES = {
    'CPC0005': 'radar_estimated_rain_rate',
    'CPC0060': 'rainfall_accumulation',
    'CPC0180': 'rainfall_accumulation',
    'CPC0360': 'rainfall_accumulation',
    'CPC0720': 'rainfall_accumulation',
    'CPC1440': 'rainfall_accumulation',
    'CPC2880': 'rainfall_accumulation',
    'CPC4320': 'rainfall_accumulation',
    'CPCH0005': 'radar_estimated_rain_rate',
    'CPCH0060': 'rainfall_accumulation',
    'CPCH0180': 'rainfall_accumulation',
    'CPCH0360': 'rainfall_accumulation',
    'CPCH0720': 'rainfall_accumulation',
    'CPCH1440': 'rainfall_accumulation',
    'CPCH2880': 'rainfall_accumulation',
    'CPCH4320': 'rainfall_accumulation'
}


[docs]def read_gif(filename, additional_metadata=None, chy0=255., chx0=-160., xres=1., yres=1., nx=710, ny=640, nz=1, **kwargs): """ Read a MeteoSwiss operational radar data gif file. Parameters ---------- filename : str Name of the file to read. additional_metadata : dict of dicts, optional Dictionary of dictionaries to retrieve metadata 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. chy0, chx0 : float Swiss coordinates position of the south-western point in the grid xres, yres : float resolution of each grid point [km] nx, ny, nz : int dimensions of the grid Returns ------- grid : Grid Grid object containing the data. """ # check that wradlib is available if not _IMAGEIO_AVAILABLE: raise MissingOptionalDependency( "imageio is required to use read_gif but is not installed") # test for non empty kwargs _test_arguments(kwargs) try: ret = imread(filename, format='gif') except OSError: warn('Unable to read file '+filename) return None # reserved_variables = [ # 'time', 'x', 'y', 'z', # 'origin_latitude', 'origin_longitude', 'origin_altitude', # 'point_x', 'point_y', 'point_z', 'projection', # 'point_latitude', 'point_longitude', 'point_altitude', # 'radar_latitude', 'radar_longitude', 'radar_altitude', # 'radar_name', 'radar_time', 'base_time', 'time_offset', # 'ProjectionCoordinateSystem'] # metadata metadata = _get_metadata(ret.meta) filemetadata = FileMetadata('GIF', GIF_FIELD_NAMES, additional_metadata) # required reserved variables time = filemetadata('grid_time') origin_latitude = filemetadata('origin_latitude') origin_longitude = filemetadata('origin_longitude') origin_altitude = filemetadata('origin_altitude') x = filemetadata('x') y = filemetadata('y') z = filemetadata('z') x['data'] = 1000.*(np.arange(nx)*xres+chy0+xres/2.-600.) y['data'] = 1000.*(np.arange(ny)*yres+chx0+yres/2.-200.) z['data'] = np.array([0.]) # Origin of LV03 Swiss coordinates origin_latitude['data'] = np.array([46.951082877]) origin_longitude['data'] = np.array([7.438632495]) origin_altitude['data'] = np.array([0.]) bfile = os.path.basename(filename) # Time prod_time = datetime.datetime.strptime(bfile[3:12], '%y%j%H%M') time['units'] = 'seconds since '+prod_time.strftime('%Y-%m-%d %H:%M:%S') time['data'] = np.array([0]) # projection (Swiss Oblique Mercator) projection = { 'proj': 'somerc', '_include_lon_0_lat_0': True } # read in the fields datatype = _get_datatype_from_file(bfile) if datatype is None: return None fields = {} field = filemetadata.get_field_name(datatype) field_dict = filemetadata(field) field_dict['data'] = np.broadcast_to( _get_physical_data(ret, datatype, prod_time)[::-1, :], (nz, ny, nx)) fields[field] = field_dict # radar variables radar_latitude = None radar_longitude = None radar_altitude = None radar_name = None radar_time = None return Grid( time, fields, metadata, origin_latitude, origin_longitude, origin_altitude, x, y, z, projection=projection, radar_latitude=radar_latitude, radar_longitude=radar_longitude, radar_altitude=radar_altitude, radar_name=radar_name, radar_time=radar_time)
def _get_metadata(raw_metadata): """ puts metadata in a dictionary Parameters ---------- raw_metadata : str dictionary Returns ------- datatype : str Data type contained in the file """ if 'comment' not in raw_metadata: return dict() raw_comments = str(raw_metadata['comment'], 'utf-8') raw_comments = raw_comments.split('"') comments = [] for comment in raw_comments: comments.append(comment.lstrip()) metadata_dict = dict() for i, comment in enumerate(comments): if '=' in comment: comments_aux = comment.split(' ') for comment_aux in comments_aux: comment_aux2 = comment_aux.split('=') if comment_aux2[1] == '': metadata_dict.update({comment_aux2[0]: comments[i+1]}) else: metadata_dict.update({comment_aux2[0]: comment_aux2[1]}) return metadata_dict def _get_datatype_from_file(filename): """ gets data type from file name Parameters ---------- filename : str base name of the file Returns ------- datatype : str Data type contained in the file """ if filename.startswith('CPC'): acronym = 'CPC' if filename.endswith('_00005.801.gif'): accu_time = '0005' elif filename.endswith('_00060.801.gif'): accu_time = '0060' elif filename.endswith('_00180.801.gif'): accu_time = '0180' elif filename.endswith('_00360.801.gif'): accu_time = '0360' elif filename.endswith('_00720.801.gif'): accu_time = '0720' elif filename.endswith('_01440.801.gif'): accu_time = '1440' elif filename.endswith('_02880.801.gif'): accu_time = '2880' elif filename.endswith('_04320.801.gif'): accu_time = '4320' else: warn('Unknown CPC product') return None return acronym+accu_time warn('Unknown product') return None def _get_physical_data(rgba_data, datatype, prod_time): """ gets data in physical units Parameters ---------- rgba_data : uint8 ndarray the data as 4 channel rgba datatype : str The data type prod_time : datetime object The date at which the product was generated Returns ------- data : float ndarray the data in physical units """ if datatype.startswith('CPC'): scale = np.ma.masked_all(256) ind = np.arange(256.)+1 if prod_time > datetime.datetime(2018, 6, 28): scale[2:251] = np.ma.power( np.ma.power(10., (ind[2:251]-71.5)/20.)/316., 0.6666667) else: scale[2:251] = np.ma.power( np.ma.power(10., (ind[1:250]-71.5)/20.)/316., 0.6666667) ind_vals = 255-rgba_data[:, :, 1] data = scale[ind_vals] return data