imap-processing 0.11.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 (415) hide show
  1. imap_processing/__init__.py +11 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +66 -18
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +24 -40
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +934 -42
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  9. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  10. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  11. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -14
  12. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  13. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  14. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  15. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +25 -9
  16. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  17. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  18. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  19. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  20. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +23 -20
  21. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  22. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  23. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  24. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  25. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  26. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  27. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  28. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  29. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  30. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +64 -52
  31. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  32. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +180 -19
  33. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  34. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +80 -17
  35. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +32 -57
  36. imap_processing/cdf/utils.py +52 -38
  37. imap_processing/cli.py +477 -233
  38. imap_processing/codice/codice_l1a.py +466 -131
  39. imap_processing/codice/codice_l1b.py +51 -152
  40. imap_processing/codice/constants.py +1360 -569
  41. imap_processing/codice/decompress.py +2 -6
  42. imap_processing/ena_maps/ena_maps.py +1103 -146
  43. imap_processing/ena_maps/utils/coordinates.py +19 -0
  44. imap_processing/ena_maps/utils/map_utils.py +14 -17
  45. imap_processing/ena_maps/utils/spatial_utils.py +55 -52
  46. imap_processing/glows/l1a/glows_l1a.py +28 -99
  47. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  48. imap_processing/glows/l1b/glows_l1b.py +1 -4
  49. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  50. imap_processing/glows/l2/glows_l2.py +2 -5
  51. imap_processing/hi/l1a/hi_l1a.py +54 -29
  52. imap_processing/hi/l1a/histogram.py +0 -1
  53. imap_processing/hi/l1a/science_direct_event.py +6 -8
  54. imap_processing/hi/l1b/hi_l1b.py +111 -82
  55. imap_processing/hi/l1c/hi_l1c.py +416 -32
  56. imap_processing/hi/utils.py +58 -12
  57. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  58. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  59. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  60. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  61. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  62. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  63. imap_processing/hit/hit_utils.py +235 -5
  64. imap_processing/hit/l0/constants.py +20 -11
  65. imap_processing/hit/l0/decom_hit.py +21 -5
  66. imap_processing/hit/l1a/hit_l1a.py +71 -75
  67. imap_processing/hit/l1b/constants.py +321 -0
  68. imap_processing/hit/l1b/hit_l1b.py +377 -67
  69. imap_processing/hit/l2/constants.py +318 -0
  70. imap_processing/hit/l2/hit_l2.py +723 -0
  71. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  72. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  73. imap_processing/ialirt/l0/parse_mag.py +374 -0
  74. imap_processing/ialirt/l0/process_swapi.py +69 -0
  75. imap_processing/ialirt/l0/process_swe.py +548 -0
  76. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -208
  77. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  78. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  79. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  80. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  81. imap_processing/ialirt/utils/grouping.py +114 -0
  82. imap_processing/ialirt/utils/time.py +29 -0
  83. imap_processing/idex/atomic_masses.csv +22 -0
  84. imap_processing/idex/decode.py +2 -2
  85. imap_processing/idex/idex_constants.py +33 -0
  86. imap_processing/idex/idex_l0.py +22 -8
  87. imap_processing/idex/idex_l1a.py +81 -51
  88. imap_processing/idex/idex_l1b.py +13 -39
  89. imap_processing/idex/idex_l2a.py +823 -0
  90. imap_processing/idex/idex_l2b.py +120 -0
  91. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +11 -11
  92. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  93. imap_processing/lo/l0/lo_science.py +7 -2
  94. imap_processing/lo/l1a/lo_l1a.py +1 -5
  95. imap_processing/lo/l1b/lo_l1b.py +702 -29
  96. imap_processing/lo/l1b/tof_conversions.py +11 -0
  97. imap_processing/lo/l1c/lo_l1c.py +1 -4
  98. imap_processing/mag/constants.py +51 -0
  99. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  100. imap_processing/mag/l0/decom_mag.py +10 -3
  101. imap_processing/mag/l1a/mag_l1a.py +23 -19
  102. imap_processing/mag/l1a/mag_l1a_data.py +35 -10
  103. imap_processing/mag/l1b/mag_l1b.py +259 -50
  104. imap_processing/mag/l1c/interpolation_methods.py +388 -0
  105. imap_processing/mag/l1c/mag_l1c.py +621 -17
  106. imap_processing/mag/l2/mag_l2.py +140 -0
  107. imap_processing/mag/l2/mag_l2_data.py +288 -0
  108. imap_processing/quality_flags.py +1 -0
  109. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  110. imap_processing/spacecraft/quaternions.py +121 -0
  111. imap_processing/spice/geometry.py +19 -22
  112. imap_processing/spice/kernels.py +0 -276
  113. imap_processing/spice/pointing_frame.py +257 -0
  114. imap_processing/spice/repoint.py +149 -0
  115. imap_processing/spice/spin.py +38 -33
  116. imap_processing/spice/time.py +24 -0
  117. imap_processing/swapi/l1/swapi_l1.py +20 -12
  118. imap_processing/swapi/l2/swapi_l2.py +116 -5
  119. imap_processing/swapi/swapi_utils.py +32 -0
  120. imap_processing/swe/l1a/swe_l1a.py +44 -12
  121. imap_processing/swe/l1a/swe_science.py +13 -13
  122. imap_processing/swe/l1b/swe_l1b.py +898 -23
  123. imap_processing/swe/l2/swe_l2.py +75 -136
  124. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  125. imap_processing/swe/utils/swe_constants.py +64 -0
  126. imap_processing/swe/utils/swe_utils.py +85 -28
  127. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  128. imap_processing/tests/ccsds/test_excel_to_xtce.py +24 -21
  129. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  130. imap_processing/tests/cdf/test_utils.py +14 -16
  131. imap_processing/tests/codice/conftest.py +44 -33
  132. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  133. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  134. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  135. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  136. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  137. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  138. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  139. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  140. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  141. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  142. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  143. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  144. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  145. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  146. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  147. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  148. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  149. imap_processing/tests/codice/test_codice_l1a.py +126 -53
  150. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  151. imap_processing/tests/codice/test_decompress.py +4 -4
  152. imap_processing/tests/conftest.py +239 -27
  153. imap_processing/tests/ena_maps/conftest.py +51 -0
  154. imap_processing/tests/ena_maps/test_ena_maps.py +1068 -110
  155. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  156. imap_processing/tests/ena_maps/test_spatial_utils.py +17 -21
  157. imap_processing/tests/glows/conftest.py +10 -14
  158. imap_processing/tests/glows/test_glows_decom.py +4 -4
  159. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  160. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  161. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  162. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  163. imap_processing/tests/glows/test_glows_l2.py +2 -8
  164. imap_processing/tests/hi/conftest.py +1 -1
  165. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  166. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  167. imap_processing/tests/hi/test_hi_l1b.py +22 -27
  168. imap_processing/tests/hi/test_hi_l1c.py +249 -18
  169. imap_processing/tests/hi/test_l1a.py +35 -7
  170. imap_processing/tests/hi/test_science_direct_event.py +3 -3
  171. imap_processing/tests/hi/test_utils.py +24 -2
  172. imap_processing/tests/hit/helpers/l1_validation.py +74 -73
  173. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  174. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  175. imap_processing/tests/hit/test_decom_hit.py +5 -1
  176. imap_processing/tests/hit/test_hit_l1a.py +32 -36
  177. imap_processing/tests/hit/test_hit_l1b.py +300 -81
  178. imap_processing/tests/hit/test_hit_l2.py +716 -0
  179. imap_processing/tests/hit/test_hit_utils.py +184 -7
  180. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  181. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  182. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  183. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  184. imap_processing/tests/ialirt/data/l0/461971383-404.bin +0 -0
  185. imap_processing/tests/ialirt/data/l0/461971384-405.bin +0 -0
  186. imap_processing/tests/ialirt/data/l0/461971385-406.bin +0 -0
  187. imap_processing/tests/ialirt/data/l0/461971386-407.bin +0 -0
  188. imap_processing/tests/ialirt/data/l0/461971387-408.bin +0 -0
  189. imap_processing/tests/ialirt/data/l0/461971388-409.bin +0 -0
  190. imap_processing/tests/ialirt/data/l0/461971389-410.bin +0 -0
  191. imap_processing/tests/ialirt/data/l0/461971390-411.bin +0 -0
  192. imap_processing/tests/ialirt/data/l0/461971391-412.bin +0 -0
  193. imap_processing/tests/ialirt/data/l0/sample_decoded_i-alirt_data.csv +383 -0
  194. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  195. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  196. imap_processing/tests/ialirt/unit/test_parse_mag.py +223 -0
  197. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  198. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  199. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  200. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  201. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  202. imap_processing/tests/ialirt/unit/test_process_swe.py +319 -6
  203. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  204. imap_processing/tests/idex/conftest.py +127 -6
  205. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  206. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  207. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  208. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  209. imap_processing/tests/idex/test_idex_l0.py +33 -11
  210. imap_processing/tests/idex/test_idex_l1a.py +92 -21
  211. imap_processing/tests/idex/test_idex_l1b.py +106 -27
  212. imap_processing/tests/idex/test_idex_l2a.py +399 -0
  213. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  214. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  215. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  216. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  217. imap_processing/tests/lo/test_lo_l1b.py +515 -6
  218. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  219. imap_processing/tests/lo/test_lo_science.py +7 -7
  220. imap_processing/tests/lo/test_star_sensor.py +1 -1
  221. imap_processing/tests/mag/conftest.py +120 -2
  222. imap_processing/tests/mag/test_mag_decom.py +5 -4
  223. imap_processing/tests/mag/test_mag_l1a.py +51 -7
  224. imap_processing/tests/mag/test_mag_l1b.py +40 -59
  225. imap_processing/tests/mag/test_mag_l1c.py +354 -19
  226. imap_processing/tests/mag/test_mag_l2.py +130 -0
  227. imap_processing/tests/mag/test_mag_validation.py +247 -26
  228. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  229. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  230. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  231. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  232. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  233. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  234. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  235. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  236. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  237. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  238. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  239. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  240. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  241. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  242. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  243. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  244. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  245. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  246. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  247. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  248. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  249. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  250. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  251. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  252. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  253. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  254. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  255. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  256. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  257. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  258. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  259. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  260. imap_processing/tests/mag/validation/calibration/imap_mag_l1b-calibration_20240229_v001.cdf +0 -0
  261. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  262. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  263. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  264. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  265. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  266. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  267. imap_processing/tests/spice/test_geometry.py +9 -12
  268. imap_processing/tests/spice/test_kernels.py +1 -200
  269. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  270. imap_processing/tests/spice/test_repoint.py +121 -0
  271. imap_processing/tests/spice/test_spin.py +50 -9
  272. imap_processing/tests/spice/test_time.py +14 -0
  273. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  274. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  275. imap_processing/tests/swapi/test_swapi_l1.py +13 -11
  276. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  277. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  278. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  279. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  280. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  281. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  282. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  283. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  284. imap_processing/tests/swe/test_swe_l1a.py +20 -2
  285. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  286. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  287. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  288. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  289. imap_processing/tests/swe/test_swe_l2.py +153 -91
  290. imap_processing/tests/test_cli.py +171 -88
  291. imap_processing/tests/test_utils.py +140 -17
  292. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  293. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  294. imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3243 -3243
  295. imap_processing/tests/ultra/data/mock_data.py +369 -0
  296. imap_processing/tests/ultra/unit/conftest.py +115 -89
  297. imap_processing/tests/ultra/unit/test_badtimes.py +4 -4
  298. imap_processing/tests/ultra/unit/test_cullingmask.py +8 -6
  299. imap_processing/tests/ultra/unit/test_de.py +14 -13
  300. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  301. imap_processing/tests/ultra/unit/test_decom_apid_881.py +54 -11
  302. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  303. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  304. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  305. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +77 -0
  306. imap_processing/tests/ultra/unit/test_ultra_l1a.py +98 -305
  307. imap_processing/tests/ultra/unit/test_ultra_l1b.py +60 -14
  308. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  309. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +26 -27
  310. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +239 -70
  311. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  312. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +114 -83
  313. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  314. imap_processing/ultra/constants.py +1 -1
  315. imap_processing/ultra/l0/decom_tools.py +27 -39
  316. imap_processing/ultra/l0/decom_ultra.py +168 -204
  317. imap_processing/ultra/l0/ultra_utils.py +152 -136
  318. imap_processing/ultra/l1a/ultra_l1a.py +55 -271
  319. imap_processing/ultra/l1b/badtimes.py +1 -4
  320. imap_processing/ultra/l1b/cullingmask.py +2 -6
  321. imap_processing/ultra/l1b/de.py +116 -57
  322. imap_processing/ultra/l1b/extendedspin.py +20 -18
  323. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  324. imap_processing/ultra/l1b/ultra_l1b.py +36 -16
  325. imap_processing/ultra/l1b/ultra_l1b_culling.py +66 -30
  326. imap_processing/ultra/l1b/ultra_l1b_extended.py +297 -94
  327. imap_processing/ultra/l1c/histogram.py +2 -6
  328. imap_processing/ultra/l1c/spacecraft_pset.py +84 -0
  329. imap_processing/ultra/l1c/ultra_l1c.py +8 -9
  330. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +206 -108
  331. imap_processing/ultra/l2/ultra_l2.py +299 -0
  332. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  333. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  334. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  335. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  336. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  337. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  338. imap_processing/ultra/packet_definitions/README.md +38 -0
  339. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  340. imap_processing/ultra/utils/ultra_l1_utils.py +31 -12
  341. imap_processing/utils.py +69 -29
  342. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +10 -6
  343. imap_processing-0.13.0.dist-info/RECORD +578 -0
  344. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  345. imap_processing/hi/l1a/housekeeping.py +0 -27
  346. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  347. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  348. imap_processing/swe/l1b/swe_l1b_science.py +0 -652
  349. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  350. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  351. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  352. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  353. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  354. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  355. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  356. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  357. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  358. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  359. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  360. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  361. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  362. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  363. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  364. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  365. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  366. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  367. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  368. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  369. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  370. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  371. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  372. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  373. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  374. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  375. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  376. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  377. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  378. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  379. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  380. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  381. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  382. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  383. imap_processing/tests/swe/test_swe_l1b_science.py +0 -84
  384. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  385. imap_processing/ultra/l1c/pset.py +0 -40
  386. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  387. imap_processing-0.11.0.dist-info/RECORD +0 -488
  388. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  389. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  390. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  391. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  392. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  393. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  394. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  395. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  396. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  397. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  398. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  399. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  400. /imap_processing/{mag/l1b → tests/spacecraft}/__init__.py +0 -0
  401. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  402. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  403. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  404. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  405. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  406. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  407. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  408. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  409. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  410. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  411. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  412. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  413. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  414. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  415. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -26,15 +26,12 @@ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
