roc-film 1.13.4__py3-none-any.whl → 1.14.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. roc/__init__.py +2 -1
  2. roc/film/__init__.py +2 -2
  3. roc/film/commands.py +372 -323
  4. roc/film/config/__init__.py +0 -1
  5. roc/film/constants.py +101 -65
  6. roc/film/descriptor.json +126 -95
  7. roc/film/exceptions.py +28 -27
  8. roc/film/tasks/__init__.py +16 -16
  9. roc/film/tasks/cat_solo_hk.py +86 -74
  10. roc/film/tasks/cdf_postpro.py +438 -309
  11. roc/film/tasks/check_dds.py +39 -45
  12. roc/film/tasks/db_to_anc_bia_sweep_table.py +381 -0
  13. roc/film/tasks/dds_to_l0.py +232 -180
  14. roc/film/tasks/export_solo_coord.py +147 -0
  15. roc/film/tasks/file_handler.py +91 -75
  16. roc/film/tasks/l0_to_hk.py +117 -103
  17. roc/film/tasks/l0_to_l1_bia_current.py +38 -30
  18. roc/film/tasks/l0_to_l1_bia_sweep.py +417 -329
  19. roc/film/tasks/l0_to_l1_sbm.py +250 -208
  20. roc/film/tasks/l0_to_l1_surv.py +185 -130
  21. roc/film/tasks/make_daily_tm.py +40 -37
  22. roc/film/tasks/merge_tcreport.py +77 -71
  23. roc/film/tasks/merge_tmraw.py +102 -89
  24. roc/film/tasks/parse_dds_xml.py +21 -20
  25. roc/film/tasks/set_l0_utc.py +51 -49
  26. roc/film/tests/cdf_compare.py +565 -0
  27. roc/film/tests/hdf5_compare.py +84 -62
  28. roc/film/tests/test_dds_to_l0.py +93 -51
  29. roc/film/tests/test_dds_to_tc.py +8 -11
  30. roc/film/tests/test_dds_to_tm.py +8 -10
  31. roc/film/tests/test_film.py +161 -116
  32. roc/film/tests/test_l0_to_hk.py +64 -36
  33. roc/film/tests/test_l0_to_l1_bia.py +10 -14
  34. roc/film/tests/test_l0_to_l1_sbm.py +14 -19
  35. roc/film/tests/test_l0_to_l1_surv.py +68 -41
  36. roc/film/tests/test_metadata.py +21 -20
  37. roc/film/tests/tests.py +743 -396
  38. roc/film/tools/__init__.py +5 -5
  39. roc/film/tools/dataset_tasks.py +34 -2
  40. roc/film/tools/file_helpers.py +390 -269
  41. roc/film/tools/l0.py +402 -324
  42. roc/film/tools/metadata.py +147 -127
  43. roc/film/tools/skeleton.py +12 -17
  44. roc/film/tools/tools.py +109 -92
  45. roc/film/tools/xlsx2skt.py +161 -139
  46. {roc_film-1.13.4.dist-info → roc_film-1.14.0.dist-info}/LICENSE +127 -125
  47. roc_film-1.14.0.dist-info/METADATA +60 -0
  48. roc_film-1.14.0.dist-info/RECORD +50 -0
  49. {roc_film-1.13.4.dist-info → roc_film-1.14.0.dist-info}/WHEEL +1 -1
  50. roc/film/tasks/l0_to_anc_bia_sweep_table.py +0 -348
  51. roc_film-1.13.4.dist-info/METADATA +0 -120
  52. roc_film-1.13.4.dist-info/RECORD +0 -48
roc/film/tools/l0.py CHANGED
@@ -9,11 +9,18 @@ from poppy.core.logger import logger
9
9
  from roc.idb.parsers.idb_parser import IDBParser
10
10
  from roc.rpl.constants import VALID_PACKET
11
11
 
12
- from roc.film import L0ProdFailure, MIN_DATETIME, MAX_DATETIME, PACKET_TYPE, TIME_L0_STRFORMAT, TIME_ISO_STRFORMAT
12
+ from roc.film import (
13
+ L0ProdFailure,
14
+ MIN_DATETIME,
15
+ MAX_DATETIME,
16
+ PACKET_TYPE,
17
+ TIME_L0_STRFORMAT,
18
+ TIME_ISO_STRFORMAT,
19
+ )
13
20
  from roc.film.tools.file_helpers import is_packet
14
21
  from roc.film.tools import valid_data_version, Map, decode
15
22
 
16
- __all__ = ['L0']
23
+ __all__ = ["L0"]
17
24
 
18
25
 
19
26
  class L0:
@@ -22,24 +29,30 @@ class L0:
22
29
  # Class attributes
23
30
  h5py_str_dtype = h5py.special_dtype(vlen=str)
24
31
 
25
- l0_file_prefix = 'solo_L0_rpw'
26
-
27
- L0_FIELDS = {'TM': ['utc_time',
28
- 'binary',
29
- 'idb',
30
- 'compressed',
31
- 'data_field_header',
32
- 'packet_header',
33
- 'source_data'],
34
- 'TC': ['utc_time',
35
- 'binary',
36
- 'idb',
37
- 'tc_ack_state',
38
- 'unique_id',
39
- 'sequence_name',
40
- 'packet_header',
41
- 'data_field_header',
42
- 'application_data']}
32
+ l0_file_prefix = "solo_L0_rpw"
33
+
34
+ L0_FIELDS = {
35
+ "TM": [
36
+ "utc_time",
37
+ "binary",
38
+ "idb",
39
+ "compressed",
40
+ "data_field_header",
41
+ "packet_header",
42
+ "source_data",
43
+ ],
44
+ "TC": [
45
+ "utc_time",
46
+ "binary",
47
+ "idb",
48
+ "tc_ack_state",
49
+ "unique_id",
50
+ "sequence_name",
51
+ "packet_header",
52
+ "data_field_header",
53
+ "application_data",
54
+ ],
55
+ }
43
56
 
44
57
  def __init__(self, filepath=None):
45
58
  self.filepath = filepath
@@ -67,7 +80,7 @@ class L0:
67
80
  @staticmethod
68
81
  def extract_header(filepath):
69
82
  if filepath and os.path.isfile(filepath):
70
- with h5py.File(filepath, 'r') as file:
83
+ with h5py.File(filepath, "r") as file:
71
84
  header = {key: val for key, val in file.attrs.items()}
72
85
  else:
73
86
  header = {}
@@ -83,9 +96,9 @@ class L0:
83
96
  :return: data version as a string of the form "XX", where XX are 2 digit integers
84
97
  """
85
98
  try:
86
- return os.path.splitext(os.path.basename(filepath))[0].split('_')[4][1:]
99
+ return os.path.splitext(os.path.basename(filepath))[0].split("_")[4][1:]
87
100
  except Exception:
88
- return ''
101
+ return ""
89
102
 
90
103
  @staticmethod
91
104
  def version_from_header(filepath):
@@ -97,15 +110,13 @@ class L0:
97
110
  :return: data version as a string of the form "XX", where XX are 2 digit integers
98
111
  """
