imap-processing 0.12.0__py3-none-any.whl → 0.13.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 (272) hide show
  1. imap_processing/__init__.py +1 -0
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +1 -2
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -12
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +569 -0
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +5 -5
  9. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +20 -1
  10. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  11. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  12. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -0
  13. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  14. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +16 -0
  15. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +178 -5
  16. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -19
  18. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +8 -48
  19. imap_processing/cdf/utils.py +41 -33
  20. imap_processing/cli.py +463 -234
  21. imap_processing/codice/codice_l1a.py +260 -47
  22. imap_processing/codice/codice_l1b.py +51 -152
  23. imap_processing/codice/constants.py +38 -1
  24. imap_processing/ena_maps/ena_maps.py +658 -65
  25. imap_processing/ena_maps/utils/coordinates.py +1 -1
  26. imap_processing/ena_maps/utils/spatial_utils.py +10 -5
  27. imap_processing/glows/l1a/glows_l1a.py +28 -99
  28. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  29. imap_processing/glows/l1b/glows_l1b.py +1 -4
  30. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  31. imap_processing/glows/l2/glows_l2.py +2 -5
  32. imap_processing/hi/l1a/hi_l1a.py +31 -12
  33. imap_processing/hi/l1b/hi_l1b.py +80 -43
  34. imap_processing/hi/l1c/hi_l1c.py +12 -16
  35. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  36. imap_processing/hit/hit_utils.py +93 -35
  37. imap_processing/hit/l0/decom_hit.py +3 -1
  38. imap_processing/hit/l1a/hit_l1a.py +30 -25
  39. imap_processing/hit/l1b/constants.py +6 -2
  40. imap_processing/hit/l1b/hit_l1b.py +279 -318
  41. imap_processing/hit/l2/constants.py +37 -0
  42. imap_processing/hit/l2/hit_l2.py +373 -264
  43. imap_processing/ialirt/l0/parse_mag.py +138 -10
  44. imap_processing/ialirt/l0/process_swapi.py +69 -0
  45. imap_processing/ialirt/l0/process_swe.py +318 -22
  46. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -212
  47. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  48. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  49. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  50. imap_processing/ialirt/utils/grouping.py +1 -1
  51. imap_processing/idex/idex_constants.py +9 -1
  52. imap_processing/idex/idex_l0.py +22 -8
  53. imap_processing/idex/idex_l1a.py +75 -44
  54. imap_processing/idex/idex_l1b.py +9 -8
  55. imap_processing/idex/idex_l2a.py +79 -45
  56. imap_processing/idex/idex_l2b.py +120 -0
  57. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -39
  58. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  59. imap_processing/lo/l0/lo_science.py +1 -2
  60. imap_processing/lo/l1a/lo_l1a.py +1 -4
  61. imap_processing/lo/l1b/lo_l1b.py +527 -6
  62. imap_processing/lo/l1b/tof_conversions.py +11 -0
  63. imap_processing/lo/l1c/lo_l1c.py +1 -4
  64. imap_processing/mag/constants.py +43 -0
  65. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  66. imap_processing/mag/l1a/mag_l1a.py +2 -9
  67. imap_processing/mag/l1a/mag_l1a_data.py +10 -10
  68. imap_processing/mag/l1b/mag_l1b.py +84 -17
  69. imap_processing/mag/l1c/interpolation_methods.py +180 -3
  70. imap_processing/mag/l1c/mag_l1c.py +236 -70
  71. imap_processing/mag/l2/mag_l2.py +140 -0
  72. imap_processing/mag/l2/mag_l2_data.py +288 -0
  73. imap_processing/spacecraft/quaternions.py +1 -3
  74. imap_processing/spice/geometry.py +3 -3
  75. imap_processing/spice/kernels.py +0 -276
  76. imap_processing/spice/pointing_frame.py +257 -0
  77. imap_processing/spice/repoint.py +48 -19
  78. imap_processing/spice/spin.py +38 -33
  79. imap_processing/spice/time.py +24 -0
  80. imap_processing/swapi/l1/swapi_l1.py +16 -12
  81. imap_processing/swapi/l2/swapi_l2.py +116 -4
  82. imap_processing/swapi/swapi_utils.py +32 -0
  83. imap_processing/swe/l1a/swe_l1a.py +2 -9
  84. imap_processing/swe/l1a/swe_science.py +8 -11
  85. imap_processing/swe/l1b/swe_l1b.py +898 -23
  86. imap_processing/swe/l2/swe_l2.py +21 -77
  87. imap_processing/swe/utils/swe_constants.py +1 -0
  88. imap_processing/tests/ccsds/test_excel_to_xtce.py +1 -1
  89. imap_processing/tests/cdf/test_utils.py +14 -16
  90. imap_processing/tests/codice/conftest.py +44 -33
  91. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  92. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  93. imap_processing/tests/codice/test_codice_l1a.py +20 -11
  94. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  95. imap_processing/tests/conftest.py +78 -22
  96. imap_processing/tests/ena_maps/test_ena_maps.py +462 -33
  97. imap_processing/tests/ena_maps/test_spatial_utils.py +1 -1
  98. imap_processing/tests/glows/conftest.py +10 -14
  99. imap_processing/tests/glows/test_glows_decom.py +4 -4
  100. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  101. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  102. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  103. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  104. imap_processing/tests/glows/test_glows_l2.py +2 -8
  105. imap_processing/tests/hi/conftest.py +1 -1
  106. imap_processing/tests/hi/test_hi_l1b.py +10 -12
  107. imap_processing/tests/hi/test_hi_l1c.py +27 -24
  108. imap_processing/tests/hi/test_l1a.py +7 -9
  109. imap_processing/tests/hi/test_science_direct_event.py +2 -2
  110. imap_processing/tests/hit/helpers/l1_validation.py +44 -43
  111. imap_processing/tests/hit/test_decom_hit.py +1 -1
  112. imap_processing/tests/hit/test_hit_l1a.py +9 -9
  113. imap_processing/tests/hit/test_hit_l1b.py +172 -217
  114. imap_processing/tests/hit/test_hit_l2.py +380 -118
  115. imap_processing/tests/hit/test_hit_utils.py +122 -55
  116. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  117. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  118. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  119. imap_processing/tests/ialirt/unit/test_grouping.py +2 -2
  120. imap_processing/tests/ialirt/unit/test_parse_mag.py +71 -16
  121. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  122. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  123. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  124. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  125. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  126. imap_processing/tests/ialirt/unit/test_process_swe.py +115 -7
  127. imap_processing/tests/idex/conftest.py +72 -7
  128. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  129. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  130. imap_processing/tests/idex/test_idex_l0.py +33 -11
  131. imap_processing/tests/idex/test_idex_l1a.py +50 -23
  132. imap_processing/tests/idex/test_idex_l1b.py +104 -25
  133. imap_processing/tests/idex/test_idex_l2a.py +48 -32
  134. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  135. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  136. imap_processing/tests/lo/test_lo_l1b.py +371 -6
  137. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  138. imap_processing/tests/lo/test_lo_science.py +6 -7
  139. imap_processing/tests/lo/test_star_sensor.py +1 -1
  140. imap_processing/tests/mag/conftest.py +58 -9
  141. imap_processing/tests/mag/test_mag_decom.py +4 -3
  142. imap_processing/tests/mag/test_mag_l1a.py +13 -7
  143. imap_processing/tests/mag/test_mag_l1b.py +9 -9
  144. imap_processing/tests/mag/test_mag_l1c.py +151 -47
  145. imap_processing/tests/mag/test_mag_l2.py +130 -0
  146. imap_processing/tests/mag/test_mag_validation.py +144 -7
  147. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  148. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  149. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  150. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  151. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  152. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  153. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  154. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  155. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  156. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  157. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  158. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  159. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  160. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  161. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  162. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  163. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  164. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  165. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  166. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  167. imap_processing/tests/spacecraft/test_quaternions.py +1 -1
  168. imap_processing/tests/spice/test_data/fake_repoint_data.csv +4 -4
  169. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  170. imap_processing/tests/spice/test_geometry.py +3 -3
  171. imap_processing/tests/spice/test_kernels.py +1 -200
  172. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  173. imap_processing/tests/spice/test_repoint.py +20 -10
  174. imap_processing/tests/spice/test_spin.py +50 -9
  175. imap_processing/tests/spice/test_time.py +14 -0
  176. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  177. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  178. imap_processing/tests/swapi/test_swapi_l1.py +7 -9
  179. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  180. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  181. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  182. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  183. imap_processing/tests/swe/test_swe_l1a.py +6 -6
  184. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  185. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  186. imap_processing/tests/swe/test_swe_l2.py +82 -102
  187. imap_processing/tests/test_cli.py +171 -88
  188. imap_processing/tests/test_utils.py +2 -1
  189. imap_processing/tests/ultra/data/mock_data.py +49 -21
  190. imap_processing/tests/ultra/unit/conftest.py +53 -70
  191. imap_processing/tests/ultra/unit/test_badtimes.py +2 -4
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -6
  193. imap_processing/tests/ultra/unit/test_de.py +3 -10
  194. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  195. imap_processing/tests/ultra/unit/test_decom_apid_881.py +15 -16
  196. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  197. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  198. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  199. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +3 -4
  200. imap_processing/tests/ultra/unit/test_ultra_l1a.py +84 -307
  201. imap_processing/tests/ultra/unit/test_ultra_l1b.py +30 -12
  202. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  203. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +4 -1
  204. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +163 -29
  205. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  206. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +32 -43
  207. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  208. imap_processing/ultra/constants.py +1 -1
  209. imap_processing/ultra/l0/decom_tools.py +21 -34
  210. imap_processing/ultra/l0/decom_ultra.py +168 -204
  211. imap_processing/ultra/l0/ultra_utils.py +152 -136
  212. imap_processing/ultra/l1a/ultra_l1a.py +55 -243
  213. imap_processing/ultra/l1b/badtimes.py +1 -4
  214. imap_processing/ultra/l1b/cullingmask.py +2 -6
  215. imap_processing/ultra/l1b/de.py +62 -47
  216. imap_processing/ultra/l1b/extendedspin.py +8 -4
  217. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  218. imap_processing/ultra/l1b/ultra_l1b.py +3 -8
  219. imap_processing/ultra/l1b/ultra_l1b_culling.py +4 -4
  220. imap_processing/ultra/l1b/ultra_l1b_extended.py +236 -78
  221. imap_processing/ultra/l1c/histogram.py +2 -6
  222. imap_processing/ultra/l1c/spacecraft_pset.py +2 -4
  223. imap_processing/ultra/l1c/ultra_l1c.py +1 -5
  224. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +107 -60
  225. imap_processing/ultra/l2/ultra_l2.py +299 -0
  226. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  227. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  228. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  229. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  230. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  231. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  232. imap_processing/ultra/packet_definitions/README.md +38 -0
  233. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  234. imap_processing/ultra/utils/ultra_l1_utils.py +13 -12
  235. imap_processing/utils.py +1 -1
  236. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +3 -2
  237. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/RECORD +264 -225
  238. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  239. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +0 -6
  240. imap_processing/mag/l1b/__init__.py +0 -0
  241. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  242. imap_processing/swe/l1b/swe_l1b_science.py +0 -699
  243. imap_processing/tests/swe/test_swe_l1b_science.py +0 -103
  244. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  245. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  246. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  247. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  248. /imap_processing/tests/ialirt/{test_data → data}/l0/461971383-404.bin +0 -0
  249. /imap_processing/tests/ialirt/{test_data → data}/l0/461971384-405.bin +0 -0
  250. /imap_processing/tests/ialirt/{test_data → data}/l0/461971385-406.bin +0 -0
  251. /imap_processing/tests/ialirt/{test_data → data}/l0/461971386-407.bin +0 -0
  252. /imap_processing/tests/ialirt/{test_data → data}/l0/461971387-408.bin +0 -0
  253. /imap_processing/tests/ialirt/{test_data → data}/l0/461971388-409.bin +0 -0
  254. /imap_processing/tests/ialirt/{test_data → data}/l0/461971389-410.bin +0 -0
  255. /imap_processing/tests/ialirt/{test_data → data}/l0/461971390-411.bin +0 -0
  256. /imap_processing/tests/ialirt/{test_data → data}/l0/461971391-412.bin +0 -0
  257. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  258. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  259. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  260. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  261. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  262. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  263. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  264. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  265. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  266. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  267. /imap_processing/tests/ialirt/{test_data → data}/l0/sample_decoded_i-alirt_data.csv +0 -0
  268. /imap_processing/tests/mag/validation/{imap_calibration_mag_20240229_v01.cdf → calibration/imap_mag_l1b-calibration_20240229_v001.cdf} +0 -0
  269. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  270. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  271. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  272. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -1,280 +1,244 @@