26
26
  from imap_processing.codice import constants
27
27
  from imap_processing.codice.codice_l0 import decom_packets
28
28
  from imap_processing.codice.decompress import decompress
29
- from imap_processing.codice.utils import CODICEAPID
29
+ from imap_processing.codice.utils import CODICEAPID, CoDICECompression
30
30
  from imap_processing.spice.time import met_to_ttj2000ns
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
  logger.setLevel(logging.INFO)
34
34
 
35
- # TODO: Determine what should go in event data CDF and how it should be
36
- # structured.
37
-
38
35
 
39
36
  class CoDICEL1aPipeline:
40
37
  """
@@ -74,6 +71,8 @@ class CoDICEL1aPipeline:
74
71
  Retrieve the acquisition times via the Lo stepping table.
75
72
  get_energy_table()
76
73
  Retrieve the ESA sweep values.
74
+ get_hi_energy_table_data(species)
75
+ Retrieve energy table data for CoDICE-Hi products
77
76
  reshape_data()
78
77
  Reshape the data arrays based on the data product being made.
79
78
  set_data_product_config()
@@ -149,7 +148,7 @@ class CoDICEL1aPipeline:
149
148
  """
150
149
  self.coords = {}
151
150
 
152
- coord_names = ["epoch", *list(self.config["dims"].keys())]
151
+ coord_names = ["epoch", *list(self.config["output_dims"].keys())]
153
152
 