99
112
  try:
100
- with h5py.File(filepath, 'r') as file:
101
- return valid_data_version(file.attrs['Data_version'])
113
+ with h5py.File(filepath, "r") as file:
114
+ return valid_data_version(file.attrs["Data_version"])
102
115
  except Exception:
103
- return ''
116
+ return ""
104
117
 
105
118
  @staticmethod
106
- def to_hdf5(filepath,
107
- packet_parser=None,
108
- metadata={}):
119
+ def to_hdf5(filepath, packet_parser=None, metadata={}):
109
120
  """
110
121
  Given an PacketParser object like and the target on which to put the packets data,
111
122
  generate the L0 HDF5 file in format with all the necessary meta information.
@@ -114,21 +125,21 @@ class L0:
114
125
  """
115
126
 
116
127
  if os.path.isfile(filepath):
117
- action = 'a'
128
+ action = "a"
118
129
  else:
119
- action = 'w'
130
+ action = "w"
120
131
 
121
132
  # Create instance of L0 class
122
133
  l0 = L0()
123
134
 
124
135
  try:
125
136
  with h5py.File(filepath, action) as hdf5:
126
-
127
137
  # Add l0 root metadata
128
138
  for key, val in metadata.items():
129
139
  if key in hdf5.attrs:
130
- logger.debug(f'{key} L0 metadata already defined: '
131
- f'{hdf5.attrs[key]}!')
140
+ logger.debug(
141
+ f"{key} L0 metadata already defined: {hdf5.attrs[key]}!"
142
+ )
132
143
  hdf5.attrs[key] = val
133
144
 
134
145
  # write packets data into the file
@@ -136,11 +147,11 @@ class L0:
136
147
  l0._to_hdf5(hdf5, packet_parser)
137
148
 
138
149
  except Exception:
139
- logger.exception(f'{filepath} production has failed!')
150
+ logger.exception(f"{filepath} production has failed!")
140
151
  raise L0ProdFailure()
141
152
 
142
153
  if not L0.is_l0(filepath):
143
- logger.exception(f'{filepath} not saved correctly!')
154
+ logger.exception(f"{filepath} not saved correctly!")
144
155
  raise L0ProdFailure()
145
156
 
146
157
  return filepath
@@ -156,23 +167,22 @@ class L0:
156
167
 
157
168
  # create a group for TM and an other for TC packets
158
169
  # and initialize counters
159
- if 'TM' not in self.hdf5.keys():
160
- tm = self.hdf5.create_group('TM')
170
+ if "TM" not in self.hdf5.keys():
171
+ tm = self.hdf5.create_group("TM")
161
172
  tm_count = 0
162
173
  else:
163
- tm = self.hdf5['TM']
164
- tm_count = tm.attrs['COUNT']
174
+ tm = self.hdf5["TM"]
175
+ tm_count = tm.attrs["COUNT"]
165
176
 
166
- if 'TC' not in self.hdf5.keys():
167
- tc = self.hdf5.create_group('TC')
177
+ if "TC" not in self.hdf5.keys():
178
+ tc = self.hdf5.create_group("TC")
168
179
  tc_count = 0
169
180
  else:
170
- tc = self.hdf5['TC']
171
- tc_count = tc.attrs['COUNT']
181
+ tc = self.hdf5["TC"]
182
+ tc_count = tc.attrs["COUNT"]
172
183
 
173
184
  # loop over registered packets
174
185
  for packet in packet_parser.packet.manager.instances:
175
-
176
186
  # if the packet is empty do not try to add it
177
187
  # same thing if it is a compressed one
178
188
  if packet.is_compressed or packet.counter == 0:
@@ -182,7 +192,9 @@ class L0:
182
192
  criterion = packet.status == VALID_PACKET
183
193
  new_counter = len(packet.status[criterion])
184
194
  if not packet.counter == new_counter:
185
- logger.warning(f'{packet.name} has {packet.counter - new_counter} invalid packets')
195
+ logger.warning(
196
+ f"{packet.name} has {packet.counter - new_counter} invalid packets"
197
+ )
186
198
  # Loop over packet attributes
187
199
  for key, val in packet.__dict__.items():
188
200
  try:
@@ -195,7 +207,7 @@ class L0:
195
207
  packet.counter = len(packet.status)
196
208
 
197
209
  # send the packet to the good type
198
- logger.debug('Insert {0} into L0 file'.format(packet))
210
+ logger.debug("Insert {0} into L0 file".format(packet))
199
211
  if packet.type == 0:
200
212
  # call the method to store into hdf5 for each packet
201
213
  tm_count += self.packet_to_hdf5(packet, tm)
@@ -204,8 +216,8 @@ class L0:
204
216
  tc_count += self.packet_to_hdf5(packet, tc, tc=True)
205
217
 
206
218
  # Set TM / TC packet counters
207
- tm.attrs['COUNT'] = tm_count
208
- tc.attrs['COUNT'] = tc_count
219
+ tm.attrs["COUNT"] = tm_count
220
+ tc.attrs["COUNT"] = tc_count
209
221
 
210
222
  return tm, tc
211
223
 
@@ -227,85 +239,95 @@ class L0:
227
239
  # Store some metadata of current packet
228
240
  # as H5 datasets in L0 packet group
229
241
  # Mapping dict of the attributes to add
230
- attrs_dict = {'SRDB_ID': (packet.__dict__, 'srdb_id'),
231
- 'PACKET_CATEGORY': (packet.__dict__, 'category')}
242
+ attrs_dict = {
243
+ "SRDB_ID": (packet.__dict__, "srdb_id"),
244
+ "PACKET_CATEGORY": (packet.__dict__, "category"),
245
+ }
232
246
  self.add_packet_attrs(packet, attrs_dict, packet_group)
233
247
 
234
248
  # Store number of packets
235
249
  try:
236
- if 'COUNT' in packet_group.attrs:
237
- packet_count = packet_group.attrs['COUNT']
250
+ if "COUNT" in packet_group.attrs:
251
+ packet_count = packet_group.attrs["COUNT"]
238
252
  else:
239
253
  packet_count = 0
240
254
 
241
- packet_group.attrs['COUNT'] = packet_count + packet.counter
255
+ packet_group.attrs["COUNT"] = packet_count + packet.counter
242
256
  except Exception:
243
- logger.warning(f'No counter found for packet {packet.name}')
257
+ logger.warning(f"No counter found for packet {packet.name}")
244
258
 
245
259
  # packet_header, data_field_header, source_data ou application_data
246
260
 
247
261
  # inside it, create groups for the packet_header,
248
262
  # data_field_header and the source_data/application_data
249
- self._packet_to_hdf5('packet_header', packet.header, packet_group)
250
- self._packet_to_hdf5('data_field_header',
251
- packet.data_header, packet_group)
263
+ self._packet_to_hdf5("packet_header", packet.header, packet_group)
264
+ self._packet_to_hdf5("data_field_header", packet.data_header, packet_group)
252
265
 
253
266
  if tc:
254
- self._packet_to_hdf5('application_data', packet.data, packet_group)
267
+ self._packet_to_hdf5("application_data", packet.data, packet_group)
255
268
 
256
269
  # Add TC specific info:
257
270
  # array of Ack. TC acceptance/execution state
258
- self._packet_to_hdf5('tc_ack_state',
259
- packet.tc_ack_state.astype(
260
- self.h5py_str_dtype),
261
- packet_group)
271
+ self._packet_to_hdf5(
272
+ "tc_ack_state",
273
+ packet.tc_ack_state.astype(self.h5py_str_dtype),
274
+ packet_group,
275
+ )
262
276
 
263
277
  # unique ID as a string
264
- self._packet_to_hdf5('unique_id',
265
- packet.unique_id.astype(self.h5py_str_dtype),
266
- packet_group)
278
+ self._packet_to_hdf5(
279
+ "unique_id", packet.unique_id.astype(self.h5py_str_dtype), packet_group
280
+ )
267
281
 
268
282
  # sequence name ID as a string
269
- self._packet_to_hdf5('sequence_name',
270
- packet.sequence_name.astype(
271
- self.h5py_str_dtype),
272
- packet_group)
283
+ self._packet_to_hdf5(
284
+ "sequence_name",
285
+ packet.sequence_name.astype(self.h5py_str_dtype),
286
+ packet_group,
287
+ )
273
288
 
274
289
  else:
275
- self._packet_to_hdf5('source_data', packet.data, packet_group)
290
+ self._packet_to_hdf5("source_data", packet.data, packet_group)
276
291
 
277
292
  # Add binary
278
- self._packet_to_hdf5('binary',
279
- packet.binary.astype(self.h5py_str_dtype),
280
- packet_group)
293
+ self._packet_to_hdf5(
294
+ "binary", packet.binary.astype(self.h5py_str_dtype), packet_group
295
+ )
281
296
 
282
297
  # Add idb_source and idb_version
283
- self._packet_to_hdf5('idb',
284
- packet.idb.astype(self.h5py_str_dtype),
285
- packet_group)
298
+ self._packet_to_hdf5(
299
+ "idb", packet.idb.astype(self.h5py_str_dtype), packet_group
300
+ )
286
301
 
287
302
  # save utc time as string
288
303
  # Note: datetime64 could be also saved as int64
289
- self._packet_to_hdf5('utc_time',
290
- np.datetime_as_string(packet.utc_time, timezone='UTC').astype(
291
- self.h5py_str_dtype),
292
- packet_group)
304
+ self._packet_to_hdf5(
305
+ "utc_time",
306
+ np.datetime_as_string(packet.utc_time, timezone="UTC").astype(
307
+ self.h5py_str_dtype
308
+ ),
309
+ packet_group,
310
+ )
293
311
 
294
312
  # Save compression status (only if any compressed packet)
295
- if not np.all(packet.compressed == 0) or 'compressed' in packet_group.keys():
296
- self._packet_to_hdf5('compressed',
297
- packet.compressed,
298
- packet_group)
313
+ if not np.all(packet.compressed == 0) or "compressed" in packet_group.keys():
314
+ self._packet_to_hdf5("compressed", packet.compressed, packet_group)
299
315
  # Mapping dict of the attributes to add for compressed packets
300
- packet_name_c = packet.name + '_C'
301
- attrs_dict = {'SRDB_ID_C': (self.packet_parser.palisade_metadata[packet_name_c],
302
- 'srdb_id'),
303
- 'PACKET_CATEGORY_C': (self.packet_parser.palisade_metadata[packet_name_c],
304
- 'packet_category')}
316
+ packet_name_c = packet.name + "_C"
317
+ attrs_dict = {
318
+ "SRDB_ID_C": (
319
+ self.packet_parser.palisade_metadata[packet_name_c],
320
+ "srdb_id",
321
+ ),
322
+ "PACKET_CATEGORY_C": (
323
+ self.packet_parser.palisade_metadata[packet_name_c],
324
+ "packet_category",
325
+ ),
326
+ }
305
327
  self.add_packet_attrs(packet, attrs_dict, packet_group)
306
328
 
307
329
  # Return number of packets
308
- return packet_group.attrs['COUNT']
330
+ return packet_group.attrs["COUNT"]
309
331
 
310
332
  def _packet_to_hdf5(self, name, data, group):
311
333
  """
@@ -337,16 +359,19 @@ class L0:
337
359
  if delta_size > 0:
338
360
  # If delta size is positive, it means that we need to increase
339
361
  # the size of dataset array along axis 1
340
- logger.debug(f'Resizing axis 1 of {name} from {dataset.shape[1]} to {dataset.shape[1] + delta_size}')
362
+ logger.debug(
363
+ f"Resizing axis 1 of {name} from {dataset.shape[1]} to {dataset.shape[1] + delta_size}"
364
+ )
341
365
  dataset.resize(dataset.shape[1] + delta_size, axis=1)
342
366
 
343
367
  # Than save 2D array data
344
- dataset[old_dset_shape[0]:, :data.shape[
345
- 1]] = data[:, :data.shape[1]]
368
+ dataset[old_dset_shape[0] :, : data.shape[1]] = data[
369
+ :, : data.shape[1]
370
+ ]
346
371
 
347
372
  else:
348
373
  # Saving data along axis 0 if dim = 1
349
- dataset[old_dset_shape[0]:] = data[:]
374
+ dataset[old_dset_shape[0] :] = data[:]
350
375
  else:
351
376
  # Else if the dataset does not exist, create it and insert input data
352
377
  # Make sure that dataset is resizable (None == unlimited)
@@ -357,8 +382,9 @@ class L0:
357
382
  maxshape = (None, None)
358
383
 
359
384
  # Create and fill new chunked dataset
360
- dataset = group.create_dataset(name, data.shape, dtype=data.dtype,
361
- maxshape=maxshape, chunks=True)
385
+ dataset = group.create_dataset(
386
+ name, data.shape, dtype=data.dtype, maxshape=maxshape, chunks=True
387
+ )
362
388
  dataset[:] = data
363
389
 
364
390
  # in this case, this is a part of the record array, so treating
@@ -405,7 +431,9 @@ class L0:
405
431
  :param filepath: Path of the file to check
406
432
  :return: True if input file exists and has a valid RPW L0 file name, False otherwise
407
433
  """
408
- return os.path.isfile(filepath) and L0.l0_file_prefix in os.path.basename(filepath)
434
+ return os.path.isfile(filepath) and L0.l0_file_prefix in os.path.basename(
435
+ filepath
436
+ )
409
437
 
410
438
  @staticmethod
411
439
  def set_attr(l0_attrs, metadata):
@@ -421,21 +449,24 @@ class L0:
421
449
 
422
450
  for key, val in metadata.items():
423
451
  if key in l0_attrs:
424
- logger.debug(f'{key} L0 attribute already defined: '
425
- f'Replace by {l0_attrs[key]}')
452
+ logger.debug(
453
+ f"{key} L0 attribute already defined: Replace by {l0_attrs[key]}"
454
+ )
426
455
  l0_attrs[key] = val
427
456
 
428
457
  @staticmethod
429
- def l0_to_packet_list(files,
430
- include=[],
431
- exclude=[],
432
- start_time=MIN_DATETIME,
433
- end_time=MAX_DATETIME,
434
- packet_type=PACKET_TYPE,
435
- no_header=False,
436
- no_data=False,
437
- ascending=True,
438
- to_dataframe=False):
458
+ def l0_to_packet_list(
459
+ files,
460
+ include=[],
461
+ exclude=[],
462
+ start_time=MIN_DATETIME,
463
+ end_time=MAX_DATETIME,
464
+ packet_type=PACKET_TYPE,
465
+ no_header=False,
466
+ no_data=False,
467
+ ascending=True,
468
+ to_dataframe=False,
469
+ ):
439
470
  """
440
471
  Parse list of input RPW L0 files
441
472
  and return list of TM/TC packets
@@ -457,7 +488,6 @@ class L0:
457
488
  import scipy.sparse as sparse
458
489
 
459
490
  def load_param(current_group, current_df):
460
-
461
491
  if not isinstance(current_group, h5py.Group):
462
492
  return False
463
493
 
@@ -476,15 +506,14 @@ class L0:
476
506
  total_sample_num = 0
477
507
  file_num = len(files)
478
508
  for file_idx, file in enumerate(files):
479
-
480
- logger.debug(f'Opening {file}... ({file_idx + 1}/{file_num})')
481
- with h5py.File(file, 'r') as l0:
509
+ logger.debug(f"Opening {file}... ({file_idx + 1}/{file_num})")
510
+ with h5py.File(file, "r") as l0:
482
511
  for current_type in packet_type:
483
512
  for current_packet in l0[current_type].keys():
484
-
485
- if ((current_packet in exclude)
486
- or (include and current_packet not in include)):
487
- logger.debug(f'{current_packet} excluded')
513
+ if (current_packet in exclude) or (
514
+ include and current_packet not in include
515
+ ):
516
+ logger.debug(f"{current_packet} excluded")
488
517
  continue
489
518
  # else:
490
519
  # logger.debug(f'{current_packet} included')
@@ -492,87 +521,108 @@ class L0:
492
521
  # Initialize DataFrame instance for the current packet
493
522
  current_df = pd.DataFrame()
494
523
 
495
- current_times = decode(l0[current_type][
496
- current_packet]['utc_time'][()])
524
+ current_times = decode(
525
+ l0[current_type][current_packet]["utc_time"][()]
526
+ )
497
527
 
498
- current_binary = decode(l0[current_type][
499
- current_packet]['binary'][()])
528
+ current_binary = decode(
529
+ l0[current_type][current_packet]["binary"][()]
530
+ )
500
531
 
501
532
  # Get number of
502
533
  current_nsamp = len(current_times)
503
- current_counter = l0[current_type][
504
- current_packet].attrs['COUNT']
534
+ current_counter = l0[current_type][current_packet].attrs[
535
+ "COUNT"
536
+ ]
505
537
  try:
506
538
  assert current_nsamp == current_counter
507
539
  except Exception:
508
- logger.warning(f'Something goes wrong for {current_packet} COUNT in {file}')
540
+ logger.warning(
541
+ f"Something goes wrong for {current_packet} COUNT in {file}"
542
+ )
509
543
  else:
510
- logger.debug(f'{current_counter} {current_packet} found in {file}')
544
+ logger.debug(
545
+ f"{current_counter} {current_packet} found in {file}"
546
+ )
511
547
 
512
548
  # Store packet utc time values
513
- current_df['utc_time'] = current_times
549
+ current_df["utc_time"] = current_times
514
550
  # Convert utc_time strings into datetime objects
515
- current_df['utc_time'] = current_df['utc_time'].apply(
516
- lambda x: datetime.strptime(x, TIME_L0_STRFORMAT))
551
+ current_df["utc_time"] = current_df["utc_time"].apply(
552
+ lambda x: datetime.strptime(x, TIME_L0_STRFORMAT)
553
+ )
517
554
 
518
555
  # Convert binary hexa packet data to string hexa
519
- current_df['binary'] = current_binary
520
- current_df['palisade_id'] = [
521
- current_packet] * current_nsamp
522
- current_df['srdb_id'] = [l0[current_type][current_packet].attrs[
523
- 'SRDB_ID']] * current_nsamp
524
- current_df['category'] = [l0[current_type][current_packet].attrs[
525
- 'PACKET_CATEGORY']] * current_nsamp
556
+ current_df["binary"] = current_binary
557
+ current_df["palisade_id"] = [current_packet] * current_nsamp
558
+ current_df["srdb_id"] = [
559
+ l0[current_type][current_packet].attrs["SRDB_ID"]
560
+ ] * current_nsamp
561
+ current_df["category"] = [
562
+ l0[current_type][current_packet].attrs["PACKET_CATEGORY"]
563
+ ] * current_nsamp
526
564
 
527
565
  # Get IDB source/version
528
- current_idb = l0[current_type][
529
- current_packet]['idb'][()]
530
- current_df['idb_source'] = decode(current_idb[:, 0])
531
- current_df['idb_version'] = decode(current_idb[:, 1])
566
+ current_idb = l0[current_type][current_packet]["idb"][()]
567
+ current_df["idb_source"] = decode(current_idb[:, 0])
568
+ current_df["idb_version"] = decode(current_idb[:, 1])
532
569
 
533
570
  # Case of compressed TM packets
534
- if 'compressed' in l0[current_type][current_packet].keys():
571
+ if "compressed" in l0[current_type][current_packet].keys():
535
572
  # Add compressed array to the current dataframe
536
- current_df['compressed'] = l0[current_type][
537
- current_packet]['compressed'][()]
573
+ current_df["compressed"] = l0[current_type][current_packet][
574
+ "compressed"
575
+ ][()]
538
576
 
539
577
  # Be sure that compressed TM have the right
540
578
  # PALISADE_ID, SDRB_ID and CATEGORY
541
- where_compressed = (current_df.compressed == '1')
542
- current_df.loc[where_compressed, 'srdb_id'] = l0[current_type][current_packet].attrs[
543
- 'SRDB_ID_C']
544
- current_df.loc[where_compressed, 'category'] = l0[current_type][current_packet].attrs[
545
- 'PACKET_CATEGORY_C']
546
- current_df.loc[where_compressed,
547
- 'palisade_id'] = current_packet + '_C'
548
-
549
- if current_type == 'TM':
550
- data_grp = 'source_data'
551
- elif current_type == 'TC':
552
- data_grp = 'application_data'
553
- current_df['unique_id'] = decode(l0[current_type][
554
- current_packet]['unique_id'][()])
555
- current_df['sequence_name'] = decode(l0[current_type][
556
- current_packet]['sequence_name'][()])
557
- current_tc_state = l0[current_type][
558
- current_packet]['tc_ack_state'][()]
559
- current_df['tc_acc_state'] = decode(current_tc_state[:, 0])
560
- current_df['tc_exe_state'] = decode(current_tc_state[:, 1])
579
+ where_compressed = current_df.compressed == "1"
580
+ current_df.loc[where_compressed, "srdb_id"] = l0[
581
+ current_type
582
+ ][current_packet].attrs["SRDB_ID_C"]
583
+ current_df.loc[where_compressed, "category"] = l0[
584
+ current_type
585
+ ][current_packet].attrs["PACKET_CATEGORY_C"]
586
+ current_df.loc[where_compressed, "palisade_id"] = (
587
+ current_packet + "_C"
588
+ )
589
+
590
+ if current_type == "TM":
591
+ data_grp = "source_data"
592
+ elif current_type == "TC":
593
+ data_grp = "application_data"
594
+ current_df["unique_id"] = decode(
595
+ l0[current_type][current_packet]["unique_id"][()]
596
+ )
597
+ current_df["sequence_name"] = decode(
598
+ l0[current_type][current_packet]["sequence_name"][()]
599
+ )
600
+ current_tc_state = l0[current_type][current_packet][
601
+ "tc_ack_state"
602
+ ][()]
603
+ current_df["tc_acc_state"] = decode(current_tc_state[:, 0])
604
+ current_df["tc_exe_state"] = decode(current_tc_state[:, 1])
561
605
 
562
606
  if not no_header:
563
- load_param(l0[current_type][current_packet][
564
- 'packet_header'], current_df)
565
- load_param(l0[current_type][current_packet][
566
- 'data_field_header'], current_df)
607
+ load_param(
608
+ l0[current_type][current_packet]["packet_header"],
609
+ current_df,
610
+ )
611
+ load_param(
612
+ l0[current_type][current_packet]["data_field_header"],
613
+ current_df,
614
+ )
567
615
 
568
616
  if not no_data:
569
- load_param(l0[current_type][current_packet][
570
- data_grp], current_df)
617
+ load_param(
618
+ l0[current_type][current_packet][data_grp], current_df
619
+ )
571
620
 
572
621
  # Filter by start_time/end_time
573
- current_mask = (current_df['utc_time'] >= start_time)
622
+ current_mask = current_df["utc_time"] >= start_time
574
623
  current_mask = current_mask & (
575
- current_df['utc_time'] <= end_time)
624
+ current_df["utc_time"] <= end_time
625
+ )
576
626
  current_df = current_df.loc[current_mask]
577
627
  # Get actual number of samples
578
628
  current_nsamp = len(current_df.index)
@@ -583,38 +633,42 @@ class L0:
583
633
  if current_packet not in packet_data:
584
634
  packet_data[current_packet] = current_df
585
635
  else:
586
- packet_data[current_packet] = pd.concat([packet_data[
587
- current_packet], current_df])
636
+ packet_data[current_packet] = pd.concat(
637
+ [packet_data[current_packet], current_df]
638
+ )
588
639
 
589
640
  logger.debug(
590
- f'{current_nsamp} samples extracted from {current_packet} (total samples extracted: {total_sample_num})')
641
+ f"{current_nsamp} samples extracted from {current_packet} (total samples extracted: {total_sample_num})"
642
+ )
591
643
 
592
644
  # Free memory
593
645
  current_df = None
594
646
 
595
- logger.info(f'RPW packet loading completed '
596
- f'({total_sample_num} samples extracted)')
647
+ logger.info(
648
+ f"RPW packet loading completed ({total_sample_num} samples extracted)"
649
+ )
597
650
 
598
651
  if to_dataframe:
599
- logger.debug('Return packet data as a Pandas DataFrame object')
652
+ logger.debug("Return packet data as a Pandas DataFrame object")
600
653
  return packet_data
601
654
 
602
- logger.info('Converting to list of RPW packets...')
655
+ logger.info("Converting to list of RPW packets...")
603
656
  packet_list = [None] * total_sample_num
604
657
  counter = 0
605
658
  for key, val in packet_data.items():
606
- current_samples = val.to_dict('Records')
659
+ current_samples = val.to_dict("Records")
607
660
  current_nsamp = len(current_samples)
608
- packet_list[counter:counter + current_nsamp] = current_samples
661
+ packet_list[counter : counter + current_nsamp] = current_samples
609
662
  counter += current_nsamp
610
- perc = '{: .2f}'.format(100.0 * counter / total_sample_num)
611
- logger.debug(f'{current_nsamp} {key} samples added to the packet list ({perc}% completed)')
663
+ perc = "{: .2f}".format(100.0 * counter / total_sample_num)
664
+ logger.debug(
665
+ f"{current_nsamp} {key} samples added to the packet list ({perc}% completed)"
666
+ )
612
667
 
613
668
  # Sort by ascending packet creation times
614
669
  if ascending:
615
- logger.info(
616
- 'Sorting packet list by ascending packet creation time...')
617
- key = 'utc_time'
670
+ logger.info("Sorting packet list by ascending packet creation time...")
671
+ key = "utc_time"
618
672
  sorted_packet_list = sorted(packet_list, key=lambda i: i[key])
619
673
  else:
620
674
  sorted_packet_list = packet_list
@@ -630,20 +684,27 @@ class L0:
630
684
  :return: True if valid, False otherwise
631
685
  """