1
1
  """Decommutates Ultra CCSDS packets."""
2
2
 
3
- import collections
4
3
  import logging
5
4
  from collections import defaultdict
6
- from typing import Any, Union
5
+ from typing import cast
7
6
 
8
7
  import numpy as np
9
- from space_packet_parser import packets
8
+ import xarray as xr
9
+ from numpy.typing import NDArray
10
10
 
11
- from imap_processing.ccsds.ccsds_data import CcsdsData
11
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
12
12
  from imap_processing.ultra.l0.decom_tools import (
13
13
  decompress_binary,
14
14
  decompress_image,
15
15
  read_image_raw_events_binary,
16
16
  )
17
17
  from imap_processing.ultra.l0.ultra_utils import (
18
+ EVENT_FIELD_RANGES,
18
19
  RATES_KEYS,
19
- ULTRA_AUX,
20
- ULTRA_EVENTS,
21
20
  ULTRA_RATES,
22
21
  ULTRA_TOF,
23
- append_ccsds_fields,
24
22
  )
25
- from imap_processing.utils import convert_to_binary_string, sort_by_time
23
+ from imap_processing.utils import convert_to_binary_string
26
24
 
27
25
  logging.basicConfig(level=logging.INFO)
28
26
  logger = logging.getLogger(__name__)