154
153
  # These are labels unique to lo-counters products coordinates
155
154
  if self.config["dataset_name"] in [
@@ -158,11 +157,19 @@ class CoDICEL1aPipeline:
158
157
  ]:
159
158
  coord_names.append("spin_sector_pairs_label")
160
159
 
160
+ # Define the values for the coordinates
161
161
  for name in coord_names:
162
162
  if name == "epoch":
163
163
  values = self.calculate_epoch_values()
164
- elif name in ["esa_step", "inst_az", "spin_sector", "spin_sector_pairs"]:
165
- values = np.arange(self.config["dims"][name])
164
+ elif name in [
165
+ "esa_step",
166
+ "inst_az",
167
+ "spin_sector",
168
+ "spin_sector_pairs",
169
+ "spin_sector_index",
170
+ "ssd_index",
171
+ ]:
172
+ values = np.arange(self.config["output_dims"][name])
166
173
  elif name == "spin_sector_pairs_label":
167
174
  values = np.array(
168
175
  [
@@ -174,10 +181,6 @@ class CoDICEL1aPipeline:
174
181
  "150-180 deg",
175
182
  ]
176
183
  )
177
- else:
178
- # TODO: May need to implement other types of coords for Hi
179
- # and/or event data products
180
- continue
181
184
 