632
686
 
633
- for mandatory_key in ['palisade_id', 'srdb_id',
634
- 'utc_time', 'binary',
635
- 'category', 'idb_version',
636
- 'idb_source']:
687
+ for mandatory_key in [
688
+ "palisade_id",
689
+ "srdb_id",
690
+ "utc_time",
691
+ "binary",
692
+ "category",
693
+ "idb_version",
694
+ "idb_source",
695
+ ]:
637
696
  if not packet.get(mandatory_key):
638
697
  return False
639
698
 
640
- if packet['palisade_id'].startswith('TM'):
699
+ if packet["palisade_id"].startswith("TM"):
641
700
  pass
642
- elif packet['palisade_id'].startswith('TC'):
643
- for mandatory_key in ['unique_id',
644
- 'sequence_name',
645
- 'tc_acc_state',
646
- 'tc_exe_state']:
701
+ elif packet["palisade_id"].startswith("TC"):
702
+ for mandatory_key in [
703
+ "unique_id",
704
+ "sequence_name",
705
+ "tc_acc_state",
706
+ "tc_exe_state",
707
+ ]:
647
708
  if not packet.get(mandatory_key):
648
709
  return False
649
710
  else:
@@ -652,11 +713,13 @@ class L0:
652
713
  return True
653
714
 
654
715
  @staticmethod
655
- def l0_to_raw(l0_file_list,
656
- expected_packet_list=[],
657
- start_time=None,
658
- end_time=None,
659
- increasing_time=True):
716
+ def l0_to_raw(
717
+ l0_file_list,
718
+ expected_packet_list=[],
719
+ start_time=None,
720
+ end_time=None,
721
+ increasing_time=True,
722
+ ):
660
723
  """
661
724
  Extract packet data from a list of L0 files.
662
725
 
@@ -676,59 +739,63 @@ class L0:
676
739
  l0_file_list = [l0_file_list]
677
740
 
678
741
  if len(l0_file_list) == 0:
679
- logger.warning('Input list of L0 file is empty!')
680
- return {'packet_list': []}
742
+ logger.warning("Input list of L0 file is empty!")
743
+ return {"packet_list": []}
681
744
 
682
745
  # loop over L0 file(s) to get data and save packet data
683
746
  for i, l0_file in enumerate(l0_file_list):
684
- logger.debug(f'Parsing {l0_file}...')
685
- with h5py.File(l0_file, 'r') as l0:
686
-
747
+ logger.debug(f"Parsing {l0_file}...")
748
+ with h5py.File(l0_file, "r") as l0:
687
749
  # Get L0 time minimum/maximum
688
750
  l0_time_min = datetime.strptime(
689
- l0.attrs['TIME_MIN'], TIME_ISO_STRFORMAT)
751
+ l0.attrs["TIME_MIN"], TIME_ISO_STRFORMAT
752
+ )
690
753
  l0_time_max = datetime.strptime(
691
- l0.attrs['TIME_MAX'], TIME_ISO_STRFORMAT)
754
+ l0.attrs["TIME_MAX"], TIME_ISO_STRFORMAT
755
+ )
692
756
  # If start_time/end_time passed, then filter L0 data outside
693
757
  # time range
694
758
  if start_time and l0_time_max < start_time:
695
- logger.info(f'{l0_file} time max. is less than {start_time}, skip it')
759
+ logger.info(
760
+ f"{l0_file} time max. is less than {start_time}, skip it"
761
+ )
696
762
  continue
697
763
 
698
764
  if end_time and l0_time_min > end_time:
699
- logger.info(f'{l0_file} time min. is greater than {end_time}, skip it')
765
+ logger.info(
766
+ f"{l0_file} time min. is greater than {end_time}, skip it"
767
+ )
700
768
  continue
701
769
 
702
- file_id = l0.attrs['File_ID']
703
- creation_date = l0.attrs['Generation_date']
770
+ file_id = l0.attrs["File_ID"]
771
+ creation_date = l0.attrs["Generation_date"]
704
772
 
705
773
  # if expected_packet_list not passed as an input
706
774
  # then load all packets
707
775
  if not expected_packet_list:
708
776
  l0_expected_packet_list = []
709
- if 'TM' in l0.keys():
710
- l0_expected_packet_list.extend(list(l0['TM'].keys()))
711
- if 'TC' in l0.keys():
712
- l0_expected_packet_list.extend(list(l0['TC'].keys()))
777
+ if "TM" in l0.keys():
778
+ l0_expected_packet_list.extend(list(l0["TM"].keys()))
779
+ if "TC" in l0.keys():
780
+ l0_expected_packet_list.extend(list(l0["TC"].keys()))
713
781
  else:
714
782
  l0_expected_packet_list = expected_packet_list
715
783
 
716
784
  # Loop over list of expected packets
717
785
  for expected_packet in l0_expected_packet_list:
718
-
719
- if expected_packet.startswith('TM'):
720
- current_type = 'TM'
721
- current_data_group = 'source_data'
722
- elif expected_packet.startswith('TC'):
723
- current_type = 'TC'
724
- current_data_group = 'application_data'
786
+ if expected_packet.startswith("TM"):
787
+ current_type = "TM"
788
+ current_data_group = "source_data"
789
+ elif expected_packet.startswith("TC"):
790
+ current_type = "TC"
791
+ current_data_group = "application_data"
725
792
  else:
726
- logger.warning(f'Unknown packet type: {expected_packet}')
793
+ logger.warning(f"Unknown packet type: {expected_packet}")
727
794
  continue
728
795
 
729
796
  # Check that packet(s) are found in the present l0 file
730
797
  if not is_packet(expected_packet, l0[current_type]):
731
- logger.debug(f'No {expected_packet} packet found in {l0_file}')
798
+ logger.debug(f"No {expected_packet} packet found in {l0_file}")
732
799
  # if not continue
733
800
  continue
734
801
 
@@ -739,16 +806,16 @@ class L0:
739
806
  current_packet_data = current_packet[current_data_group]
740
807
 
741
808
  # Get list of TC execution UTC times
742
- utc_time_list = decode(current_packet['utc_time'][()])
809
+ utc_time_list = decode(current_packet["utc_time"][()])
743
810
 
744
811
  # Get number of packets
745
812
  current_packet_num = len(utc_time_list)
746
813
 
747
814
  # Loop over packets in l0
748
- logger.debug(f'Extracting {current_packet_num} '
749
- f'{expected_packet} packets...')
815
+ logger.debug(
816
+ f"Extracting {current_packet_num} {expected_packet} packets..."
817
+ )
750
818
  for j, utc_time in enumerate(utc_time_list):
751
-
752
819
  try:
753
820
  # Put current packet parameter values into a
754
821
  # dictionary
@@ -763,93 +830,101 @@ class L0:
763
830
 
764
831
  # Get current packet header
765
832
  current_packet_header = L0.l0_packet_to_dotdict(
766
- l0[current_type][expected_packet]['packet_header'], j)
833
+ l0[current_type][expected_packet]["packet_header"], j
834
+ )
767
835
 
768
836
  # Get current packet data field header
769
837
  current_packet_data_header = L0.l0_packet_to_dotdict(
770
- l0[current_type][expected_packet]['data_field_header'], j)
838
+ l0[current_type][expected_packet]["data_field_header"], j
839
+ )
771
840
 
772
841
  # Compute packet APID
773
- current_apid = IDBParser.compute_apid(current_packet_header['process_id'],
774
- current_packet_header['packet_category'])
842
+ current_apid = IDBParser.compute_apid(
843
+ current_packet_header["process_id"],
844
+ current_packet_header["packet_category"],
845
+ )
775
846
 
776
847
  # Get some packet attributes in L0
777
848
  try:
778
- srdb_id = current_packet.attrs['SRDB_ID']
779
- packet_cat = current_packet.attrs[
780
- 'PACKET_CATEGORY']
849
+ srdb_id = current_packet.attrs["SRDB_ID"]
850
+ packet_cat = current_packet.attrs["PACKET_CATEGORY"]
781
851
  except Exception:
782
- logger.warning(f'Attributes missing in {l0_file}!')
852
+ logger.warning(f"Attributes missing in {l0_file}!")
783
853
  srdb_id = None
784
854
  packet_cat = None
785
855
 
786
856
  # Get compression flag
787
857
  try:
788
- current_compressed = current_packet[
789
- 'compressed'][:]
858
+ current_compressed = current_packet["compressed"][:]
790
859
  except Exception:
791
860
  current_compressed = None
792
861
 
793
862
  # Add current packet parameters to lists
794
863
  # utc_time, name of packet and parameters
795
864
  current_packet_fields = {
796
- 'utc_time': L0.l0_utc_time_to_dt(utc_time),
797
- 'palisade_id': expected_packet,
798
- 'srdb_id': srdb_id,
799
- 'data': parameters,
800
- 'type': current_type,
801
- 'category': packet_cat,
802
- 'binary': decode(current_packet['binary'][j]),
803
- 'idb_source': decode(current_packet['idb'][j][0]),
804
- 'idb_version': decode(current_packet['idb'][j][1]),
805
- 'length': current_packet_header['packet_length'] + 7,
806
- 'apid': current_apid,
807
- 'header': current_packet_header,
808
- 'data_header': current_packet_data_header,
809
- 'compressed': current_compressed,
865
+ "utc_time": L0.l0_utc_time_to_dt(utc_time),
866
+ "palisade_id": expected_packet,
867
+ "srdb_id": srdb_id,
868
+ "data": parameters,
869
+ "type": current_type,
870
+ "category": packet_cat,
871
+ "binary": decode(current_packet["binary"][j]),
872
+ "idb_source": decode(current_packet["idb"][j][0]),
873
+ "idb_version": decode(current_packet["idb"][j][1]),
874
+ "length": current_packet_header["packet_length"] + 7,
875
+ "apid": current_apid,
876
+ "header": current_packet_header,
877
+ "data_header": current_packet_data_header,
878
+ "compressed": current_compressed,
810
879
  }
811
880
 
812
881
  # If TC or TM, add also specific attributes
813
- if current_type == 'TC':
814
- current_packet_fields[
815
- 'unique_id'] = current_packet['unique_id'][j]
816
- current_packet_fields['sequence_name'] = current_packet[
817
- 'sequence_name'][j]
818
- current_packet_fields['ack_acc_state'] = current_packet[
819
- 'tc_ack_state'][j][0]
820
- current_packet_fields['ack_exe_state'] = current_packet[
821
- 'tc_ack_state'][j][1]
822
- elif current_type == 'TM':
823
- current_packet_fields[
824
- 'sync_flag'] = current_packet_data_header['time'][2]
825
- current_packet_fields['obt_time'] = f'1/' \
826
- f"{current_packet_data_header['time'][0]}:" \
882
+ if current_type == "TC":
883
+ current_packet_fields["unique_id"] = current_packet[
884
+ "unique_id"
885
+ ][j]
886
+ current_packet_fields["sequence_name"] = current_packet[
887
+ "sequence_name"
888
+ ][j]
889
+ current_packet_fields["ack_acc_state"] = current_packet[
890
+ "tc_ack_state"
891
+ ][j][0]
892
+ current_packet_fields["ack_exe_state"] = current_packet[
893
+ "tc_ack_state"
894
+ ][j][1]
895
+ elif current_type == "TM":
896
+ current_packet_fields["sync_flag"] = (
897
+ current_packet_data_header["time"][2]
898
+ )
899
+ current_packet_fields["obt_time"] = (
900
+ f"1/"
901
+ f"{current_packet_data_header['time'][0]}:"
827
902
  f"{current_packet_data_header['time'][1]}"
903
+ )
828
904
 
829
905
  output_packet_list.append(current_packet_fields)
830
906
 
831
907
  output_packet_num = len(output_packet_list)
832
908
  if output_packet_num == 0:
833
- logger.info('No packet has been returned')
834
- return {'packet_list': []}
909
+ logger.info("No packet has been returned")
910
+ return {"packet_list": []}
835
911
  else:
836
- logger.debug(f'{output_packet_num} packets returned')
912
+ logger.debug(f"{output_packet_num} packets returned")
837
913
  # Sort list by increasing time
838
914
  if increasing_time:
839
915
  output_packet_list = sorted(
840
- output_packet_list,
841
- key=lambda
842
- k: k['utc_time'])
916
+ output_packet_list, key=lambda k: k["utc_time"]
917
+ )
843
918
 
844
919
  # FIXME - Strange output combining data from one L0
845
920
  # (l0_time_min, l0_time_max, file_id, creation_date)
846
921
  # and for several L0 (packet_list)
847
922
  l0_data = {
848
- 'time_min': l0_time_min,
849
- 'time_max': l0_time_max,
850
- 'file_id': file_id,
851
- 'creation_date': creation_date,
852
- 'packet_list': output_packet_list
923
+ "time_min": l0_time_min,
924
+ "time_max": l0_time_max,
925
+ "file_id": file_id,
926
+ "creation_date": creation_date,
927
+ "packet_list": output_packet_list,
853
928
  }
854
929
 
855
930
  return l0_data
@@ -874,18 +949,19 @@ class L0:
874
949
  l0_file_list = [l0_file_list]
875
950
 
876
951
  if len(l0_file_list) == 0:
877
- logger.warning('Input list of L0 file is empty!')
952
+ logger.warning("Input list of L0 file is empty!")
878
953
  return output_file_list
879
954
 
880
955
  # loop over L0 file(s) to filter by time range
881
956
  for i, l0_file in enumerate(l0_file_list):
882
- with h5py.File(l0_file, 'r') as l0:
883
-
957
+ with h5py.File(l0_file, "r") as l0:
884
958
  # Get L0 time minimum/maximum
885
959
  l0_time_min = datetime.strptime(
886
- l0.attrs['TIME_MIN'], TIME_ISO_STRFORMAT)
960
+ l0.attrs["TIME_MIN"], TIME_ISO_STRFORMAT
961
+ )
887
962
  l0_time_max = datetime.strptime(
888
- l0.attrs['TIME_MAX'], TIME_ISO_STRFORMAT)
963
+ l0.attrs["TIME_MAX"], TIME_ISO_STRFORMAT
964
+ )
889
965
  # If start_time/end_time passed, then filter L0 data outside
890
966
  # time range
891
967
  if start_time and l0_time_max < start_time:
@@ -930,13 +1006,10 @@ class L0:
930
1006
  """
931
1007
  # Nanoseconds not supported by datetime and must removed from input l0
932
1008
  # utc time
933
- return datetime.strptime(decode(l0_utc_time)[:-4] + 'Z',
934
- TIME_ISO_STRFORMAT)
1009
+ return datetime.strptime(decode(l0_utc_time)[:-4] + "Z", TIME_ISO_STRFORMAT)
935
1010
 
936
1011
  @staticmethod
937
- def count_packets(l0_file,
938
- tm=True,
939
- tc=True):
1012
+ def count_packets(l0_file, tm=True, tc=True):
940
1013
  """
941
1014
  Count number of Packet elements in the input RPW L0 file.
942
1015
 
@@ -948,13 +1021,12 @@ class L0:
948
1021
  # Initialize output
949
1022
  packet_num = 0
950
1023
 
951
- with h5py.File(l0_file, 'r') as l0:
952
- tm_num = l0['TM'].attrs['COUNT']
953
- tc_num = l0['TC'].attrs['COUNT']
1024
+ with h5py.File(l0_file, "r") as l0:
1025
+ tm_num = l0["TM"].attrs["COUNT"]
1026
+ tc_num = l0["TC"].attrs["COUNT"]
954
1027
 
955
1028
  if not tm and not tc:
956
- logger.warning(
957
- 'At least tm and/or tc keyword must be set to True')
1029
+ logger.warning("At least tm and/or tc keyword must be set to True")
958
1030
  return packet_num
959
1031
 
960
1032
  if tm:
@@ -965,9 +1037,7 @@ class L0:
965
1037
  return packet_num
966
1038
 
967
1039
  @staticmethod
968
- def order_by_utc(l0_file,
969
- unique=False,
970
- update_time_minmax=False):
1040
+ def order_by_utc(l0_file, unique=False, update_time_minmax=False):
971
1041
  """
