diff --git a/edosl0util/cli.py b/edosl0util/cli.py index d8bceef6dc7ac833a70ed78311259b4fe62a87c1..2532f5015e57c01196fb8da15036b9ba892c446c 100644 --- a/edosl0util/cli.py +++ b/edosl0util/cli.py @@ -110,15 +110,23 @@ def cmd_merge(): def cmd_rdr2l0(): + """ + Extract CCSDS packets from a JPSS RDR. They are extracted in the order in + which they are listed in the APID list and in packet tracker order, i.e., + Not in time/apid order. Files will be named using the input h5 name with + .science.pds and .diary[0,8,11].pds appended. + """ parser = _default_parser() - parser.add_argument('-o', '--output') - parser.add_argument('-f', '--skipfill', action='store_true') - parser.add_argument('sensor', choices=('atms', 'cris')) + parser.description = cmd_rdr2l0.__doc__ + parser.add_argument( + '-d', '--diary', action='store_true', + help='Write diary[0,8,11].pds if available') + parser.add_argument( + '-f', '--skipfill', action='store_true', + help=('Skip any packets that are marked in the packet tracker as ' + 'containing fill')) parser.add_argument('rdr') args = parser.parse_args() _configure_logging(args) - output = args.output or args.rdr + '.pds' - with io.open(output, 'wb') as fptr: - for packet in jpssrdr.convert_to_nasa_l0(args.sensor, args.rdr): - fptr.write(packet) + jpssrdr.write_rdr_datasets(args.rdr, args.diary) diff --git a/edosl0util/jpssrdr.py b/edosl0util/jpssrdr.py index d8ef6a862c126e2d70f363d0754739d9c3ab2315..a217fae272350d01a365444e5c4998abe5ffcdda 100644 --- a/edosl0util/jpssrdr.py +++ b/edosl0util/jpssrdr.py @@ -9,8 +9,10 @@ Code for reading/writing/manipulating JPSS Common RDR files as documented in: """ __copyright__ = "Copyright (C) 2015 University of Wisconsin SSEC. All rights reserved." +import os import logging import ctypes as c +from datetime import datetime from collections import namedtuple import numpy as np @@ -90,13 +92,17 @@ Packet = namedtuple('Packet', ('tracker', 'packet')) class CommonRdr(namedtuple('CommonRdr', ('buf', 'header', 'apids'))): + """ + A single common rdr as found in a RawApplicationPackets_X dataset. + """ def packets_for_apid(self, apid): """ Return a generator that yields tuples of (tracker, packet) for the given `Apid`. """ - return _packets_for_apid(self.buf, self.header, apid) + for tracker, packet in _packets_for_apid(self.buf, self.header, apid): + yield Packet(tracker, packet) def packets(self): """ @@ -104,8 +110,8 @@ class CommonRdr(namedtuple('CommonRdr', ('buf', 'header', 'apids'))): apid list. """ for apid in self.apids: - for tracker, packet in self.packets_for_apid(apid): - yield Packet(tracker, packet) + for packet in self.packets_for_apid(apid): + yield packet def _packets_for_apid(buf, header, apid): @@ -137,31 +143,54 @@ def _read_apid_list(header, buf): offset += c.sizeof(Apid) -def read_common_rdrs(sensor, filepath): - """ - Generate CommonRdr-s for each dataset(granule) in `filelpath` - """ - for buf in read_rdr_datasets(sensor, filepath): - header = StaticHeader.from_buffer(buf) - apids = _read_apid_list(header, buf) - yield CommonRdr(buf, header, list(apids)) +def _sorted_packet_dataset_names(names): + names = [k for k in names if k.startswith('RawApplicationPackets_')] + cmp_names = lambda *tup: cmp(*(int(x.split('_')[-1]) for x in tup)) # noqa + return sorted(names, cmp=cmp_names) -def read_rdr_datasets(sensor, filepath): - """ - Generate byte arrays of granule RawApplicationPackets in granule number - order. - """ - sensor = sensor.upper() +def _generate_packet_datasets(group): + dsnames = group.keys() + for name in _sorted_packet_dataset_names(dsnames): + ds = group[name] + yield np.array(ds) + + +def _find_science_group(fobj): + for sensor in ['viirs', 'cris', 'atms']: + group = fobj.get('/All_Data/{}-SCIENCE-RDR_All'.format(sensor.upper())) + if group: + return group + + +def _rdrs_for_packet_dataset(group): + if group: + for buf in _generate_packet_datasets(group): + header = StaticHeader.from_buffer(buf) + apids = _read_apid_list(header, buf) + yield CommonRdr(buf, header, list(apids)) + + +def rdr_datasets(filepath): fobj = H5File(filepath) - grp = fobj['/All_Data/{}-SCIENCE-RDR_All'.format(sensor)] + rdr = {} + group = _find_science_group(fobj) + rdr['science'] = _rdrs_for_packet_dataset(group) + group = fobj.get('/All_Data/SPACECRAFT-DIARY-RDR_All') + rdr['diary'] = _rdrs_for_packet_dataset(group) + return rdr - dsnames = [k for k in grp.keys() if k.startswith('RawApplicationPackets_')] - # compare ds names by index after '_' - cmp_names = lambda *tup: cmp(*(int(x.split('_')[-1]) for x in tup)) # noqa - for name in sorted(dsnames, cmp=cmp_names): - ds = grp[name] - yield np.array(ds) + +def rdr_ccsds_packets(rdr, skipfill=False): + """ + Get all CCSDS packets from an `CommonRdr` in packet tracker order. + """ + for packet in rdr.packets(): + if packet.tracker.fill_percent != 0: + LOG.debug('fill: %s', packet.tracker) + if skipfill: + continue + yield packet.packet def sort_packets_by_obs_time(packets): @@ -182,17 +211,25 @@ def sort_packets_by_apid(packets, order=None): return sorted(packets, key=lambda p: p.packet.apid) -def convert_to_nasa_l0(sensor, filename, skipfill=False): - """ - Convert a JSPP RDR to a NASA L0 PDS file. - """ - for idx, rdr in enumerate(read_common_rdrs(sensor, filename)): - LOG.debug(rdr.header) - for apid in rdr.apids: - LOG.debug(apid) - for packet in rdr.packets(): - if packet.tracker.fill_percent != 0: - LOG.debug('fill: %s', packet.tracker) - if skipfill: +def write_rdr_datasets(filepath, diary=True, skipfill=False): + def write_packets(pkts, dest): + with open(dest, 'wb') as fptr: + for pkt in pkts: + if pkt.tracker.fill_percent != 0 and skipfill: continue - yield packet.packet + fptr.write(pkt.packet) + rdrname = os.path.basename(filepath) + rdrs = rdr_datasets(filepath) + for idx, rdr in enumerate(rdrs['science']): + fname = '{}.science.pds'.format(rdrname) + hdr = rdr.header + LOG.debug('writing gran %d %s-%s-%s', idx, hdr.satellite, hdr.sensor, hdr.type_id) + write_packets(rdr.packets(), fname) + + if diary: + for idx, rdr in enumerate(rdrs['diary']): + for apid in rdr.apids: + fname = '{}.diary{}.pds'.format(rdrname, apid.value) + hdr = rdr.header + LOG.debug('writing gran %d %s-%s-%s %d', idx, hdr.satellite, hdr.sensor, hdr.type_id, apid.value) + write_packets(rdr.packets_for_apid(apid), fname)