From 2aafd00b8eceee5bb7306352fe2ff140657505fc Mon Sep 17 00:00:00 2001
From: Greg Quinn <greg.quinn@ssec.wisc.edu>
Date: Mon, 9 Oct 2017 11:51:23 -0500
Subject: [PATCH] Add RCRIS-RNSCA rdrgen test

---
 edosl0util/rdrgen.py                          | 39 ++++++++-----
 ...5_b30810_c20171008061237136301_nobu_ops.h5 |  3 +
 tests/test_rdrgen.py                          | 58 ++++++++++++++++++-
 3 files changed, 82 insertions(+), 18 deletions(-)
 create mode 100644 tests/RCRIS-RNSCA_npp_d20171008_t0004096_e0012095_b30810_c20171008061237136301_nobu_ops.h5

diff --git a/edosl0util/rdrgen.py b/edosl0util/rdrgen.py
index 7b1e516..0092776 100644
--- a/edosl0util/rdrgen.py
+++ b/edosl0util/rdrgen.py
@@ -16,22 +16,28 @@ from edosl0util.jpssrdr import (
 from edosl0util.stream import jpss_packet_stream
 
 
-def packets_to_rdrs(sat, pkt_files, aggr_level=None, attr_overrides={}):
+def packets_to_rdrs(sat, l0_files, **kwargs):
+    def iter_pkts(l0_files):
+        for l0_file in l0_files:
+            with open(l0_file) as l0_file_obj:
+                for pkt in jpss_packet_stream(l0_file_obj):
+                    yield pkt
+    build_rdr(sat, iter_pkts(l0_files), **kwargs)
+
+
+def build_rdr(sat, pkt_iter, aggr_level=None, diary_cushion=10000000, attr_overrides={}):
 
     # divy packets up into temp files organized by granule
     file_mgr = BinnedTemporaryFileManager()
     get_jpss_packet_time = GetJpssPacketTime()
     gran_infos = set()  # (rdr_type, gran_iet) pairs
-    for pkt_file in pkt_files:
-        with open(pkt_file) as file_obj:
-            stream = jpss_packet_stream(file_obj)
-            for pkt in stream:
-                rdr_type = get_rdr_type(pkt.apid)
-                pkt_iet = get_jpss_packet_time(pkt)
-                gran_iet = get_granule_start(sat, rdr_type.gran_len, pkt_iet)
-                gran_info = (rdr_type, gran_iet)
-                gran_infos.add(gran_info)
-                file_mgr.add_data(gran_info, pkt.bytes())
+    for pkt in pkt_iter:
+        rdr_type = get_rdr_type(pkt.apid)
+        pkt_iet = get_jpss_packet_time(pkt)
+        gran_iet = get_granule_start(sat, rdr_type.gran_len, pkt_iet)
+        gran_info = (rdr_type, gran_iet)
+        gran_infos.add(gran_info)
+        file_mgr.add_data(gran_info, pkt.bytes())
 
     # determine what RDR files we'll be producing based on the packets we've seen
     rdr_types = set(rdr_type for rdr_type, gran_iet in gran_infos)
@@ -43,6 +49,7 @@ def packets_to_rdrs(sat, pkt_files, aggr_level=None, attr_overrides={}):
         for (rdr_type, gran_iet) in gran_infos if rdr_type is primary_type))
 
     # now generate the RDRs
+    rdr_files = []
     for aggr_iet in primary_aggr_iets:
         rdr_writer = RdrWriter(sat, rdr_types, aggr_iet, aggr_level, **attr_overrides)
         rdr_writer.write_aggregate(primary_type, aggr_iet, aggr_level)
@@ -54,10 +61,9 @@ def packets_to_rdrs(sat, pkt_files, aggr_level=None, attr_overrides={}):
             blob = build_rdr_blob(sat, pkts, primary_type, gran_iet)
             rdr_writer.write_granule(primary_type, gran_iet, blob)
         if packaged_type:
-            cushion = 1000000  # 1 second; is this consistent with IDPS?
             packaged_gran_iets = get_overlapping_granules(
-                sat, packaged_type.gran_len, aggr_iet - cushion,
-                aggr_iet + aggr_level * primary_type.gran_len + cushion + 1)
+                sat, packaged_type.gran_len, aggr_iet - diary_cushion,
+                aggr_iet + aggr_level * primary_type.gran_len + diary_cushion + 1)
             rdr_writer.write_aggregate(
                 packaged_type, packaged_gran_iets[0], len(packaged_gran_iets))
             for gran_iet in packaged_gran_iets:
@@ -66,6 +72,9 @@ def packets_to_rdrs(sat, pkt_files, aggr_level=None, attr_overrides={}):
                 blob = build_rdr_blob(sat, pkts, packaged_type, gran_iet)
                 rdr_writer.write_granule(packaged_type, gran_iet, blob)
         rdr_writer.close()
+        rdr_files.append(rdr_writer.file_name)
+
+    return rdr_files
 
 
 def process_rdr_types(given_rdr_types, force_packaging):
@@ -214,7 +223,7 @@ class RdrWriter(object):
             'AggregateEndingGranuleID': make_granule_id(self._sat, last_gran_iet),
             'AggregateEndingOrbitNumber': np.uint64(self._orbit_num),
             'AggregateEndingTime': self._format_time_attr(aggr_end_iet),
-            'AggregateNumberGranules': np.uint64(1)})
+            'AggregateNumberGranules': np.uint64(num_grans)})
 
     def write_granule(self, rdr_type, gran_iet, blob, creation_time=None):
         raw_grp = self._h5_file['All_Data/{}_All'.format(rdr_type.short_name)]
