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