Skip to content

Commit

Permalink
ENH: Improve Level2File for legacy formatted data
Browse files Browse the repository at this point in the history
This file, which has AR2V0001 as the version, has some oddities in it.
Improve the parser to cope with these better.
  • Loading branch information
dopplershift committed Apr 27, 2021
1 parent a5f5d8b commit 7ff3cdb
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 14 deletions.
44 changes: 32 additions & 12 deletions src/metpy/io/nexrad.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ def _read_data(self):

# Check if we have any message segments still in the buffer
if self._msg_buf:
log.warning('Remaining buffered messages segments for message type(s): %s',
' '.join(map(str, self._msg_buf)))
log.warning('Remaining buffered message segments for message type(s): %s',
' '.join(f'{typ} ({len(rem)})' for typ, rem in self._msg_buf.items()))

del self._msg_buf

Expand Down Expand Up @@ -305,14 +305,14 @@ def _decode_msg1(self, msg_hdr):
hdr.surv_gate_width,
hdr.surv_num_gates, 2.0, 66.0)))

if hdr.vel_offset:
if hdr.doppler_num_gates and hdr.vel_offset:
read_info.append((hdr.vel_offset,
self.msg1_data_hdr('VEL', hdr.doppler_first_gate,
hdr.doppler_gate_width,
hdr.doppler_num_gates,
1. / hdr.dop_res, 129.0)))

if hdr.sw_offset:
if hdr.doppler_num_gates and hdr.sw_offset:
read_info.append((hdr.sw_offset,
self.msg1_data_hdr('SW', hdr.doppler_first_gate,
hdr.doppler_gate_width,
Expand Down Expand Up @@ -452,14 +452,23 @@ def _decode_msg5(self, msg_hdr):
def _decode_msg13(self, msg_hdr):
data = self._buffer_segment(msg_hdr)
if data:
date, time, num_el, *data = Struct('>{:d}h'.format(len(data) // 2)).unpack(data)
self.clutter_filter_bypass_map = {'datetime': nexrad_to_datetime(date, time),
'data': []}
data = Struct('>{:d}h'.format(len(data) // 2)).unpack(data)
# Legacy format doesn't have date/time and has fewer azimuths
if data[0] <= 5:
num_el = data[0]
dt = None
num_az = 256
offset = 1
else:
date, time, num_el = data[:3]
# time is in "minutes since midnight", need to pass as ms since midnight
dt = nexrad_to_datetime(date, 60 * 1000 * time)
num_az = 360
offset = 3

num_az = 360
self.clutter_filter_bypass_map = {'datetime': dt, 'data': []}
chunk_size = 32
bit_conv = Bits(16)
offset = 0
for e in range(num_el):
seg_num = data[offset]
if seg_num != (e + 1):
Expand Down Expand Up @@ -487,7 +496,14 @@ def _decode_msg15(self, msg_hdr):
data = self._buffer_segment(msg_hdr)
if data:
date, time, num_el, *data = Struct('>{:d}h'.format(len(data) // 2)).unpack(data)
self.clutter_filter_map = {'datetime': nexrad_to_datetime(date, time), 'data': []}
if num_el == 0:
log.info('Message 15 num_el is 0--likely legacy clutter filter notch width. '
'Skipping...')
return

# time is in "minutes since midnight", need to pass as ms since midnight
self.clutter_filter_map = {'datetime': nexrad_to_datetime(date, 60 * 1000 * time),
'data': []}

offset = 0
for _ in range(num_el):
Expand All @@ -507,14 +523,18 @@ def _decode_msg18(self, msg_hdr):
# buffer the segments until we have the whole thing. The data
# will be returned concatenated when this is the case
data = self._buffer_segment(msg_hdr)
if data:

# Legacy versions don't even document this:
if data and self.vol_hdr.version[:8] not in (b'ARCHIVE2', b'AR2V0001'):
from ._nexrad_msgs.msg18 import descriptions, fields
self.rda_adaptation_desc = descriptions

# Can't use NamedStruct because we have more than 255 items--this
# is a CPython limit for arguments.
msg_fmt = DictStruct(fields, '>')
self.rda = msg_fmt.unpack(data)

# Be extra paranoid about passing too much data in case of legacy files
self.rda = msg_fmt.unpack(data[:msg_fmt.size])
for num in (11, 21, 31, 32, 300, 301):
attr = f'VCPAT{num}'
dat = self.rda[attr]
Expand Down
1 change: 1 addition & 0 deletions src/metpy/static-data-manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ KICX_20170712_1458 94bd4f795832f056f7489a5562acf76de9a9cab1694549562cc3154abb225
KTLX19990503_235621.gz 7a097251bb7a15dbcdec75812812e41a86c5eb9850f55c3d91d120c2c61e046e
KTLX20130520_201643_V06.gz 772e01b154a5c966982a6d0aa2fc78bc64f08a9b77165b74dc02d7aa5aa69275
KTLX20150530_000802_V06.bz2 d78689afc525c853dec8ccab4a4eccc2daacef5c7df198a35a3a791016e993b0
KVWX_20050626_221551.gz 78f98f3c3660627abcb7ba073b1399af45b2b61b30ae7d64fa726fc6acf72d9c
Level2_FOP1_20191223_003655.ar2v 4a086f6190c0d324612922e9fcb46262c3a1d825810caa8a11aca3823db17ae3
Level2_KDDC_20200823_204121.ar2v 17c9011be6155f454b4710f8d36ea8974bc39472016a5b663d8718fb87425a4e
Level2_KFTG_20150430_1419.ar2v 77c3355c8a503561eb3cddc3854337e640d983a4acdfc27bdfbab60c0b18cfc1
Expand Down
Binary file added staticdata/KVWX_20050626_221551.gz
Binary file not shown.
5 changes: 3 additions & 2 deletions tests/io/test_nexrad.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
('TDAL20191021021543V08.raw.gz', datetime(2019, 10, 21, 2, 15, 43), 10, 1,
3, 0),
('Level2_FOP1_20191223_003655.ar2v', datetime(2019, 12, 23, 0, 36, 55, 649000),
16, 5, 7, 0)]
16, 5, 7, 0),
('KVWX_20050626_221551.gz', datetime(2005, 6, 26, 22, 15, 51), 11, 1, 3, 23)]


# ids here fixes how things are presented in pycharm
Expand Down Expand Up @@ -95,7 +96,7 @@ def test_msg15():
f = Level2File(get_test_data('KTLX20130520_201643_V06.gz', as_file_obj=False))
data = f.clutter_filter_map['data']
assert isinstance(data[0][0], list)
assert f.clutter_filter_map['datetime'] == datetime(2013, 5, 19, 0, 0, 0, 315000)
assert f.clutter_filter_map['datetime'] == datetime(2013, 5, 19, 5, 15, 0, 0)


def test_single_chunk(caplog):
Expand Down

0 comments on commit 7ff3cdb

Please sign in to comment.