182
185
  coord = xr.DataArray(
183
186
  values,
@@ -226,9 +229,20 @@ class CoDICEL1aPipeline:
226
229
  cdf_attrs_key = f"{descriptor}-{variable_name}"
227
230
  attrs = self.cdf_attrs.get_variable_attributes(cdf_attrs_key)
228
231
 
229
- # The final CDF dimensions always has "epoch" as the first dimension,
230
- # followed by the dimensions for the specific data product
231
- dims = ["epoch", *list(self.config["dims"].keys())]
232
+ # For most products, the final CDF dimensions always has "epoch" as
233
+ # the first dimension followed by the dimensions for the specific
234
+ # data product
235
+ dims = ["epoch", *list(self.config["output_dims"].keys())]
236
+
237
+ # However, CoDICE-Hi products use specific energy bins for the
238
+ # energy dimension
239
+ # TODO: This will be expanded to all CoDICE-Hi products once I
240
+ # can validate them. For now, just operate on hi-sectored
241
+ if self.config["dataset_name"] == "imap_codice_l1a_hi-sectored":
242
+ dims = [
243
+ f"energy_{variable_name}" if item == "esa_step" else item
244
+ for item in dims
245
+ ]
232
246
 
233
247
  # Create the CDF data variable
234
248
  dataset[variable_name] = xr.DataArray(
@@ -241,6 +255,13 @@ class CoDICEL1aPipeline:
241
255
  # Add support data variables based on data product
242
256
  dataset = self.define_support_variables(dataset)
243
257
 
258
+ # For CoDICE-Hi products, since energy dimension was replaced, we no
259
+ # longer need the "esa_step" coordinate
260
+ # TODO: This will be expanded to all CoDICE-Hi products once I
261
+ # can validate them. For now, just operate on hi-sectored
262
+ if self.config["dataset_name"] == "imap_codice_l1a_hi-sectored":
263
+ dataset = dataset.drop_vars("esa_step")
264
+
244
265
  return dataset
245
266
 
246
267
  def define_support_variables(self, dataset: xr.Dataset) -> xr.Dataset:
@@ -269,45 +290,88 @@ class CoDICEL1aPipeline:
269
290
  "st_bias_gain_mode",
270
291
  ]
271
292
 
293
+ hi_energy_table_variables = [
294
+ "energy_h",
295
+ "energy_he3",
296
+ "energy_he4",
297
+ "energy_c",
298
+ "energy_o",
299
+ "energy_ne_mg_si",
300
+ "energy_fe",
301
+ "energy_uh",
302
+ "energy_junk",
303
+ "energy_he3he4",
304
+ "energy_cno",
305
+ ]
306
+
272
307
  for variable_name in self.config["support_variables"]:
273
- # These variables require reading in external tables
274
- if variable_name == "energy_table":
275
- variable_data = self.get_energy_table()
276
- dims = ["esa_step"]
277
- attrs = self.cdf_attrs.get_variable_attributes("energy_table")
278
-
279
- elif variable_name == "acquisition_time_per_step":
280
- variable_data = self.get_acquisition_times()
281
- dims = ["esa_step"]
282
- attrs = self.cdf_attrs.get_variable_attributes(
283
- "acquisition_time_per_step"
308
+ # CoDICE-Hi energy tables are treated differently because values
309
+ # are binned and we need to record the energies _and_ their deltas
310
+ if variable_name in hi_energy_table_variables:
311
+ centers, deltas = self.get_hi_energy_table_data(
312
+ variable_name.split("energy_")[-1]
284
313
  )
285
314
 
286
- elif variable_name in packet_data_variables:
287
- variable_data = self.dataset[variable_name].data
288
- dims = ["epoch"]
289
- attrs = self.cdf_attrs.get_variable_attributes(variable_name)
290
-
291
- # Data quality is named differently in packet data and needs to be
292
- # treated slightly differently
293
- elif variable_name == "data_quality":
294
- variable_data = self.dataset.suspect.data
295
- dims = ["epoch"]
296
- attrs = self.cdf_attrs.get_variable_attributes("data_quality")
297
-
298
- # Spin period requires the application of a conversion factor
299
- # See Table B.5 in the algorithm document
300
- elif variable_name == "spin_period":
301
- variable_data = self.dataset.spin_period.data * 0.00032
302
- dims = ["epoch"]
303
- attrs = self.cdf_attrs.get_variable_attributes("spin_period")
315
+ # Add bin centers and deltas to the dataset
316
+ dataset[variable_name] = xr.DataArray(
317
+ centers,
318
+ dims=[variable_name],
319
+ attrs=self.cdf_attrs.get_variable_attributes(
320
+ f"{self.config['dataset_name'].split('_')[-1]}-{variable_name}"
321
+ ),
322
+ )
323
+ dataset[f"{variable_name}_delta"] = xr.DataArray(
324
+ deltas,
325
+ dims=[f"{variable_name}_delta"],
326
+ attrs=self.cdf_attrs.get_variable_attributes(
327
+ f"{self.config['dataset_name'].split('_')[-1]}-{variable_name}_delta"
328
+ ),
329
+ )
304
330
 
305
- # Add variable to the dataset
306
- dataset[variable_name] = xr.DataArray(
307
- variable_data,
308
- dims=dims,
309
- attrs=attrs,
310
- )
331
+ # Otherwise, support variable data can be gathered from nominal
332
+ # lookup tables or packet data
333
+ else:
334
+ # These variables require reading in external tables
335
+ if variable_name == "energy_table":
336
+ variable_data = self.get_energy_table()
337
+ dims = ["esa_step"]
338
+ attrs = self.cdf_attrs.get_variable_attributes("energy_table")
339
+
340
+ elif variable_name == "acquisition_time_per_step":
341
+ variable_data = self.get_acquisition_times()
342
+ dims = ["esa_step"]
343
+ attrs = self.cdf_attrs.get_variable_attributes(
344
+ "acquisition_time_per_step"
345
+ )
346
+
347
+ # These variables can be gathered straight from the packet data
348
+ elif variable_name in packet_data_variables:
349
+ variable_data = self.dataset[variable_name].data
350
+ dims = ["epoch"]
351
+ attrs = self.cdf_attrs.get_variable_attributes(variable_name)
352
+
353
+ # Data quality is named differently in packet data and needs to be
354
+ # treated slightly differently
355
+ elif variable_name == "data_quality":
356
+ variable_data = self.dataset.suspect.data
357
+ dims = ["epoch"]
358
+ attrs = self.cdf_attrs.get_variable_attributes("data_quality")
359
+
360
+ # Spin period requires the application of a conversion factor
361
+ # See Table B.5 in the algorithm document
362
+ elif variable_name == "spin_period":
363
+ variable_data = (
364
+ self.dataset.spin_period.data * constants.SPIN_PERIOD_CONVERSION
365
+ ).astype(np.float32)
366
+ dims = ["epoch"]
367
+ attrs = self.cdf_attrs.get_variable_attributes("spin_period")
368
+
369
+ # Add variable to the dataset
370
+ dataset[variable_name] = xr.DataArray(
371
+ variable_data,
372
+ dims=dims,
373
+ attrs=attrs,
374
+ )
311
375
 
312
376
  return dataset
313
377
 
@@ -315,12 +379,11 @@ class CoDICEL1aPipeline:
315
379
  """
316
380
  Retrieve the acquisition times via the Lo stepping table.
317
381
 
318
- Get the acquisition times from the data file based on the values of
382
+ Get the acquisition times from the lookup table based on the values of
319
383
  ``plan_id`` and ``plan_step``
320
384
 
321
385
  The Lo stepping table defines how many voltage steps and which steps are
322
386
  used during each spacecraft spin. A full cycle takes 16 spins. The table
323
- provides the timing for a given energy step, and most importantly
324
387
  provides the "acquisition time", which is the acquisition time, in
325
388
  milliseconds, for the energy step.
326
389
 
@@ -329,37 +392,15 @@ class CoDICEL1aPipeline:
329
392
  acquisition_times : list[float]
330
393
  The list of acquisition times from the Lo stepping table.
331
394
  """
332
- # Read in the Lo stepping data table
333
- lo_stepping_data_file = Path(
334
- f"{imap_module_directory}/codice/data/lo_stepping_values.csv"
335
- )
336
- lo_stepping_data = pd.read_csv(lo_stepping_data_file)
337
-
338
395
  # Determine which Lo stepping table is needed
339
396
  lo_stepping_table_id = constants.LO_STEPPING_TABLE_ID_LOOKUP[
340
397
  (self.plan_id, self.plan_step)
341
398
  ]
342
399
 
343
- # Get the appropriate values
344
- lo_stepping_values = lo_stepping_data[
345
- lo_stepping_data["table_num"] == lo_stepping_table_id
400
+ acquisition_times: list[float] = constants.ACQUISITION_TIMES[
401
+ lo_stepping_table_id
346
402
  ]
347
403
 
348
- # Create a list for the acquisition times
349
- acquisition_times = []
350
-
351
- # Only need the energy columns from the table
352
- energy_steps = lo_stepping_values[
353
- ["e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8"]
354
- ].astype(str) # convert to string to avoid confusion with table index value
355
-
356
- # For each energy step (0-127), scan the energy columns and find the row
357
- # number, which corresponds to a specific acquisition time, then append
358
- # it to the list
359
- for step_number in range(128):
360
- row_number = np.argmax(energy_steps == str(step_number), axis=1).argmax()
361
- acquisition_times.append(lo_stepping_values.acq_time[row_number])
362
-
363
404
  return acquisition_times
364
405
 
365
406
  def get_energy_table(self) -> NDArray[float]:
@@ -400,39 +441,100 @@ class CoDICEL1aPipeline:
400
441
 
401
442
  return energy_table
402
443
 
444
+ def get_hi_energy_table_data(
445
+ self, species: str
446
+ ) -> tuple[NDArray[float], NDArray[float]]:
447
+ """
448
+ Retrieve energy table data for CoDICE-Hi products.
449
+
450
+ This includes the centers and deltas of the energy bins for a given
451
+ species. These data eventually get included in the CoDICE-Hi CDF data
452
+ products.
453
+
454
+ Parameters
455
+ ----------
456
+ species : str
457
+ The species of interest, which determines which lookup table to
458
+ use (e.g. ``h``).
459
+
460
+ Returns
461
+ -------
462
+ centers : NDArray[float]
463
+ An array whose values represent the centers of the energy bins.
464
+ deltas : NDArray[float]
465
+ An array whose values represent the deltas of the energy bins.
466
+ """
467
+ data_product = self.config["dataset_name"].split("-")[-1].upper()
468
+ energy_table = getattr(constants, f"{data_product}_ENERGY_TABLE")[species]
469
+
470
+ # Find the centers and deltas of the energy bins
471
+ centers = np.array(
472
+ [
473
+ (energy_table[i] + energy_table[i + 1]) / 2
474
+ for i in range(len(energy_table) - 1)
475
+ ]
476
+ )
477
+ deltas = energy_table[1:] - centers
478
+
479
+ return centers, deltas
480
+
403
481
  def reshape_data(self) -> None:
404
482
  """
405
483
  Reshape the data arrays based on the data product being made.
406
484
 
407
485
  These data need to be divided up by species or priorities (or
408
486
  what I am calling "counters" as a general term), and re-arranged into
409
- 3D arrays representing dimensions such as spin sectors, positions, and
410
- energies (depending on the data product).
487
+ 4D arrays representing dimensions such as time, spin sectors, positions,
488
+ and energies (depending on the data product).
489
+
490
+ However, the existence and order of these dimensions can vary depending
491
+ on the specific data product, so we define this in the "input_dims"
492
+ and "output_dims" values configuration dictionary; the "input_dims"
493
+ defines how the dimensions are written into the packet data, while
494
+ "output_dims" defines how the dimensions should be written to the final
495
+ CDF product.
411
496
  """
412
497
  # This will contain the reshaped data for all counters
413
498
  self.data = []
414
499
 
415
- # Typically, data are a 4D arrays with a shape representing some
416
- # combination of <num_counters>, <num_positions>, <num_spin_sectors>,
417
- # and <num_energy_steps>. However, the existence and order of these
418
- # dimensions can vary depending on the specific data product, so we
419
- # define this in the "dims" value configuration dictionary. The number
420
- # of counters is the first dimension/axis.
421
- reshape_dims = (self.config["num_counters"], *self.config["dims"].values())
500
+ # First reshape the data based on how it is written to the data array of
501
+ # the packet data. The number of counters is the first dimension / axis,
502
+ # with the exception of lo-counters-aggregated which is treated slightly
503
+ # differently
504
+ if self.config["dataset_name"] != "imap_codice_l1a_lo-counters-aggregated":
505
+ reshape_dims = (
506
+ self.config["num_counters"],
507
+ *self.config["input_dims"].values(),
508
+ )
509
+ else:
510
+ reshape_dims = (
511
+ *self.config["input_dims"].values(),
512
+ self.config["num_counters"],
513
+ )
514
+
515
+ # Then, transpose the data based on how the dimensions should be written
516
+ # to the CDF file. Since this is specific to each data product, we need
517
+ # to determine this dynamically based on the "output_dims" config.
518
+ # Again, lo-counters-aggregated is treated slightly differently
519
+ input_keys = ["num_counters", *self.config["input_dims"].keys()]
520
+ output_keys = ["num_counters", *self.config["output_dims"].keys()]
521
+ if self.config["dataset_name"] != "imap_codice_l1a_lo-counters-aggregated":
522
+ transpose_axes = [input_keys.index(dim) for dim in output_keys]
523
+ else:
524
+ transpose_axes = [1, 2, 0] # [esa_step, spin_sector_pairs, num_counters]
422
525
 
423
- # For each packet/epoch, reshape the data along these dimensions
424
526
  for packet_data in self.raw_data:
425
527
  reshaped_packet_data = np.array(packet_data, dtype=np.uint32).reshape(
426
528
  reshape_dims
427
529
  )
428
- self.data.append(reshaped_packet_data)
530
+ reshaped_cdf_data = np.transpose(reshaped_packet_data, axes=transpose_axes)
531
+
532
+ self.data.append(reshaped_cdf_data)
429
533
 
430
534
  # No longer need to keep the raw data around
431
535
  del self.raw_data
432
536
 
433
- def set_data_product_config(
434
- self, apid: int, dataset: xr.Dataset, data_version: str
435
- ) -> None:
537
+ def set_data_product_config(self, apid: int, dataset: xr.Dataset) -> None:
436
538
  """
437
539
  Set the various settings for defining the data products.
438
540
 
@@ -442,79 +544,139 @@ class CoDICEL1aPipeline:
442
544
  The APID of interest.
443
545
  dataset : xarray.Dataset
444
546
  The dataset for the APID of interest.
445
- data_version : str
446
- Version of the data product being created.
447
547
  """
448
548
  # Set the packet dataset so that it can be easily called from various
449
549
  # methods
450
550
  self.dataset = dataset
451
551
 
452
552
  # Set various configurations of the data product
453
- self.config: dict[str, Any] = constants.DATA_PRODUCT_CONFIGURATIONS.get(apid) # type: ignore
553
+ self.config: dict[str, Any] = constants.DATA_PRODUCT_CONFIGURATIONS[apid]
454
554
 
455
555
  # Gather and set the CDF attributes
456
556
  self.cdf_attrs = ImapCdfAttributes()
457
557
  self.cdf_attrs.add_instrument_global_attrs("codice")
458
558
  self.cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
459
- self.cdf_attrs.add_global_attribute("Data_version", data_version)
460
559
 
461
560
 
462
- def create_event_dataset(
463
- apid: int, packet: xr.Dataset, data_version: str
464
- ) -> xr.Dataset:
561
+ def create_direct_event_dataset(apid: int, packets: xr.Dataset) -> xr.Dataset:
465
562
  """
466
- Create dataset for event data.
563
+ Create dataset for direct event data.
564
+
565
+ For direct event data, the raw data from the spacecraft is organized first
566
+ by epoch, then by priority, then by events. For example, for a CoDICE-Lo
567
+ dataset with 10 epochs, we expect the length of the `event_data` field to
568
+ be (10 epochs * 8 priorities) = 80 items, with each item being a compressed
569
+ byte object representing a variable number of events (up to 10000 events).
570
+ Each compressed byte object is comprised of several fields with specific
571
+ bit lengths/positions, described by the constants.[LO|HI]_DE_BIT_STRUCTURE
572
+ dictionary. Padding is added to any fields that have less than 10000 events.
573
+
574
+ In order to process these data, we must take the decommed raw data, group
575
+ the packets appropriately based on their `seq_flgs`, decompress the data,
576
+ then arrange the data into CDF data variables for each priority and bit
577
+ field. For example, P2_SpinAngle represents the spin angles for the 2nd
578
+ priority data.
467
579
 
468
580
  Parameters
469
581
  ----------
470
582
  apid : int
471
583
  The APID of the packet.
472
- packet : xarray.Dataset
473
- The packet to process.
474
- data_version : str
475
- Version of the data product being created.
584
+ packets : xarray.Dataset
585
+ The packets to process..
476
586
 
477
587
  Returns
478
588
  -------
479
589
  dataset : xarray.Dataset
480
- Xarray dataset containing the event data.
590
+ Xarray dataset containing the direct event data.
481
591
  """
592
+ # Set some useful variables unique to CoDICE-Lo and CoDICE-Hi
482
593
  if apid == CODICEAPID.COD_LO_PHA:
483
- dataset_name = "imap_codice_l1a_lo-pha"
594
+ num_priorities = 8
595
+ cdf_fields = [
596
+ "NumEvents",
597
+ "DataQuality",
598
+ "APDGain",
599
+ "APD_ID",
600
+ "APDEnergy",
601
+ "TOF",
602
+ "MultiFlag",
603
+ "PHAType",
604
+ "SpinAngle",
605
+ "EnergyStep",
606
+ ]
484
607
  elif apid == CODICEAPID.COD_HI_PHA:
485
- dataset_name = "imap_codice_l1a_hi-pha"
608
+ num_priorities = 6
609
+ cdf_fields = [
610
+ "NumEvents",
611
+ "DataQuality",
612
+ "SSDEnergy0,TOF",
613
+ "SSD_ID",
614
+ "ERGE",
615
+ "MultiFlag",
616
+ "Type",
617
+ "SpinAngle",
618
+ "SpinNumber",
619
+ ]
620
+
621
+ # Group and decompress the data
622
+ grouped_data = group_data(packets)
623
+ decompressed_data = [
624
+ decompress(group, CoDICECompression.LOSSLESS) for group in grouped_data
625
+ ]
486
626
 
487
- # Extract the data
488
- # event_data = packet.event_data.data (Currently turned off, see TODO)
627
+ # Reshape the packet data into CDF-ready variables
628
+ data = reshape_de_data(packets, decompressed_data, num_priorities)
489
629
 
630
+ # Gather the CDF attributes
490
631
  cdf_attrs = ImapCdfAttributes()
491
632
  cdf_attrs.add_instrument_global_attrs("codice")
492
633
  cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
493
- cdf_attrs.add_global_attribute("Data_version", data_version)
494
634
 
495
635
  # Define coordinates
636
+ # For epoch, we take the first epoch from each priority set
496
637
  epoch = xr.DataArray(
497
- packet.epoch,
638
+ packets.epoch[::num_priorities],
498
639
  name="epoch",
499
640
  dims=["epoch"],
500
641
  attrs=cdf_attrs.get_variable_attributes("epoch"),
501
642
  )
643
+ event_num = xr.DataArray(
644
+ np.arange(10000),
645
+ name="event_num",
646
+ dims=["event_num"],
647
+ attrs=cdf_attrs.get_variable_attributes("event_num"),
648
+ )
502
649
 
503
650
  # Create the dataset to hold the data variables
651
+ if apid == CODICEAPID.COD_LO_PHA:
652
+ attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_lo-pha")
653
+ elif apid == CODICEAPID.COD_HI_PHA:
654
+ attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_hi-pha")
504
655
  dataset = xr.Dataset(
505
- coords={
506
- "epoch": epoch,
507
- },
508
- attrs=cdf_attrs.get_global_attributes(dataset_name),
656
+ coords={"epoch": epoch, "event_num": event_num},
657
+ attrs=attrs,
509
658
  )
510
659
 
660
+ # Create the CDF data variables for each Priority and Field
661
+ for i in range(num_priorities):
662
+ for field in cdf_fields:
663
+ variable_name = f"P{i}_{field}"
664
+ attrs = cdf_attrs.get_variable_attributes(variable_name)
665
+ if field in ["NumEvents", "DataQuality"]:
666
+ dims = ["epoch"]
667
+ else:
668
+ dims = ["epoch", "event_num"]
669
+ dataset[variable_name] = xr.DataArray(
670
+ np.array(data[variable_name]),
671
+ name=variable_name,
672
+ dims=dims,
673
+ attrs=attrs,
674
+ )
675
+
511
676
  return dataset
512
677
 
513
678
 
514
- def create_hskp_dataset(
515
- packet: xr.Dataset,
516
- data_version: str,
517
- ) -> xr.Dataset:
679
+ def create_hskp_dataset(packet: xr.Dataset) -> xr.Dataset:
518
680
  """
519
681
  Create dataset for each metadata field for housekeeping data.
520
682
 
@@ -522,8 +684,6 @@ def create_hskp_dataset(
522
684
  ----------
523
685
  packet : xarray.Dataset
524
686
  The packet to process.
525
- data_version : str
526
- Version of the data product being created.
527
687
 
528
688
  Returns
529
689
  -------
@@ -533,7 +693,6 @@ def create_hskp_dataset(
533
693
  cdf_attrs = ImapCdfAttributes()
534
694
  cdf_attrs.add_instrument_global_attrs("codice")
535
695
  cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
536
- cdf_attrs.add_global_attribute("Data_version", data_version)
537
696
 
538
697
  epoch = xr.DataArray(
539
698
  packet.epoch,
@@ -547,7 +706,23 @@ def create_hskp_dataset(
547
706
  attrs=cdf_attrs.get_global_attributes("imap_codice_l1a_hskp"),
548
707
  )
549
708
 
709
+ # These variables don't need to carry over from L0 to L1a
710
+ exclude_variables = [
711
+ "spare_1",
712
+ "spare_2",
713
+ "spare_3",
714
+ "spare_4",
715
+ "spare_5",
716
+ "spare_6",
717
+ "spare_62",
718
+ "spare_68",
719
+ "chksum",
720
+ ]
721
+
550
722
  for variable in packet:
723
+ if variable in exclude_variables:
724
+ continue
725
+
551
726
  attrs = cdf_attrs.get_variable_attributes(variable)
552
727
 
553
728
  dataset[variable] = xr.DataArray(
@@ -596,6 +771,69 @@ def get_params(dataset: xr.Dataset) -> tuple[int, int, int, int]:
596
771
  return table_id, plan_id, plan_step, view_id
597
772
 
598
773
 
774
+ def group_data(packets: xr.Dataset) -> list[bytes]:
775
+ """
776
+ Organize continuation packets into appropriate groups.
777
+
778
+ Some packets are continuation packets, as in, they are packets that are
779
+ part of a group of packets. These packets are marked by the `seq_flgs` field
780
+ in the CCSDS header of the packet. For CoDICE, the values are defined as
781
+ follows:
782
+
783
+ 3 = Packet is not part of a group
784
+ 1 = Packet is the first packet of the group
785
+ 0 = Packet is in the middle of the group
786
+ 2 = Packet is the last packet of the group
787
+
788
+ For packets that are part of a group, the byte count associated with the
789
+ first packet of the group signifies the byte count for the entire group.
790
+
791
+ Parameters
792
+ ----------
793
+ packets : xarray.Dataset
794
+ Dataset containing the packets to group.
795
+
796
+ Returns
797
+ -------
798
+ grouped_data : list[bytes]
799
+ The packet data, converted to bytes and grouped appropriately.
800
+ """
801
+ grouped_data = [] # Holds the properly grouped data to be decompressed
802
+ current_group = bytearray() # Temporary storage for current group
803
+ group_byte_count = None # Temporary storage for current group byte count
804
+
805
+ for packet_data, group_code, byte_count in zip(
806
+ packets.event_data.data, packets.seq_flgs.data, packets.byte_count.data
807
+ ):
808
+ # If the group code is 3, this means the data is not part of a group
809
+ # and can be decompressed as-is
810
+ if group_code == 3:
811
+ values_to_decompress = packet_data[:byte_count]
812
+ grouped_data.append(values_to_decompress)
813
+
814
+ # If the group code is 1, this means the data is the first data in a
815
+ # group. Also, set the byte count for the group
816
+ elif group_code == 1:
817
+ group_byte_count = byte_count
818
+ current_group = packet_data
819
+
820
+ # If the group code is 0, this means the data is part of the middle of
821
+ # the group
822
+ elif group_code == 0:
823
+ current_group += packet_data
824
+
825
+ # If the group code is 2, this means the data is the last data in the
826
+ # group
827
+ elif group_code == 2:
828
+ current_group += packet_data
829
+ values_to_decompress = current_group[:group_byte_count]
830
+ grouped_data.append(values_to_decompress)
831
+ current_group = bytearray()
832
+ group_byte_count = None
833
+
834
+ return grouped_data
835
+
836
+
599
837
  def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
600
838
  """
601
839
  Log info about the input data to help with tracking and/or debugging.
@@ -607,9 +845,9 @@ def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
607
845
  """
608
846
  launch_time = np.datetime64("2010-01-01T00:01:06.184", "ns")
609
847
  logger.info("\nThis input file contains the following APIDs:\n")
610
- for apid in datasets:
611
- num_packets = len(datasets[apid].epoch.data)
612
- time_deltas = [np.timedelta64(item, "ns") for item in datasets[apid].epoch.data]
848
+ for apid, ds in datasets.items():
849
+ num_packets = len(ds.epoch.data)
850
+ time_deltas = [np.timedelta64(item, "ns") for item in ds.epoch.data]
613
851
  times = [launch_time + delta for delta in time_deltas]
614
852
  start = np.datetime_as_string(times[0])
615
853
  end = np.datetime_as_string(times[-1])
@@ -618,7 +856,102 @@ def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
618
856
  )
619
857
 
620
858
 
621
- def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
859
+ def reshape_de_data(
860
+ packets: xr.Dataset, decompressed_data: list[list[int]], num_priorities: int
861
+ ) -> dict[str, np.ndarray]:
862
+ """
863
+ Reshape the decompressed direct event data into CDF-ready arrays.
864
+
865
+ Parameters
866
+ ----------
867
+ packets : xarray.Dataset
868
+ Dataset containing the packets, needed to determine priority order
869
+ and data quality.
870
+ decompressed_data : list[list[int]]
871
+ The decompressed data to reshape, in the format <epoch>[<priority>[<event>]].
872
+ num_priorities : int
873
+ The number of priorities in the data product (differs between CoDICE-Lo
874
+ and CoDICE-Hi).
875
+
876
+ Returns
877
+ -------
878
+ data : dict[str, numpy.ndarray]
879
+ The reshaped, CDF-ready arrays. The keys of the dictionary represent the
880
+ CDF variable names, and the values represent the data.
881
+ """
882
+ # Dictionary to hold all the (soon to be restructured) direct event data
883
+ data: dict[str, np.ndarray] = {}
884
+
885
+ # Determine the number of epochs to help with data array initialization
886
+ # There is one epoch per set of priorities
887
+ num_epochs = len(packets.epoch.data) // num_priorities
888
+
889
+ # Initialize data arrays for each priority and field to store the data
890
+ # We also need arrays to hold number of events and data quality
891
+ for priority_num in range(num_priorities):
892
+ for field in constants.LO_DE_BIT_STRUCTURE:
893
+ if field not in ["Priority", "Spare"]:
894
+ data[f"P{priority_num}_{field}"] = np.full(
895
+ (num_epochs, 10000), 255, dtype=np.uint16
896
+ )
897
+ data[f"P{priority_num}_NumEvents"] = np.full(num_epochs, 255, dtype=np.uint16)
898
+ data[f"P{priority_num}_DataQuality"] = np.full(num_epochs, 255, dtype=np.uint16)
899
+
900
+ # decompressed_data is one large list of values of length
901
+ # (<number of epochs> * <8 priorities>)
902
+ # Chunk the data into each epoch
903
+ for epoch_index in range(num_epochs):
904
+ # Determine the starting and ending indices of the epoch
905
+ epoch_start = epoch_index * num_priorities
906
+ epoch_end = epoch_start + num_priorities
907
+
908
+ # Extract the data for the epoch
909
+ epoch_data = decompressed_data[epoch_start:epoch_end]
910
+
911
+ # The order of the priorities and data quality flags are unique to each
912
+ # epoch and can be gathered from the packet data
913
+ priority_order = packets.priority[epoch_start:epoch_end].data
914
+ data_quality = packets.suspect[epoch_start:epoch_end].data
915
+
916
+ # For each epoch/priority combo, iterate over each event
917
+ for i, priority_num in enumerate(priority_order):
918
+ priority_data = epoch_data[i]
919
+
920
+ # Number of events and data quality can be determined at this stage
921
+ num_events = len(priority_data) // num_priorities
922
+ data[f"P{priority_num}_NumEvents"][epoch_index] = num_events
923
+ data[f"P{priority_num}_DataQuality"][epoch_index] = data_quality[i]
924
+
925
+ # Iterate over each event
926
+ for event_index in range(num_events):
927
+ event_start = event_index * num_priorities
928
+ event_end = event_start + num_priorities
929
+ event = priority_data[event_start:event_end]
930
+ # Separate out each individual field from the bit string
931
+ # The fields are packed into the bit string in reverse order, so
932
+ # we need to back them out in reverse order
933
+ bit_string = (
934
+ f"{int.from_bytes(event, byteorder='big'):0{len(event) * 8}b}"
935
+ )
936
+ bit_position = 0
937
+ for field_name, bit_length in reversed(
938
+ constants.LO_DE_BIT_STRUCTURE.items()
939
+ ):
940
+ if field_name in ["Priority", "Spare"]:
941
+ bit_position += bit_length
942
+ continue
943
+ value = int(bit_string[bit_position : bit_position + bit_length], 2)
944
+ data[f"P{priority_num}_{field_name}"][epoch_index, event_index] = (
945
+ value
946
+ )
947
+ bit_position += bit_length
948
+
949
+ # TODO: Implement specific np.dtype and fill_val per field
950
+
951
+ return data
952
+
953
+
954
+ def process_codice_l1a(file_path: Path) -> list[xr.Dataset]:
622
955
  """
623
956
  Will process CoDICE l0 data to create l1a data products.
624
957
 
@@ -626,8 +959,6 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
626
959
  ----------
627
960
  file_path : pathlib.Path | str
628
961
  Path to the CoDICE L0 file to process.
629
- data_version : str
630
- Version of the data product being created.
631
962
 
632
963
  Returns
633
964
  -------
@@ -651,14 +982,19 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
651
982
 
652
983
  # Housekeeping data
653
984
  if apid == CODICEAPID.COD_NHK:
654
- processed_dataset = create_hskp_dataset(dataset, data_version)
985
+ processed_dataset = create_hskp_dataset(dataset)
655
986
  logger.info(f"\nFinal data product:\n{processed_dataset}\n")
656
987
 
657
988
  # Event data
658
- elif apid in [CODICEAPID.COD_LO_PHA, CODICEAPID.COD_HI_PHA]:
659
- processed_dataset = create_event_dataset(apid, dataset, data_version)
989
+ elif apid == CODICEAPID.COD_LO_PHA:
990
+ processed_dataset = create_direct_event_dataset(apid, dataset)
660
991
  logger.info(f"\nFinal data product:\n{processed_dataset}\n")
661
992
 
993
+ # TODO: Still need to implement
994
+ elif apid == CODICEAPID.COD_HI_PHA:
995
+ logger.info("\tStill need to properly implement")
996
+ processed_dataset = None
997
+
662
998
  # Everything else
663
999
  elif apid in constants.APIDS_FOR_SCIENCE_PROCESSING:
664
1000
  # Extract the data
@@ -669,7 +1005,7 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
669
1005
 
670
1006
  # Run the pipeline to create a dataset for the product
671
1007
  pipeline = CoDICEL1aPipeline(table_id, plan_id, plan_step, view_id)
672
- pipeline.set_data_product_config(apid, dataset, data_version)
1008
+ pipeline.set_data_product_config(apid, dataset)
673
1009
  pipeline.decompress_data(science_values)
674
1010
  pipeline.reshape_data()
675
1011
  pipeline.define_coordinates()
@@ -677,9 +1013,8 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
677
1013
 
678
1014
  logger.info(f"\nFinal data product:\n{processed_dataset}\n")
679
1015
 
680
- # TODO: Still need to implement I-ALiRT and hi-priorities data products
1016
+ # TODO: Still need to implement I-ALiRT data products
681
1017
  elif apid in [
682
- CODICEAPID.COD_HI_INST_COUNTS_PRIORITIES,
683
1018
  CODICEAPID.COD_HI_IAL,
684
1019
  CODICEAPID.COD_LO_IAL,
685
1020
  ]: