11import collections
2+ import dataclasses
23
34import numpy as np
45import xarray as xr
56
7+ from imap_processing .cdf .global_attrs import ConstantCoordinates
8+ from imap_processing .swe import swe_cdf_attrs
9+ from imap_processing .swe .utils .swe_utils import (
10+ add_metadata_to_array ,
11+ )
612
7- def uncompress_counts (cem_count ):
8- """Uncompress counts from the CEMs.
13+
14+ def decompressed_counts (cem_count ):
15+ """Decompressed counts from the CEMs.
916
1017 Parameters
1118 ----------
@@ -15,16 +22,16 @@ def uncompress_counts(cem_count):
1522 Returns
1623 -------
1724 int
18- uncompressed count. Eg. 40959
25+ decompressed count. Eg. 40959
1926 """
2027 # index is the first four bits of input data
2128 # multi is the last four bits of input data
2229 index = cem_count // 16
2330 multi = cem_count % 16
2431
2532 # This is look up table for the index to get
26- # base and step_size to calculate the uncompressed count.
27- uncompress_table = {
33+ # base and step_size to calculate the decompressed count.
34+ decompress_table = {
2835 0 : {"base" : 0 , "step_size" : 1 },
2936 1 : {"base" : 16 , "step_size" : 1 },
3037 2 : {"base" : 32 , "step_size" : 2 },
@@ -43,36 +50,18 @@ def uncompress_counts(cem_count):
4350 15 : {"base" : 33792 , "step_size" : 2048 },
4451 }
4552
46- # uncompression formula from SWE algorithm document CN102D-D0001 and page 16.
53+ # decompression formula from SWE algorithm document CN102D-D0001 and page 16.
4754 # N = base[index] + multi * step_size[index] + (step_size[index] - 1) / 2
4855 # NOTE: for (step_size[index] - 1) / 2, we only keep the whole number part of
4956 # the quotient
5057
5158 return (
52- uncompress_table [index ]["base" ]
53- + (multi * uncompress_table [index ]["step_size" ])
54- + ((uncompress_table [index ]["step_size" ] - 1 ) // 2 )
59+ decompress_table [index ]["base" ]
60+ + (multi * decompress_table [index ]["step_size" ])
61+ + ((decompress_table [index ]["step_size" ] - 1 ) // 2 )
5562 )
5663
5764
58- def add_metadata_to_array (data_packet , metadata_arrays ):
59- """Add metadata to the metadata_arrays.
60-
61- Parameters
62- ----------
63- data_packet : space_packet_parser.parser.Packet
64- SWE data packet
65- metadata_arrays : dict
66- metadata arrays
67- """
68- for key , value in data_packet .header .items ():
69- metadata_arrays .setdefault (key , []).append (value .raw_value )
70-
71- for key , value in data_packet .data .items ():
72- if key != "SCIENCE_DATA" :
73- metadata_arrays .setdefault (key , []).append (value .raw_value )
74-
75-
7665def swe_science (decom_data ):
7766 """SWE L1a science processing.
7867
@@ -116,7 +105,7 @@ def swe_science(decom_data):
116105
117106 # We know we can only have 8 bit numbers input, so iterate over all
118107 # possibilities once up front
119- decompression_table = np .array ([uncompress_counts (i ) for i in range (256 )])
108+ decompression_table = np .array ([decompressed_counts (i ) for i in range (256 )])
120109
121110 for data_packet in decom_data :
122111 # read raw data
@@ -129,51 +118,98 @@ def swe_science(decom_data):
129118 # convert bytes to numpy array of uint8
130119 raw_counts = np .frombuffer (byte_data , dtype = np .uint8 )
131120
132- # Uncompress counts. Uncompressed data is a list of 1260
133- # where 1260 = 15 seconds x 12 energy steps x 7 CEMs
121+ # Uncompress counts. Decompressed data is a list of 1260
122+ # where 1260 = 180 x 7 CEMs
134123 # Take the "raw_counts" indices/counts mapping from
135124 # decompression_table and then reshape the return
136- uncompress_data = np .take (decompression_table , raw_counts ).reshape (15 , 12 , 7 )
137- raw_counts = raw_counts .reshape (15 , 12 , 7 )
125+ uncompress_data = np .take (decompression_table , raw_counts ).reshape (180 , 7 )
126+ # Save raw counts data as well
127+ raw_counts = raw_counts .reshape (180 , 7 )
138128
139129 # Save data with its metadata field to attrs and DataArray of xarray.
140- science_array .append (uncompress_data )
141- raw_science_array .append (raw_counts )
142- add_metadata_to_array (data_packet , metadata_arrays )
130+ # Save data as np.int64 to be complaint with ISTP' FILLVAL
131+ science_array .append (uncompress_data .astype (np .int64 ))
132+ raw_science_array .append (raw_counts .astype (np .int64 ))
133+ metadata_arrays = add_metadata_to_array (data_packet , metadata_arrays )
143134
144- met_time = xr .DataArray (
135+ epoch_time = xr .DataArray (
145136 metadata_arrays ["SHCOARSE" ],
146- name = "met_time" ,
147- dims = ["met_time" ],
148- attrs = dict (
149- description = "Mission elapsed time" ,
150- units = "seconds since start of the mission" ,
151- ),
137+ name = "Epoch" ,
138+ dims = ["Epoch" ],
139+ attrs = ConstantCoordinates .EPOCH ,
140+ )
141+
142+ # TODO: add more descriptive description
143+ energy = xr .DataArray (
144+ np .arange (180 ),
145+ name = "Energy" ,
146+ dims = ["Energy" ],
147+ attrs = dataclasses .replace (
148+ swe_cdf_attrs .int_base ,
149+ catdesc = "Energy's index value in the lookup table" ,
150+ fieldname = "Energy Bins" ,
151+ label_axis = "Energy Bins" ,
152+ units = "" ,
153+ ).output (),
154+ )
155+
156+ counts = xr .DataArray (
157+ np .arange (7 ),
158+ name = "Counts" ,
159+ dims = ["Counts" ],
160+ attrs = dataclasses .replace (
161+ swe_cdf_attrs .int_base ,
162+ catdesc = "Counts" ,
163+ fieldname = "Counts" ,
164+ label_axis = "Counts" ,
165+ units = "int" ,
166+ ).output (),
152167 )
153168
154169 science_xarray = xr .DataArray (
155170 science_array ,
156- dims = ["met_time" , "seconds" , "energy_steps" , "cem_counts" ],
171+ dims = ["Epoch" , "Energy" , "Counts" ],
172+ attrs = swe_cdf_attrs .l1a_science_attrs .output (),
157173 )
174+
158175 raw_science_xarray = xr .DataArray (
159176 raw_science_array ,
160- dims = ["met_time" , "seconds" , "energy_steps" , "cem_counts" ],
177+ dims = ["Epoch" , "Energy" , "Counts" ],
178+ attrs = swe_cdf_attrs .l1a_science_attrs .output (),
161179 )
162180
163181 dataset = xr .Dataset (
164- {"SCIENCE_DATA" : science_xarray },
165- coords = {"met_time" : met_time },
182+ coords = {
183+ "Epoch" : epoch_time ,
184+ "Energy" : energy ,
185+ "Counts" : counts ,
186+ },
187+ attrs = swe_cdf_attrs .swe_l1a_global_attrs .output (),
166188 )
167-
189+ dataset [ "SCIENCE_DATA" ] = science_xarray
168190 dataset ["RAW_SCIENCE_DATA" ] = raw_science_xarray
169191
170192 # create xarray dataset for each metadata field
171193 for key , value in metadata_arrays .items ():
172194 if key == "SHCOARSE" :
173195 continue
196+ # TODO: figure out how to add more descriptive
197+ # description for each metadata field
198+ #
199+ # int_attrs["CATDESC"] = int_attrs["FIELDNAM"] = int_attrs["LABLAXIS"] = key
200+ # # get int32's max since most of metadata is under 32-bits
201+ # int_attrs["VALIDMAX"] = np.iinfo(np.int32).max
202+ # int_attrs["DEPEND_0"] = "Epoch"
174203 dataset [key ] = xr .DataArray (
175204 value ,
176- dims = ["met_time" ],
205+ dims = ["Epoch" ],
206+ attrs = dataclasses .replace (
207+ swe_cdf_attrs .swe_metadata_attrs ,
208+ catdesc = key ,
209+ fieldname = key ,
210+ label_axis = key ,
211+ depend_0 = "Epoch" ,
212+ ).output (),
177213 )
178214
179215 return dataset
0 commit comments