diff --git a/tests/RCRIS-RNSCA_npp_d20171008_t0004096_e0012095_b30810_c20171008061237136301_nobu_ops.h5 b/tests/RCRIS-RNSCA_npp_d20171008_t0004096_e0012095_b30810_c20171008061237136301_nobu_ops.h5
new file mode 100644
index 0000000..5a6abf3
--- /dev/null
+++ b/tests/RCRIS-RNSCA_npp_d20171008_t0004096_e0012095_b30810_c20171008061237136301_nobu_ops.h5
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8b0087a9fbac547fab22f1de950dc26137f72ed9ff6ddf9dd875b945e0e501ad
+size 141353912
diff --git a/tests/test_rdrgen.py b/tests/test_rdrgen.py
index dd0b359..4dc0b2b 100644
--- a/tests/test_rdrgen.py
+++ b/tests/test_rdrgen.py
@@ -1,6 +1,6 @@
 import os
 import subprocess
-from StringIO import StringIO
+from io import BytesIO
 from datetime import datetime
 
 import h5py
@@ -10,6 +10,58 @@ from edosl0util.jpssrdr import decode_rdr_blob
 from edosl0util.stream import jpss_packet_stream
 
 
+def generate_rdr_packets(rdr_file):
+    """Iterate over all packets in an RDR
+
+    For RDRs with packaged spacecraft diary (e.g. RCRIS-RNSCA), all packets from
+    one RDR type will be provided before the other. Within each RDR type packets
+    will be provided in the order in which they were received when the RDR was
+    constructed (i.e. storage order not tracker order).
+    """
+    with h5py.File(rdr_file, 'r') as h5_file:
+        for grp in h5_file['All_Data'].values():
+            for gran_idx in range(len(grp)):
+                blob = grp['RawApplicationPackets_{}'.format(gran_idx)][:]
+                for pkt in generate_rdr_blob_packets(blob):
+                    yield pkt
+
+
+def generate_rdr_blob_packets(blob):
+    """Iterate packets in an RDR blob in storage (not tracker) order"""
+    # TODO: move to an edosl0util module?
+    info = decode_rdr_blob(blob)
+    pkt_buf = blob[info.header.ap_storage_offset:]
+    return jpss_packet_stream(BytesIO(pkt_buf))
+
+
+def test_can_reproduce_cris_rdr():
+    orig_file_name = 'RCRIS-RNSCA_npp_d20171008_t0004096_e0012095_b30810_c20171008061237136301_nobu_ops.h5'
+    orig_file = os.path.join(os.path.dirname(__file__), orig_file_name)
+    new_file, = m.build_rdr('snpp', generate_rdr_packets(orig_file))
+    with h5py.File(orig_file, 'r') as orig_h5, h5py.File(new_file, 'a') as new_h5:
+        root_attrs = ['Distributor', 'N_Dataset_Source', 'N_HDF_Creation_Date',
+                      'N_HDF_Creation_Time']
+        coll_attrs = ['N_Processing_Domain']
+        aggr_attrs = ['AggregateBeginningOrbitNumber', 'AggregateEndingOrbitNumber']
+        gran_attrs = ['N_Beginning_Orbit_Number', 'N_Creation_Date', 'N_Creation_Time',
+                      'N_IDPS_Mode', 'N_Software_Version', 'N_Granule_Version',
+                      'N_Reference_ID']
+        def copy_attrs(get_obj, attrs):
+            orig_obj = get_obj(orig_h5)
+            new_obj = get_obj(new_h5)
+            for attr in attrs:
+                new_obj.attrs[attr] = orig_obj.attrs[attr]
+        copy_attrs(lambda h5: h5, root_attrs)
+        for coll in orig_h5['Data_Products']:
+            copy_attrs(lambda h5: h5['Data_Products'][coll], coll_attrs)
+            copy_attrs(lambda h5: h5['Data_Products'][coll][coll + '_Aggr'], aggr_attrs)
+            for gran_idx in range(len(orig_h5['Data_Products'][coll]) - 1):
+                copy_attrs(
+                    lambda h5: h5['Data_Products'][coll][coll + '_Gran_' + str(gran_idx)],
+                    gran_attrs)
+
+
+
 def test_can_reproduce_rdr_from_class():
     class_rdr_file = 'RNSCA_npp_d20170912_t0001170_e0001370_b30441_c20170913220340173580_nobu_ops.h5'
     class_rdr_path = os.path.join(os.path.dirname(__file__), class_rdr_file)
@@ -27,7 +79,7 @@ def test_can_reproduce_rdr_from_class():
     rdr_type = m.SpacecraftDiaryRdrType
     gran_iet = 1883865714000000
     aggr_level = 1
-    pkt_stream = jpss_packet_stream(StringIO(pkt_buf.tobytes()))
+    pkt_stream = jpss_packet_stream(BytesIO(pkt_buf.tobytes()))
     blob = m.build_rdr_blob('snpp', pkt_stream, rdr_type, gran_iet)
     tmp_dir = '/tmp'
     writer = m.RdrWriter(
@@ -35,9 +87,9 @@ def test_can_reproduce_rdr_from_class():
         distributor='arch', origin='nob-', domain='ops',
         creation_time=datetime(2017, 9, 13, 22, 3, 40, 173580),
         orbit_num=30441, software_ver='I2.0.03.00')
+    writer.write_aggregate(rdr_type, gran_iet, aggr_level)
     writer.write_granule(rdr_type, gran_iet, blob,
                          creation_time=datetime(2017, 9, 12, 1, 37, 43, 474383))
-    writer.write_aggregate(rdr_type, gran_iet, aggr_level)
     writer.close()
 
 
-- 
GitLab