972
1042
  Order data in an input RPW L0 HDF5 file
973
1043
  by packet creation UTC times.
@@ -978,6 +1048,7 @@ class L0:
978
1048
  root attributes with actual values.
979
1049
  :return:
980
1050
  """
1051
+
981
1052
  # Internal function to sort a dataset according to input indices
982
1053
  def _sort_dataset(group, item, unique_idx, sorted_idx):
983
1054
  # If not dtype.names, then we have a dataset
@@ -988,15 +1059,14 @@ class L0:
988
1059
  # Only update dataset if no empty data
989
1060
  if current_dataset.shape[0] > 0:
990
1061
  # Extract sorted/unique dataset array
991
- sorted_dataset = (current_dataset[()][unique_idx])[
992
- sorted_idx]
1062
+ sorted_dataset = (current_dataset[()][unique_idx])[sorted_idx]
993
1063
 
994
1064
  # If there duplicate values, then resize L0 HDF5 dataset
995
1065
  if sorted_dataset.shape[0] < current_dataset.shape[0]:
996
- delta_shape = current_dataset.shape[
997
- 0] - sorted_dataset.shape[0]
998
- current_dataset.resize(current_dataset.shape[
999
- 0] - delta_shape, axis=0)
1066
+ delta_shape = current_dataset.shape[0] - sorted_dataset.shape[0]
1067
+ current_dataset.resize(
1068
+ current_dataset.shape[0] - delta_shape, axis=0
1069
+ )
1000
1070
 
1001
1071
  # Then update it with sorted indices
1002
1072
  current_dataset[...] = sorted_dataset
@@ -1007,54 +1077,61 @@ class L0:
1007
1077
  _sort_dataset(group[item], field, unique_idx, sorted_idx)
1008
1078
 
1009
1079
  # Initialize time_min / time_max
1010
- time_min = '9999-12-31T23:59:59.999999999Z'
1011
- time_max = '0000-01-01T00:00:00.000000000Z'
1080
+ time_min = "9999-12-31T23:59:59.999999999Z"
1081
+ time_max = "0000-01-01T00:00:00.000000000Z"
1012
1082
 
1013
1083
  # Open L0 file
1014
- with h5py.File(l0_file, 'a') as l0:
1015
-
1084
+ with h5py.File(l0_file, "a") as l0:
1016
1085
  # Loop over TM/TC groups in L0
1017
- for cat in ['TM', 'TC']:
1086
+ for cat in ["TM", "TC"]:
1018
1087
  # Check that TM/TC group exists
1019
1088
  if cat in l0.keys():
1020
1089
  # Loop over each TM packet in L0
1021
1090
  new_packet_count = []
1022
1091
  for packet_name in l0[cat].keys():
1023
-
1024
1092
  # Get packet utc_time values
1025
- original_utc_time = l0[cat][
1026
- packet_name]['utc_time'][()]
1093
+ original_utc_time = l0[cat][packet_name]["utc_time"][()]
1027
1094
 
1028
1095
  if unique:
1029
1096
  # If unique input keyword is True,
1030
- if cat == 'TM':
1097
+ if cat == "TM":
1031
1098
  # then if TM
1032
1099
  # apply the uniqueness of the tuple (packet,
1033
1100
  # binary) over packets in l0 file
1034
- binary = l0[cat][
1035
- packet_name]['binary'][()]
1101
+ binary = l0[cat][packet_name]["binary"][()]
1036
1102
  binary, unique_idx = np.unique(
1037
- binary, return_index=True)
1103
+ binary, return_index=True
1104
+ )
1038
1105
  utc_time = original_utc_time[unique_idx]
1039
1106
  else:
1040
1107
  # then if TC
1041
1108
  # apply the uniqueness of the tuple (packet,
1042
1109
  # utc_time) over packets in l0 file
1043
1110
  utc_time, unique_idx = np.unique(
1044
- original_utc_time, return_index=True)
1111
+ original_utc_time, return_index=True
1112
+ )
1045
1113
 
1046
1114
  # Update packet COUNT attribute
1047
- l0[cat][packet_name].attrs[
1048
- 'COUNT'] = utc_time.shape[0]
1115
+ l0[cat][packet_name].attrs["COUNT"] = utc_time.shape[0]
1049
1116
  new_packet_count.append(utc_time.shape[0])
1050
1117
 
1051
1118
  else:
1052
1119
  unique_idx = np.arange(original_utc_time.shape[0])
1053
1120
 
1054
- if cat == 'TM' and utc_time.shape[0] != original_utc_time.shape[0]:
1055
- duplicated_times = [item for item, count in collections.Counter(
1056
- original_utc_time).items() if count > 1]
1057
- logger.warning(f'There are duplicated times ({duplicated_times}) for packet {packet_name} in {l0_file}!')
1121
+ if (
1122
+ cat == "TM"
1123
+ and utc_time.shape[0] != original_utc_time.shape[0]
1124
+ ):
1125
+ duplicated_times = [
1126
+ item
1127
+ for item, count in collections.Counter(
1128
+ original_utc_time
1129
+ ).items()
1130
+ if count > 1
1131
+ ]
1132
+ logger.warning(
1133
+ f"There are duplicated times ({duplicated_times}) for packet {packet_name} in {l0_file}!"
1134
+ )
1058
1135
 
1059
1136
  # Code block to get indices of duplicated elements
1060
1137
  # duplicated_indices = []
@@ -1068,7 +1145,8 @@ class L0:
1068
1145
  for item in L0.L0_FIELDS[cat]:
1069
1146
  if item in l0[cat][packet_name].keys():
1070
1147
  _sort_dataset(
1071
- l0[cat][packet_name], item, unique_idx, sorted_idx)
1148
+ l0[cat][packet_name], item, unique_idx, sorted_idx
1149
+ )
1072
1150
 
1073
1151
  if np.min(utc_time):
1074
1152
  time_min = min([decode(np.min(utc_time)), time_min])
@@ -1078,9 +1156,9 @@ class L0:
1078
1156
  # If unique is True, then update the COUNT attribute of
1079
1157
  # TM/TC group
1080
1158
  if unique:
1081
- l0[cat].attrs['COUNT'] = sum(new_packet_count)
1159
+ l0[cat].attrs["COUNT"] = sum(new_packet_count)
1082
1160
 
1083
1161
  if update_time_minmax:
1084
1162
  # Save microsecond resolution
1085
- l0.attrs['TIME_MIN'] = time_min[:-4] + 'Z'
1086
- l0.attrs['TIME_MAX'] = time_max[:-4] + 'Z'
1163
+ l0.attrs["TIME_MIN"] = time_min[:-4] + "Z"
1164
+ l0.attrs["TIME_MAX"] = time_max[:-4] + "Z"