imap-processing 0.16.2__py3-none-any.whl → 0.18.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of imap-processing might be problematic. Click here for more details.

Files changed (110) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/ccsds/excel_to_xtce.py +12 -0
  3. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -6
  4. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +35 -0
  5. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +35 -0
  6. imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +24 -0
  7. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +8 -8
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +1 -1
  9. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +163 -100
  10. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +398 -415
  11. imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +97 -54
  12. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +9 -9
  13. imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +233 -57
  14. imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +16 -90
  15. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +30 -0
  16. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -1
  17. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +19 -0
  18. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +20 -0
  19. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +39 -0
  20. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +168 -0
  21. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +103 -2
  22. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +91 -11
  23. imap_processing/cdf/utils.py +7 -1
  24. imap_processing/cli.py +42 -13
  25. imap_processing/codice/codice_l1a.py +125 -78
  26. imap_processing/codice/codice_l1b.py +1 -1
  27. imap_processing/codice/codice_l2.py +0 -9
  28. imap_processing/codice/constants.py +481 -498
  29. imap_processing/hi/hi_l1a.py +4 -4
  30. imap_processing/hi/hi_l1b.py +2 -2
  31. imap_processing/hi/packet_definitions/TLM_HI_COMBINED_SCI.xml +218 -38
  32. imap_processing/hit/hit_utils.py +2 -2
  33. imap_processing/hit/l0/decom_hit.py +4 -3
  34. imap_processing/hit/l1a/hit_l1a.py +64 -24
  35. imap_processing/hit/l1b/constants.py +5 -0
  36. imap_processing/hit/l1b/hit_l1b.py +18 -16
  37. imap_processing/hit/l2/constants.py +1 -1
  38. imap_processing/hit/l2/hit_l2.py +4 -4
  39. imap_processing/ialirt/constants.py +21 -0
  40. imap_processing/ialirt/generate_coverage.py +188 -0
  41. imap_processing/ialirt/l0/parse_mag.py +62 -5
  42. imap_processing/ialirt/l0/process_swapi.py +1 -1
  43. imap_processing/ialirt/l0/process_swe.py +23 -7
  44. imap_processing/ialirt/utils/constants.py +22 -16
  45. imap_processing/ialirt/utils/create_xarray.py +42 -19
  46. imap_processing/idex/idex_constants.py +8 -5
  47. imap_processing/idex/idex_l2b.py +554 -58
  48. imap_processing/idex/idex_l2c.py +30 -196
  49. imap_processing/lo/l0/lo_apid.py +1 -0
  50. imap_processing/lo/l0/lo_star_sensor.py +48 -0
  51. imap_processing/lo/l1a/lo_l1a.py +74 -30
  52. imap_processing/lo/packet_definitions/lo_xtce.xml +5359 -106
  53. imap_processing/mag/constants.py +1 -0
  54. imap_processing/mag/l0/decom_mag.py +9 -6
  55. imap_processing/mag/l0/mag_l0_data.py +46 -0
  56. imap_processing/mag/l1d/__init__.py +0 -0
  57. imap_processing/mag/l1d/mag_l1d.py +133 -0
  58. imap_processing/mag/l1d/mag_l1d_data.py +588 -0
  59. imap_processing/mag/l2/__init__.py +0 -0
  60. imap_processing/mag/l2/mag_l2.py +25 -20
  61. imap_processing/mag/l2/mag_l2_data.py +191 -130
  62. imap_processing/quality_flags.py +20 -2
  63. imap_processing/spice/geometry.py +25 -3
  64. imap_processing/spice/pointing_frame.py +1 -1
  65. imap_processing/spice/spin.py +4 -0
  66. imap_processing/spice/time.py +51 -0
  67. imap_processing/swapi/l1/swapi_l1.py +12 -2
  68. imap_processing/swapi/l2/swapi_l2.py +59 -14
  69. imap_processing/swapi/swapi_utils.py +1 -1
  70. imap_processing/swe/l1b/swe_l1b.py +11 -4
  71. imap_processing/swe/l2/swe_l2.py +111 -17
  72. imap_processing/ultra/constants.py +49 -1
  73. imap_processing/ultra/l0/decom_tools.py +28 -14
  74. imap_processing/ultra/l0/decom_ultra.py +225 -15
  75. imap_processing/ultra/l0/ultra_utils.py +281 -8
  76. imap_processing/ultra/l1a/ultra_l1a.py +77 -8
  77. imap_processing/ultra/l1b/cullingmask.py +3 -3
  78. imap_processing/ultra/l1b/de.py +53 -15
  79. imap_processing/ultra/l1b/extendedspin.py +26 -2
  80. imap_processing/ultra/l1b/lookup_utils.py +171 -50
  81. imap_processing/ultra/l1b/quality_flag_filters.py +14 -0
  82. imap_processing/ultra/l1b/ultra_l1b_culling.py +198 -5
  83. imap_processing/ultra/l1b/ultra_l1b_extended.py +304 -66
  84. imap_processing/ultra/l1c/helio_pset.py +54 -7
  85. imap_processing/ultra/l1c/spacecraft_pset.py +9 -1
  86. imap_processing/ultra/l1c/ultra_l1c.py +2 -0
  87. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +106 -109
  88. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +3 -3
  89. imap_processing/ultra/utils/ultra_l1_utils.py +13 -1
  90. imap_processing/utils.py +20 -42
  91. {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/METADATA +2 -2
  92. {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/RECORD +95 -103
  93. imap_processing/lo/l0/data_classes/star_sensor.py +0 -98
  94. imap_processing/lo/l0/utils/lo_base.py +0 -57
  95. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +0 -526
  96. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +0 -526
  97. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +0 -526
  98. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +0 -524
  99. imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +0 -32769
  100. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
  101. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
  102. imap_processing/ultra/lookup_tables/dps_grid45_compressed.cdf +0 -0
  103. imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +0 -4097
  104. imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +0 -2050
  105. imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +0 -4097
  106. imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +0 -2050
  107. imap_processing/ultra/lookup_tables/yadjust.csv +0 -257
  108. {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/LICENSE +0 -0
  109. {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/WHEEL +0 -0
  110. {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """Decommutates Ultra CCSDS packets."""
2
2
 
3
3
  import logging
4
+ import math
4
5
  from collections import defaultdict
5
6
  from typing import cast
6
7
 
@@ -15,10 +16,21 @@ from imap_processing.ultra.l0.decom_tools import (
15
16
  read_image_raw_events_binary,
16
17
  )
17
18
  from imap_processing.ultra.l0.ultra_utils import (
19
+ CMD_ECHO_MAP,
20
+ ENERGY_EVENT_FIELD_RANGES,
21
+ ENERGY_RATES_KEYS,
18
22
  EVENT_FIELD_RANGES,
19
23
  RATES_KEYS,
24
+ ULTRA_ENERGY_EVENTS,
25
+ ULTRA_ENERGY_RATES,
26
+ ULTRA_ENERGY_SPECTRA,
27
+ ULTRA_EVENTS,
28
+ ULTRA_PRI_1_EVENTS,
29
+ ULTRA_PRI_2_EVENTS,
30
+ ULTRA_PRI_3_EVENTS,
31
+ ULTRA_PRI_4_EVENTS,
20
32
  ULTRA_RATES,
21
- ULTRA_TOF,
33
+ PacketProperties,
22
34
  )
23
35
  from imap_processing.utils import convert_to_binary_string
24
36
 
@@ -26,7 +38,7 @@ logging.basicConfig(level=logging.INFO)
26
38
  logger = logging.getLogger(__name__)
27
39
 
28
40
 
29
- def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
41
+ def process_ultra_tof(ds: xr.Dataset, packet_props: PacketProperties) -> xr.Dataset:
30
42
  """
31
43
  Unpack and decode Ultra TOF packets.
32
44
 
@@ -34,6 +46,9 @@ def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
34
46
  ----------
35
47
  ds : xarray.Dataset
36
48
  TOF dataset.
49
+ packet_props : PacketProperties
50
+ Information that defines properties of the packet including the pixel window
51
+ dimensions of images and number of image panes.
37
52
 
38
53
  Returns
39
54
  -------
@@ -42,14 +57,35 @@ def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
42
57
  """
43
58
  scalar_keys = [key for key in ds.data_vars if key not in ("packetdata", "sid")]
44
59
 
60
+ image_planes = packet_props.image_planes
61
+ rows = packet_props.pixel_window_rows
62
+ cols = packet_props.pixel_window_columns
63
+ planes_per_packet = packet_props.image_planes_per_packet
64
+
65
+ if (
66
+ image_planes is None
67
+ or rows is None
68
+ or cols is None
69
+ or planes_per_packet is None
70
+ ):
71
+ raise ValueError(
72
+ "Packet properties must specify pixel window dimensions, "
73
+ "width bit, image planes, and image planes per packet for this packet type."
74
+ )
75
+ # Calculate the number of image packets based on the number of image panes and
76
+ # planes per packet.
77
+ # There may be cases where the last packet has fewer planes than the
78
+ # planes_per_packet, to account for this, we use ceiling division.
79
+ num_image_packets = math.ceil(image_planes / planes_per_packet)
80
+
45
81
  decom_data: defaultdict[str, list[np.ndarray]] = defaultdict(list)
46
82
  decom_data["packetdata"] = []
47
83
  valid_epoch = []
48
- width = cast(int, ULTRA_TOF.width)
49
- mantissa_bit_length = cast(int, ULTRA_TOF.mantissa_bit_length)
50
84
 
51
85
  for val, group in ds.groupby("epoch"):
52
- if set(group["sid"].values) >= set(range(8)):
86
+ if set(group["sid"].values) >= set(
87
+ np.arange(0, image_planes, planes_per_packet)
88
+ ):
53
89
  valid_epoch.append(val)
54
90
  group.sortby("sid")
55
91
 
@@ -57,13 +93,12 @@ def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
57
93
  decom_data[key].append(group[key].values)
58
94
 
59
95
  image = []
60
- for i in range(8):
96
+ for i in range(num_image_packets):
61
97
  binary = convert_to_binary_string(group["packetdata"].values[i])
62
98
  decompressed = decompress_image(
63
99
  group["p00"].values[i],
64
100
  binary,
65
- width,
66
- mantissa_bit_length,
101
+ packet_props,
67
102
  )
68
103
  image.append(decompressed)
69
104
 
@@ -76,9 +111,9 @@ def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
76
111
 
77
112
  coords = {
78
113
  "epoch": np.array(valid_epoch, dtype=np.uint64),
79
- "sid": xr.DataArray(np.arange(8), dims=["sid"], name="sid"),
80
- "row": xr.DataArray(np.arange(54), dims=["row"], name="row"),
81
- "column": xr.DataArray(np.arange(180), dims=["column"], name="column"),
114
+ "sid": xr.DataArray(np.arange(num_image_packets), dims=["sid"], name="sid"),
115
+ "row": xr.DataArray(np.arange(rows), dims=["row"], name="row"),
116
+ "column": xr.DataArray(np.arange(cols), dims=["column"], name="column"),
82
117
  }
83
118
 
84
119
  dataset = xr.Dataset(coords=coords)
@@ -136,7 +171,7 @@ def get_event_id(shcoarse: NDArray) -> NDArray:
136
171
  return np.array(event_ids, dtype=np.int64)
137
172
 
138
173
 
139
- def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
174
+ def process_ultra_events(ds: xr.Dataset, apid: int) -> xr.Dataset:
140
175
  """
141
176
  Unpack and decode Ultra EVENTS packets.
142
177
 
@@ -144,12 +179,28 @@ def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
144
179
  ----------
145
180
  ds : xarray.Dataset
146
181
  Events dataset.
182
+ apid : int
183
+ APID of the events dataset.
147
184
 
148
185
  Returns
149
186
  -------
150
187
  ds : xarray.Dataset
151
188
  Dataset containing the decoded and decompressed data.
152
189
  """
190
+ all_event_apids = set(
191
+ ULTRA_EVENTS.apid
192
+ + ULTRA_PRI_1_EVENTS.apid
193
+ + ULTRA_PRI_2_EVENTS.apid
194
+ + ULTRA_PRI_3_EVENTS.apid
195
+ + ULTRA_PRI_4_EVENTS.apid
196
+ )
197
+ if apid in all_event_apids:
198
+ field_ranges = EVENT_FIELD_RANGES
199
+ elif apid in ULTRA_ENERGY_EVENTS.apid:
200
+ field_ranges = ENERGY_EVENT_FIELD_RANGES
201
+ else:
202
+ raise ValueError(f"APID {apid} not recognized for Ultra events processing.")
203
+
153
204
  all_events = []
154
205
  all_indices = []
155
206
 
@@ -160,7 +211,7 @@ def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
160
211
  field: attrs.get_variable_attributes(field).get(
161
212
  "FILLVAL", np.iinfo(np.int64).min
162
213
  )
163
- for field in EVENT_FIELD_RANGES
214
+ for field in field_ranges
164
215
  }
165
216
 
166
217
  counts = ds["count"].values
@@ -173,7 +224,9 @@ def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
173
224
  else:
174
225
  # Here there are multiple images in a single packet,
175
226
  # so we need to loop through each image and decompress it.
176
- event_data_list = read_image_raw_events_binary(eventdata_array[i], count)
227
+ event_data_list = read_image_raw_events_binary(
228
+ eventdata_array[i], count, field_ranges
229
+ )
177
230
  all_events.extend(event_data_list)
178
231
  # Keep track of how many times does the event occurred at this epoch.
179
232
  all_indices.extend([i] * count)
@@ -189,7 +242,7 @@ def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
189
242
  }
190
243
 
191
244
  # Add the event data to the expanded dataset.
192
- for key in EVENT_FIELD_RANGES:
245
+ for key in field_ranges:
193
246
  expanded_data[key] = np.array([event[key] for event in all_events])
194
247
 
195
248
  event_ids = get_event_id(expanded_data["shcoarse"])
@@ -242,3 +295,160 @@ def process_ultra_rates(ds: xr.Dataset) -> xr.Dataset:
242
295
  ds[key] = xr.DataArray(np.array(values), dims=["epoch"])
243
296
 
244
297
  return ds
298
+
299
+
300
+ def process_ultra_energy_rates(ds: xr.Dataset) -> xr.Dataset:
301
+ """
302
+ Unpack and decode Ultra ENERGY RATES packets.
303
+
304
+ Parameters
305
+ ----------
306
+ ds : xarray.Dataset
307
+ Energy rates dataset.
308
+
309
+ Returns
310
+ -------
311
+ dataset : xarray.Dataset
312
+ Dataset containing the decoded and decompressed data.
313
+ """
314
+ decom_data = defaultdict(list)
315
+
316
+ for rate in ds["ratedata"]:
317
+ raw_binary_string = convert_to_binary_string(rate.item())
318
+ decompressed_data = decompress_binary(
319
+ raw_binary_string,
320
+ cast(int, ULTRA_ENERGY_RATES.width),
321
+ cast(int, ULTRA_ENERGY_RATES.block),
322
+ cast(int, ULTRA_ENERGY_RATES.len_array),
323
+ cast(int, ULTRA_ENERGY_RATES.mantissa_bit_length),
324
+ )
325
+
326
+ for index in range(cast(int, ULTRA_ENERGY_RATES.len_array)):
327
+ decom_data[ENERGY_RATES_KEYS[index]].append(decompressed_data[index])
328
+
329
+ for key, values in decom_data.items():
330
+ ds[key] = xr.DataArray(np.array(values), dims=["epoch"])
331
+
332
+ return ds
333
+
334
+
335
+ def process_ultra_energy_spectra(ds: xr.Dataset) -> xr.Dataset:
336
+ """
337
+ Unpack and decode Ultra ENERGY SPECTRA packets.
338
+
339
+ Parameters
340
+ ----------
341
+ ds : xarray.Dataset
342
+ Energy rates dataset.
343
+
344
+ Returns
345
+ -------
346
+ dataset : xarray.Dataset
347
+ Dataset containing the decoded and decompressed data.
348
+ """
349
+ energy_spectra = []
350
+
351
+ for rate in ds["compdata"]:
352
+ raw_binary_string = convert_to_binary_string(rate.item())
353
+ decompressed_data = decompress_binary(
354
+ raw_binary_string,
355
+ cast(int, ULTRA_ENERGY_SPECTRA.width),
356
+ cast(int, ULTRA_ENERGY_SPECTRA.block),
357
+ cast(int, ULTRA_ENERGY_SPECTRA.len_array),
358
+ cast(int, ULTRA_ENERGY_SPECTRA.mantissa_bit_length),
359
+ )
360
+
361
+ energy_spectra.append(decompressed_data)
362
+
363
+ energy_spectra = np.array(energy_spectra)
364
+
365
+ ds["ssd_sum"] = xr.DataArray(
366
+ energy_spectra,
367
+ dims=["epoch", "energyspectrastate"],
368
+ coords={"epoch": ds["epoch"], "energyspectrastate": np.arange(16)},
369
+ )
370
+
371
+ return ds
372
+
373
+
374
+ def process_ultra_cmd_echo(ds: xr.Dataset) -> xr.Dataset:
375
+ """
376
+ Unpack and decode Ultra CMD ECHO packets.
377
+
378
+ Parameters
379
+ ----------
380
+ ds : xarray.Dataset
381
+ Energy rates dataset.
382
+
383
+ Returns
384
+ -------
385
+ dataset : xarray.Dataset
386
+ Dataset containing the decoded and decompressed data.
387
+ """
388
+ descriptions = []
389
+
390
+ fill = 0xFF
391
+ max_len = 10
392
+ arg_array = np.full((len(ds["epoch"]), max_len), fill, dtype=np.uint8)
393
+
394
+ for i, arg in enumerate(ds["args"].values):
395
+ # Converts to the numeric representations of each byte.
396
+ arg_array[i, : len(arg)] = np.frombuffer(arg, dtype=np.uint8)
397
+
398
+ # Default to "FILL" for unlisted values
399
+ for result in ds["result"].values:
400
+ descriptions.append(CMD_ECHO_MAP.get(result, "FILL"))
401
+
402
+ ds["arguments"] = xr.DataArray(
403
+ arg_array,
404
+ dims=["epoch", "arg_index"],
405
+ coords={
406
+ "epoch": ds["epoch"],
407
+ "arg_index": np.arange(10),
408
+ },
409
+ )
410
+
411
+ ds["result_description"] = xr.DataArray(
412
+ np.array(descriptions),
413
+ dims=["epoch"],
414
+ coords={"epoch": ds["epoch"]},
415
+ )
416
+
417
+ ds = ds.drop_vars(["args", "result"])
418
+
419
+ return ds
420
+
421
+
422
+ def process_ultra_macros_checksum(ds: xr.Dataset) -> xr.Dataset:
423
+ """
424
+ Unpack and decode Ultra MACROS CHECKSUM packets.
425
+
426
+ Parameters
427
+ ----------
428
+ ds : xarray.Dataset
429
+ Dataset containing macro checksums.
430
+
431
+ Returns
432
+ -------
433
+ dataset : xarray.Dataset
434
+ Dataset with unpacked and decoded checksum values.
435
+ """
436
+ # big endian uint16
437
+ packed_dtype = np.dtype(">u2")
438
+ fill = np.iinfo(packed_dtype).max
439
+ n_epochs = ds.sizes["epoch"]
440
+ max_len = 256
441
+
442
+ checksum_array = np.full((n_epochs, max_len), fill)
443
+
444
+ for i, checksum in enumerate(ds["checksums"]):
445
+ checksum_array[i, :] = np.frombuffer(checksum.item(), dtype=packed_dtype)
446
+
447
+ ds["checksum"] = xr.DataArray(
448
+ checksum_array,
449
+ dims=["epoch", "checksum_index"],
450
+ coords={"epoch": ds["epoch"], "checksum_index": np.arange(max_len)},
451
+ )
452
+ ds = ds.drop_vars(["checksums"])
453
+
454
+ return ds