29
27
 
30
28
 
31
- def append_tof_params(
32
- decom_data: dict,
33
- packet: packets.CCSDSPacket,
34
- decompressed_data: np.ndarray,
35
- data_dict: dict,
36
- stacked_dict: dict,
37
- ) -> None:
29
+ def process_ultra_tof(ds: xr.Dataset) -> xr.Dataset:
38
30
  """
39
- Append parsed items to a dictionary, including decompressed data if available.
31
+ Unpack and decode Ultra TOF packets.
40
32
 
41
33
  Parameters
42
34
  ----------
43
- decom_data : dict
44
- Dictionary to which the data is appended.
45
- packet : space_packet_parser.packets.CCSDSPacket
46
- Individual packet.
47
- decompressed_data : list
48
- Data that has been decompressed.
49
- data_dict : dict
50
- Dictionary used for stacking in SID dimension.
51
- stacked_dict : dict
52
- Dictionary used for stacking in time dimension.
53
- """
54
- # TODO: add error handling to make certain every timestamp has 8 SID values
55
-
56
- for key in packet.user_data.keys():
57
- # Keep appending packet data until SID = 7
58
- if key == "PACKETDATA":
59
- data_dict[key].append(decompressed_data)
60
- # Keep appending all other data until SID = 7
61
- else:
62
- data_dict[key].append(packet[key])
63
-
64
- # Append CCSDS fields to the dictionary
65
- ccsds_data = CcsdsData(packet.header)
66
- append_ccsds_fields(data_dict, ccsds_data)
67
-
68
- # Once "SID" reaches 7, we have all the images and data for the single timestamp
69
- if packet["SID"] == 7:
70
- decom_data["SHCOARSE"].extend(list(set(data_dict["SHCOARSE"])))
71
- data_dict["SHCOARSE"].clear()
35
+ ds : xarray.Dataset
36
+ TOF dataset.
72
37
 
73
- for key in packet.user_data.keys():
74
- if key != "SHCOARSE":
75
- stacked_dict[key].append(np.stack(data_dict[key]))
76
- data_dict[key].clear()
77
- for key in packet.header.keys():
78
- stacked_dict[key].append(np.stack(data_dict[key]))
79
- data_dict[key].clear()
38
+ Returns
39
+ -------
40
+ dataset : xarray.Dataset
41
+ Dataset containing the decoded and decompressed data.
42
+ """
43
+ scalar_keys = [key for key in ds.data_vars if key not in ("packetdata", "sid")]
44
+
45
+ decom_data: defaultdict[str, list[np.ndarray]] = defaultdict(list)
46
+ decom_data["packetdata"] = []
47
+ valid_epoch = []
48
+ width = cast(int, ULTRA_TOF.width)
49
+ mantissa_bit_length = cast(int, ULTRA_TOF.mantissa_bit_length)
50
+
51
+ for val, group in ds.groupby("epoch"):
52
+ if set(group["sid"].values) >= set(range(8)):
53
+ valid_epoch.append(val)
54
+ group.sortby("sid")
55
+
56
+ for key in scalar_keys:
57
+ decom_data[key].append(group[key].values)
58
+
59
+ image = []
60
+ for i in range(8):
61
+ binary = convert_to_binary_string(group["packetdata"].values[i])
62
+ decompressed = decompress_image(
63
+ group["p00"].values[i],
64
+ binary,
65
+ width,
66
+ mantissa_bit_length,
67
+ )
68
+ image.append(decompressed)
69
+
70
+ decom_data["packetdata"].append(np.stack(image))
71
+
72
+ for key in scalar_keys:
73
+ decom_data[key] = np.stack(decom_data[key])
74
+
75
+ decom_data["packetdata"] = np.stack(decom_data["packetdata"])
76
+
77
+ coords = {
78
+ "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"),
82
+ }
80
83
 
84
+ dataset = xr.Dataset(coords=coords)
81
85
 
82
- def append_params(decom_data: dict, packet: packets.CCSDSPacket) -> None:
83
- # Todo Update what packet type is.
84
- """
85
- Append parsed items to a dictionary, including decompressed data if available.
86
+ # Add scalar keys (2D: epoch x sid)
87
+ for key in scalar_keys:
88
+ dataset[key] = xr.DataArray(
89
+ decom_data[key],
90
+ dims=["epoch", "sid"],
91
+ )
86
92
 
87
- Parameters
88
- ----------
89
- decom_data : dict
90
- Dictionary to which the data is appended.
91
- packet : space_packet_parser.packets.CCSDSPacket
92
- Individual packet.
93
- """
94
- for key, value in packet.user_data.items():
95
- decom_data[key].append(value)
93
+ # Add PACKETDATA (4D: epoch x sid x row x column)
94
+ dataset["packetdata"] = xr.DataArray(
95
+ decom_data["packetdata"],
96
+ dims=["epoch", "sid", "row", "column"],
97
+ )
96
98
 
97
- ccsds_data = CcsdsData(packet.header)
98
- append_ccsds_fields(decom_data, ccsds_data)
99
+ return dataset
99
100
 
100
101
 
101
- def process_ultra_apids(data: list, apid: int) -> Union[dict[Any, Any], bool]:
102
+ def get_event_id(shcoarse: NDArray) -> NDArray:
102
103
  """
103
- Unpack and decode Ultra packets using CCSDS format and XTCE packet definitions.
104
+ Get unique event IDs using data from events packets.
104
105
 
105
106
  Parameters
106
107
  ----------
107
- data : list
108
- Grouped data.
109
- apid : int
110
- The APID to process.
108
+ shcoarse : numpy.ndarray
109
+ SHCOARSE (MET).
111
110
 
112
111
  Returns
113
112
  -------
114
- decom_data : dict
115
- A dictionary containing the decoded data.
113
+ event_ids : numpy.ndarray
114
+ Ultra events data with calculated unique event IDs as 64-bit integers.
116
115
  """
117
- # Strategy dict maps APIDs to their respective processing functions
118
- strategy_dict = {
119
- ULTRA_TOF.apid[0]: process_ultra_tof,
120
- ULTRA_EVENTS.apid[0]: process_ultra_events,
121
- ULTRA_AUX.apid[0]: process_ultra_aux,
122
- ULTRA_RATES.apid[0]: process_ultra_rates,
123
- }
116
+ event_ids = []
117
+ packet_counters = {}
124
118
 
125
- sorted_packets = sort_by_time(data, "SHCOARSE")
119
+ for met in shcoarse:
120
+ # Initialize the counter for a new packet (MET value)
121
+ if met not in packet_counters:
122
+ packet_counters[met] = 0
123
+ else:
124
+ packet_counters[met] += 1
126
125
 
127
- process_function = strategy_dict.get(apid, lambda *args: False)
128
- decom_data = process_function(sorted_packets, defaultdict(list))
126
+ # Left shift SHCOARSE (u32) by 31 bits, to make room for our event counters
127
+ # (31 rather than 32 to keep it positive in the int64 representation)
128
+ # Append the current number of events in this packet to the right-most bits
129
+ # This makes each event a unique value including the MET and event number
130
+ # in the packet
131
+ # NOTE: CDF does not allow for uint64 values,
132
+ # so we use int64 representation here
133
+ event_id = (np.int64(met) << np.int64(31)) | np.int64(packet_counters[met])
134
+ event_ids.append(event_id)
129
135
 
130
- return decom_data
136
+ return np.array(event_ids, dtype=np.int64)
131
137
 
132
138
 
133
- def process_ultra_tof(
134
- sorted_packets: list, decom_data: collections.defaultdict
135
- ) -> dict:
139
+ def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
136
140
  """
137
- Unpack and decode Ultra TOF packets.
141
+ Unpack and decode Ultra EVENTS packets.
138
142
 
139
143
  Parameters
140
144
  ----------
141
- sorted_packets : list
142
- TOF packets sorted by time.
143
- decom_data : collections.defaultdict
144
- Empty dictionary.
145
+ ds : xarray.Dataset
146
+ Events dataset.
145
147
 
146
148
  Returns
147
149
  -------
148
- decom_data : dict
149
- A dictionary containing the decoded data.
150
+ ds : xarray.Dataset
151
+ Dataset containing the decoded and decompressed data.
150
152
  """
151
- stacked_dict: dict = defaultdict(list)
152
- data_dict: dict = defaultdict(list)
153
+ all_events = []
154
+ all_indices = []
153
155
 
154
- # For TOF we need to sort by time and then SID
155
- sorted_packets = sorted(
156
- sorted_packets,
157
- key=lambda x: (x["SHCOARSE"].raw_value, x["SID"].raw_value),
158
- )
159
- if isinstance(ULTRA_TOF.mantissa_bit_length, int) and isinstance(
160
- ULTRA_TOF.width, int
161
- ):
162
- for packet in sorted_packets:
163
- binary_data = convert_to_binary_string(packet["PACKETDATA"])
164
- # Decompress the image data
165
- decompressed_data = decompress_image(
166
- packet["P00"],
167
- binary_data,
168
- ULTRA_TOF.width,
169
- ULTRA_TOF.mantissa_bit_length,
170
- )
171
-
172
- # Append the decompressed data and other derived data
173
- # to the dictionary
174
- append_tof_params(
175
- decom_data,
176
- packet,
177
- decompressed_data=decompressed_data,
178
- data_dict=data_dict,
179
- stacked_dict=stacked_dict,
180
- )
181
-
182
- # Stack the data to create required dimensions
183
- for key in stacked_dict.keys():
184
- decom_data[key] = np.stack(stacked_dict[key])
185
-
186
- return decom_data
187
-
188
-
189
- def process_ultra_events(sorted_packets: list, decom_data: dict) -> dict:
190
- """
191
- Unpack and decode Ultra EVENTS packets.
156
+ attrs = ImapCdfAttributes()
157
+ attrs.add_instrument_variable_attrs("ultra", level="l1a")
192
158
 
193
- Parameters
194
- ----------
195
- sorted_packets : list
196
- EVENTS packets sorted by time.
197
- decom_data : collections.defaultdict
198
- Empty dictionary.
159
+ empty_event = {
160
+ field: attrs.get_variable_attributes(field).get(
161
+ "FILLVAL", np.iinfo(np.int64).min
162
+ )
163
+ for field in EVENT_FIELD_RANGES
164
+ }
199
165
 
200
- Returns
201
- -------
202
- decom_data : dict
203
- A dictionary containing the decoded data.
204
- """
205
- for packet in sorted_packets:
206
- # Here there are multiple images in a single packet,
207
- # so we need to loop through each image and decompress it.
208
- decom_data = read_image_raw_events_binary(packet, decom_data)
209
- count = packet["COUNT"]
166
+ counts = ds["count"].values
167
+ eventdata_array = ds["eventdata"].values
210
168
 
169
+ for i, count in enumerate(counts):
211
170
  if count == 0:
212
- append_params(decom_data, packet)
171
+ all_events.append(empty_event)
172
+ all_indices.append(i)
213
173
  else:
214
- for i in range(count):
215
- logging.info(f"Appending image #{i}")
216
- append_params(decom_data, packet)
217
-
218
- return decom_data
174
+ # Here there are multiple images in a single packet,
175
+ # so we need to loop through each image and decompress it.
176
+ event_data_list = read_image_raw_events_binary(eventdata_array[i], count)
177
+ all_events.extend(event_data_list)
178
+ # Keep track of how many times does the event occurred at this epoch.
179
+ all_indices.extend([i] * count)
180
+
181
+ # Now we have the event data, we need to create the xarray dataset.
182
+ # We cannot append to the existing dataset (sorted_packets)
183
+ # because there are multiple events for each epoch.
184
+ idx = np.array(all_indices)
185
+
186
+ # Expand the existing dataset so that it is the same length as the event data.
187
+ expanded_data = {
188
+ var: ds[var].values[idx] for var in ds.data_vars if var != "eventdata"
189
+ }
219
190
 
191
+ # Add the event data to the expanded dataset.
192
+ for key in event_data_list[0]:
193
+ expanded_data[key] = np.array([event[key] for event in all_events])
220
194
 
221
- def process_ultra_aux(sorted_packets: list, decom_data: dict) -> dict:
222
- """
223
- Unpack and decode Ultra AUX packets.
195
+ event_ids = get_event_id(expanded_data["shcoarse"])
224
196
 
225
- Parameters
226
- ----------
227
- sorted_packets : list
228
- AUX packets sorted by time.
229
- decom_data : collections.defaultdict
230
- Empty dictionary.
197
+ coords = {
198
+ "epoch": ds["epoch"].values[idx],
199
+ "event_id": ("epoch", event_ids),
200
+ }
231
201
 
232
- Returns
233
- -------
234
- decom_data : dict
235
- A dictionary containing the decoded data.
236
- """
237
- for packet in sorted_packets:
238
- append_params(decom_data, packet)
202
+ dataset = xr.Dataset(coords=coords)
203
+ for key, data in expanded_data.items():
204
+ dataset[key] = xr.DataArray(
205
+ data,
206
+ dims=["epoch"],
207
+ )
239
208
 
240
- return decom_data
209
+ return dataset
241
210
 
242
211
 
243
- def process_ultra_rates(sorted_packets: list, decom_data: dict) -> dict:
212
+ def process_ultra_rates(ds: xr.Dataset) -> xr.Dataset:
244
213
  """
245
214
  Unpack and decode Ultra RATES packets.
246
215
 
247
216
  Parameters
248
217
  ----------
249
- sorted_packets : list
250
- RATES packets sorted by time.
251
- decom_data : collections.defaultdict
252
- Empty dictionary.
218
+ ds : xarray.Dataset
219
+ Rates dataset.
253
220
 
254
221
  Returns
255
222
  -------
256
- decom_data : dict
257
- A dictionary containing the decoded data.
223
+ dataset : xarray.Dataset
224
+ Dataset containing the decoded and decompressed data.
258
225
  """
259
- if (
260
- isinstance(ULTRA_RATES.mantissa_bit_length, int)
261
- and isinstance(ULTRA_RATES.len_array, int)
262
- and isinstance(ULTRA_RATES.block, int)
263
- and isinstance(ULTRA_RATES.width, int)
264
- ):
265
- for packet in sorted_packets:
266
- raw_binary_string = convert_to_binary_string(packet["FASTDATA_00"])
267
- decompressed_data = decompress_binary(
268
- raw_binary_string,
269
- ULTRA_RATES.width,
270
- ULTRA_RATES.block,
271
- ULTRA_RATES.len_array,
272
- ULTRA_RATES.mantissa_bit_length,
273
- )
274
-
275
- for index in range(ULTRA_RATES.len_array):
276
- decom_data[RATES_KEYS[index]].append(decompressed_data[index])
277
-
278
- append_params(decom_data, packet)
279
-
280
- return decom_data
226
+ decom_data = defaultdict(list)
227
+
228
+ for fastdata in ds["fastdata_00"]:
229
+ raw_binary_string = convert_to_binary_string(fastdata.item())
230
+ decompressed_data = decompress_binary(
231
+ raw_binary_string,
232
+ cast(int, ULTRA_RATES.width),
233
+ cast(int, ULTRA_RATES.block),
234
+ cast(int, ULTRA_RATES.len_array),
235
+ cast(int, ULTRA_RATES.mantissa_bit_length),
236
+ )
237
+
238
+ for index in range(cast(int, ULTRA_RATES.len_array)):
239
+ decom_data[RATES_KEYS[index]].append(decompressed_data[index])
240
+
241
+ for key, values in decom_data.items():
242
+ ds[key] = xr.DataArray(np.array(values), dims=["epoch"])
243
+
244
+ return ds