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
@@ -66,14 +66,12 @@ def get_datasets_by_apid(
66
66
  return datasets_by_apid
67
67
 
68
68
 
69
- def get_attribute_manager(data_version: str, level: str) -> ImapCdfAttributes:
69
+ def get_attribute_manager(level: str) -> ImapCdfAttributes:
70
70
  """
71
71
  Create an attribute manager for the HIT data products.
72
72
 
73
73
  Parameters
74
74
  ----------
75
- data_version : str
76
- Version of the data product being created.
77
75
  level : str
78
76
  Data level of the product being created.
79
77
 
@@ -86,7 +84,6 @@ def get_attribute_manager(data_version: str, level: str) -> ImapCdfAttributes:
86
84
  attr_mgr = ImapCdfAttributes()
87
85
  attr_mgr.add_instrument_global_attrs(instrument="hit")
88
86
  attr_mgr.add_instrument_variable_attrs(instrument="hit", level=level)
89
- attr_mgr.add_global_attribute("Data_version", data_version)
90
87
  return attr_mgr
91
88
 
92
89
 
@@ -159,7 +156,6 @@ def process_housekeeping_data(
159
156
  # Drop keys that are not CDF data variables
160
157
  drop_keys = [
161
158
  "pkt_apid",
162
- "sc_tick",
163
159
  "version",
164
160
  "type",
165
161
  "sec_hdr_flg",
@@ -219,3 +215,237 @@ def process_housekeeping_data(
219
215
  dataset.epoch.attrs = attr_mgr.get_variable_attributes("epoch")
220
216
 
221
217
  return dataset
218
+
219
+
220
+ def initialize_particle_data_arrays(
221
+ dataset: xr.Dataset,
222
+ particle: str,
223
+ num_energy_ranges: int,
224
+ epoch_size: int,
225
+ ) -> xr.Dataset:
226
+ """
227
+ Add empty data arrays for a given particle.
228
+
229
+ Valid particle names:
230
+ h
231
+ he3
232
+ he4
233
+ he
234
+ c
235
+ n
236
+ o
237
+ ne
238
+ na
239
+ mg
240
+ al
241
+ si
242
+ s
243
+ ar
244
+ ca
245
+ fe
246
+ ni
247
+
248
+ Parameters
249
+ ----------
250
+ dataset : xr.Dataset
251
+ The dataset to add the data arrays to.
252
+ particle : str
253
+ The abbreviated particle name.
254
+ num_energy_ranges : int
255
+ Number of energy ranges for the particle.
256
+ Used to define the shape of the data arrays.
257
+ epoch_size : int
258
+ Used to define the shape of the data arrays.
259
+
260
+ Returns
261
+ -------
262
+ updated_ds : xr.Dataset
263
+ The updated dataset with the particle data arrays added.
264
+ """
265
+ updated_ds = dataset.copy()
266
+
267
+ updated_ds[f"{particle}"] = xr.DataArray(
268
+ data=np.zeros((epoch_size, num_energy_ranges), dtype=np.float32),
269
+ dims=["epoch", f"{particle}_energy_mean"],
270
+ name=f"{particle}",
271
+ )
272
+ updated_ds[f"{particle}_stat_uncert_minus"] = xr.DataArray(
273
+ data=np.zeros((epoch_size, num_energy_ranges), dtype=np.float32),
274
+ dims=["epoch", f"{particle}_energy_mean"],
275
+ name=f"{particle}_stat_uncert_minus",
276
+ )
277
+ updated_ds[f"{particle}_stat_uncert_plus"] = xr.DataArray(
278
+ data=np.zeros((epoch_size, num_energy_ranges), dtype=np.float32),
279
+ dims=["epoch", f"{particle}_energy_mean"],
280
+ name=f"{particle}_stat_uncert_plus",
281
+ )
282
+ updated_ds.coords[f"{particle}_energy_mean"] = xr.DataArray(
283
+ np.zeros(num_energy_ranges, dtype=np.int8),
284
+ dims=[f"{particle}_energy_mean"],
285
+ name=f"{particle}_energy_mean",
286
+ )
287
+
288
+ return updated_ds
289
+
290
+
291
+ def sum_particle_data(
292
+ dataset: xr.Dataset, indices: dict
293
+ ) -> tuple[xr.DataArray, xr.DataArray, xr.DataArray]:
294
+ """
295
+ Sum particle data for a given energy range.
296
+
297
+ Parameters
298
+ ----------
299
+ dataset : xr.Dataset
300
+ A dataset containing particle data to sum in the l2fgrates, l3fgrates,
301
+ penfgrates data variables. If it's an L1A dataset, these variables
302
+ contain particle counts. If it's an L1B dataset, these variables
303
+ contain particle rates.
304
+
305
+ indices : dict
306
+ A dictionary containing the indices for particle data to sum for a given
307
+ energy range. The dictionary should have the following keys:
308
+ R2 = indices for l2fgrates
309
+ R3 = indices for l3fgrates
310
+ R4 = indices for penfgrates
311
+
312
+ Returns
313
+ -------
314
+ summed_data : xr.DataArray
315
+ The summed data for the given energy range.
316
+
317
+ summed_uncertainty_minus : xr.DataArray
318
+ The summed data for delta minus statistical uncertainty.
319
+
320
+ summed_uncertainty_plus : xr.DataArray
321
+ The summed data for delta plus statistical uncertainty.
322
+ """
323
+ summed_data = (
324
+ dataset["l2fgrates"][:, indices["R2"]].sum(axis=1)
325
+ + dataset["l3fgrates"][:, indices["R3"]].sum(axis=1)
326
+ + dataset["penfgrates"][:, indices["R4"]].sum(axis=1)
327
+ )
328
+
329
+ summed_uncertainty_minus = (
330
+ dataset["l2fgrates_stat_uncert_minus"][:, indices["R2"]].sum(axis=1)
331
+ + dataset["l3fgrates_stat_uncert_minus"][:, indices["R3"]].sum(axis=1)
332
+ + dataset["penfgrates_stat_uncert_minus"][:, indices["R4"]].sum(axis=1)
333
+ )
334
+
335
+ summed_uncertainty_plus = (
336
+ dataset["l2fgrates_stat_uncert_plus"][:, indices["R2"]].sum(axis=1)
337
+ + dataset["l3fgrates_stat_uncert_plus"][:, indices["R3"]].sum(axis=1)
338
+ + dataset["penfgrates_stat_uncert_plus"][:, indices["R4"]].sum(axis=1)
339
+ )
340
+
341
+ return summed_data, summed_uncertainty_minus, summed_uncertainty_plus
342
+
343
+
344
+ def add_energy_variables(
345
+ dataset: xr.Dataset,
346
+ particle: str,
347
+ energy_min_values: np.ndarray,
348
+ energy_max_values: np.ndarray,
349
+ ) -> xr.Dataset:
350
+ """
351
+ Add energy min and max variables to the dataset.
352
+
353
+ Parameters
354
+ ----------
355
+ dataset : xr.Dataset
356
+ The dataset to add the energy variables to.
357
+ particle : str
358
+ The particle name.
359
+ energy_min_values : np.ndarray
360
+ The minimum energy values for each energy range.
361
+ energy_max_values : np.ndarray
362
+ The maximum energy values for each energy range.
363
+
364
+ Returns
365
+ -------
366
+ updated_ds : xr.Dataset
367
+ The updated dataset with the energy variables added.
368
+ """
369
+ updated_ds = dataset.copy()
370
+
371
+ energy_mean = np.mean(
372
+ np.array([energy_min_values, energy_max_values]), axis=0
373
+ ).astype(np.float32)
374
+
375
+ updated_ds[f"{particle}_energy_mean"] = xr.DataArray(
376
+ data=energy_mean,
377
+ dims=[f"{particle}_energy_mean"],
378
+ name=f"{particle}_energy_mean",
379
+ )
380
+ updated_ds[f"{particle}_energy_delta_minus"] = xr.DataArray(
381
+ data=np.array(energy_mean - np.array(energy_min_values), dtype=np.float32),
382
+ dims=[f"{particle}_energy_mean"],
383
+ name=f"{particle}_energy_delta_minus",
384
+ )
385
+ updated_ds[f"{particle}_energy_delta_plus"] = xr.DataArray(
386
+ data=np.array(energy_max_values - energy_mean, dtype=np.float32),
387
+ dims=[f"{particle}_energy_mean"],
388
+ name=f"{particle}_energy_delta_plus",
389
+ )
390
+ return updated_ds
391
+
392
+
393
+ def add_summed_particle_data_to_dataset(
394
+ dataset: xr.Dataset,
395
+ source_dataset: xr.Dataset,
396
+ particle: str,
397
+ energy_ranges: list,
398
+ ) -> xr.Dataset:
399
+ """
400
+ Add summed particle data to the dataset.
401
+
402
+ Parameters
403
+ ----------
404
+ dataset : xr.Dataset
405
+ The dataset to add the rates to (not modified in-place).
406
+ source_dataset : xr.Dataset
407
+ The dataset containing data to sum (counts or rates).
408
+ particle : str
409
+ The particle name.
410
+ energy_ranges : list
411
+ A list of energy range dictionaries for the particle.
412
+
413
+ Returns
414
+ -------
415
+ xr.Dataset
416
+ A new dataset with summed particle data added.
417
+ """
418
+ # Make a copy of the dataset to update
419
+ ds = dataset.copy()
420
+
421
+ # Initialize particle data arrays
422
+ ds = initialize_particle_data_arrays(
423
+ ds, particle, len(energy_ranges), source_dataset.sizes["epoch"]
424
+ )
425
+
426
+ # Initialize arrays for energy values
427
+ energy_min = np.zeros(len(energy_ranges), dtype=np.float32)
428
+ energy_max = np.zeros(len(energy_ranges), dtype=np.float32)
429
+
430
+ # Compute summed data and update the dataset
431
+ for i, energy_range_dict in enumerate(energy_ranges):
432
+ summed_data, summed_data_uncert_minus, summed_data_uncert_plus = (
433
+ sum_particle_data(source_dataset, energy_range_dict)
434
+ )
435
+
436
+ ds[f"{particle}"][:, i] = summed_data.astype(np.float32)
437
+ ds[f"{particle}_stat_uncert_minus"][:, i] = summed_data_uncert_minus.astype(
438
+ np.float32
439
+ )
440
+ ds[f"{particle}_stat_uncert_plus"][:, i] = summed_data_uncert_plus.astype(
441
+ np.float32
442
+ )
443
+
444
+ # Store energy range values
445
+ energy_min[i] = energy_range_dict["energy_min"]
446
+ energy_max[i] = energy_range_dict["energy_max"]
447
+
448
+ # Add energy variables
449
+ ds = add_energy_variables(ds, particle, energy_min, energy_max)
450
+
451
+ return ds
@@ -6,16 +6,16 @@ import numpy as np
6
6
 
7
7
  # energy_units: MeV/n
8
8
  MOD_10_MAPPING = {
9
- 0: {"species": "H", "energy_min": 1.8, "energy_max": 3.6},
10
- 1: {"species": "H", "energy_min": 4, "energy_max": 6},
11
- 2: {"species": "H", "energy_min": 6, "energy_max": 10},
12
- 3: {"species": "He4", "energy_min": 4, "energy_max": 6},
13
- 4: {"species": "He4", "energy_min": 6, "energy_max": 12},
14
- 5: {"species": "CNO", "energy_min": 4, "energy_max": 6},
15
- 6: {"species": "CNO", "energy_min": 6, "energy_max": 12},
16
- 7: {"species": "NeMgSi", "energy_min": 4, "energy_max": 6},
17
- 8: {"species": "NeMgSi", "energy_min": 6, "energy_max": 12},
18
- 9: {"species": "Fe", "energy_min": 4, "energy_max": 12},
9
+ 0: {"species": "h", "energy_min": 1.8, "energy_max": 3.6},
10
+ 1: {"species": "h", "energy_min": 4, "energy_max": 6},
11
+ 2: {"species": "h", "energy_min": 6, "energy_max": 10},
12
+ 3: {"species": "he4", "energy_min": 4, "energy_max": 6},
13
+ 4: {"species": "he4", "energy_min": 6, "energy_max": 12},
14
+ 5: {"species": "cno", "energy_min": 4, "energy_max": 6},
15
+ 6: {"species": "cno", "energy_min": 6, "energy_max": 12},
16
+ 7: {"species": "nemgsi", "energy_min": 4, "energy_max": 6},
17
+ 8: {"species": "nemgsi", "energy_min": 6, "energy_max": 12},
18
+ 9: {"species": "fe", "energy_min": 4, "energy_max": 12},
19
19
  }
20
20
 
21
21
  # Structure to hold binary details for a
@@ -100,7 +100,7 @@ COUNTS_DATA_STRUCTURE = {
100
100
  "penfgrates": HITPacking(16, 528, (33,)), # range 4 foreground rates
101
101
  "penbgrates": HITPacking(16, 240, (15,)), # range 4 background rates
102
102
  "ialirtrates": HITPacking(16, 320, (20,)), # ialirt rates
103
- "sectorates": HITPacking(16, 1920, (8, 15)), # sectored rates
103
+ "sectorates": HITPacking(16, 1920, (15, 8)), # sectored rates
104
104
  "l4fgrates": HITPacking(16, 768, (48,)), # all range foreground rates
105
105
  "l4bgrates": HITPacking(16, 384, (24,)), # all range foreground rates
106
106
  }
@@ -116,3 +116,12 @@ FRAME_SIZE = len(FLAG_PATTERN)
116
116
  # decompressing data
117
117
  MANTISSA_BITS = 12
118
118
  EXPONENT_BITS = 4
119
+
120
+ # Define sectorate angles
121
+ DECLINATION_ANGLES = np.array(
122
+ [11.25, 33.75, 56.25, 78.75, 101.25, 123.75, 146.25, 168.75], dtype=np.float32
123
+ )
124
+ AZIMUTH_ANGLES = np.array(
125
+ [12, 36, 60, 84, 108, 132, 156, 180, 204, 228, 252, 276, 300, 324, 348],
126
+ dtype=np.float32,
127
+ )
@@ -4,7 +4,9 @@ import numpy as np
4
4
  import xarray as xr
5
5
 
6
6
  from imap_processing.hit.l0.constants import (
7
+ AZIMUTH_ANGLES,
7
8
  COUNTS_DATA_STRUCTURE,
9
+ DECLINATION_ANGLES,
8
10
  EXPONENT_BITS,
9
11
  FLAG_PATTERN,
10
12
  FRAME_SIZE,
@@ -90,9 +92,20 @@ def parse_count_rates(sci_dataset: xr.Dataset) -> None:
90
92
  # Get dims for data variables (yaml file not created yet)
91
93
  if len(field_meta.shape) > 1:
92
94
  if "sectorates" in field:
93
- # Reshape data to 8x15 for declination and azimuth look directions
95
+ # Reshape data to 15x8 for azimuth and declination look directions
94
96
  parsed_data = np.array(parsed_data).reshape((-1, *field_meta.shape))
95
- dims = ["epoch", "declination", "azimuth"]
97
+ dims = ["epoch", "azimuth", "declination"]
98
+ # Add angle values to coordinates
99
+ sci_dataset.coords["declination"] = xr.DataArray(
100
+ data=DECLINATION_ANGLES,
101
+ dims=["declination"],
102
+ name="declination",
103
+ )
104
+ sci_dataset.coords["azimuth"] = xr.DataArray(
105
+ data=AZIMUTH_ANGLES,
106
+ dims=["azimuth"],
107
+ name="azimuth",
108
+ )
96
109
  elif "sngrates" in field:
97
110
  dims = ["epoch", "gain", f"{field}_index"]
98
111
  elif field_meta.shape[0] > 1:
@@ -100,13 +113,16 @@ def parse_count_rates(sci_dataset: xr.Dataset) -> None:
100
113
  else:
101
114
  dims = ["epoch"]
102
115
 
103
- sci_dataset[field] = xr.DataArray(parsed_data, dims=dims, name=field)
116
+ sci_dataset[field] = xr.DataArray(
117
+ np.array(parsed_data, dtype=np.int64), dims=dims, name=field
118
+ )
104
119
  # Add dimensions to coordinates
105
- # TODO: confirm that dtype int16 is correct
106
120
  for dim in dims:
107
121
  if dim not in sci_dataset.coords:
108
122
  sci_dataset.coords[dim] = xr.DataArray(
109
- np.arange(sci_dataset.sizes[dim], dtype=np.int16),
123
+ np.arange(sci_dataset.sizes[dim], dtype=np.int16)
124
+ if dim == "gain"
125
+ else np.arange(sci_dataset.sizes[dim], dtype=np.int32),
110
126
  dims=[dim],
111
127
  name=dim,
112
128
  )
@@ -8,6 +8,7 @@ import xarray as xr
8
8
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
9
9
  from imap_processing.hit.hit_utils import (
10
10
  HitAPID,
11
+ add_energy_variables,
11
12
  get_attribute_manager,
12
13
  get_datasets_by_apid,
13
14
  process_housekeeping_data,
@@ -23,7 +24,7 @@ logger = logging.getLogger(__name__)
23
24
  fillval = -9223372036854775808
24
25
 
25
26
 
26
- def hit_l1a(packet_file: str, data_version: str) -> list[xr.Dataset]:
27
+ def hit_l1a(packet_file: str) -> list[xr.Dataset]:
27
28
  """
28
29
  Will process HIT L0 data into L1A data products.
29
30
 
@@ -31,8 +32,6 @@ def hit_l1a(packet_file: str, data_version: str) -> list[xr.Dataset]:
31
32
  ----------
32
33
  packet_file : str
33
34
  Path to the CCSDS data packet file.
34
- data_version : str
35
- Version of the data product being created.
36
35
 
37
36
  Returns
38
37
  -------
@@ -43,7 +42,7 @@ def hit_l1a(packet_file: str, data_version: str) -> list[xr.Dataset]:
43
42
  datasets_by_apid = get_datasets_by_apid(packet_file)
44
43
 
45
44
  # Create the attribute manager for this data level
46
- attr_mgr = get_attribute_manager(data_version, "l1a")
45
+ attr_mgr = get_attribute_manager("l1a")
47
46
 
48
47
  l1a_datasets = []
49
48
 
@@ -62,107 +61,106 @@ def hit_l1a(packet_file: str, data_version: str) -> list[xr.Dataset]:
62
61
  return l1a_datasets
63
62
 
64
63
 
65
- def subcom_sectorates(sci_dataset: xr.Dataset) -> None:
64
+ def subcom_sectorates(sci_dataset: xr.Dataset) -> xr.Dataset:
66
65
  """
67
66
  Subcommutate sectorates data.
68
67
 
69
- Sector rates data contains rates for 5 species and 10
70
- energy ranges. This function subcommutates the sector
71
- rates data by organizing the rates by species. Which
68
+ Sectored rates data contains raw counts for 5 species and 10
69
+ energy ranges. This function subcommutates the sectored
70
+ rates data by organizing the counts by species. Which
72
71
  species and energy range the data belongs to is determined
73
72
  by taking the mod 10 value of the corresponding header
74
73
  minute count value in the dataset. A mapping of mod 10
75
74
  values to species and energy ranges is provided in constants.py.
76
75
 
77
76
  MOD_10_MAPPING = {
78
- 0: {"species": "H", "energy_min": 1.8, "energy_max": 3.6},
79
- 1: {"species": "H", "energy_min": 4, "energy_max": 6},
80
- 2: {"species": "H", "energy_min": 6, "energy_max": 10},
81
- 3: {"species": "4He", "energy_min": 4, "energy_max": 6},
77
+ 0: {"species": "h", "energy_min": 1.8, "energy_max": 3.6},
78
+ 1: {"species": "h", "energy_min": 4, "energy_max": 6},
79
+ 2: {"species": "h", "energy_min": 6, "energy_max": 10},
80
+ 3: {"species": "he4", "energy_min": 4, "energy_max": 6},
82
81
  ...
83
- 9: {"species": "Fe", "energy_min": 4, "energy_max": 12}}
82
+ 9: {"species": "fe", "energy_min": 4, "energy_max": 12}}
84
83
 
85
84
  The data is added to the dataset as new data fields named
86
85
  according to their species. They have 4 dimensions: epoch
87
- energy index, declination, and azimuth. The energy index
86
+ energy mean, azimuth, and declination. The energy mean
88
87
  dimension is used to distinguish between the different energy
89
- ranges the data belongs to. The energy min and max values for
90
- each species are also added to the dataset as new data fields.
88
+ ranges the data belongs to. The energy deltas for each species
89
+ are also added to the dataset as new data fields.
91
90
 
92
91
  Parameters
93
92
  ----------
94
93
  sci_dataset : xarray.Dataset
95
94
  Xarray dataset containing parsed HIT science data.
95
+
96
+ Returns
97
+ -------
98
+ sci_dataset : xarray.Dataset
99
+ Xarray dataset with sectored rates data organized by species.
96
100
  """
101
+ updated_dataset = sci_dataset.copy()
102
+
97
103
  # Calculate mod 10 values
98
- hdr_min_count_mod_10 = sci_dataset.hdr_minute_cnt.values % 10
104
+ hdr_min_count_mod_10 = updated_dataset.hdr_minute_cnt.values % 10
99
105
 
100
106
  # Reference mod 10 mapping to initialize data structure for species and
101
- # energy ranges and add 8x15 arrays with fill values for each science frame.
107
+ # energy ranges and add 15x8 arrays with fill values for each science frame.
102
108
  num_frames = len(hdr_min_count_mod_10)
103
- # TODO: add more specific dtype for rates (ex. int16) once this is defined by HIT
104
109
  data_by_species_and_energy_range = {
105
110
  key: {
106
111
  **value,
107
- "rates": np.full((num_frames, 8, 15), fill_value=fillval, dtype=int),
112
+ "counts": np.full((num_frames, 15, 8), fill_value=fillval, dtype=np.int64),
108
113
  }
109
114
  for key, value in MOD_10_MAPPING.items()
110
115
  }
111
116
 
112
- # Update rates for science frames where data is available
117
+ # Update counts for science frames where data is available
113
118
  for i, mod_10 in enumerate(hdr_min_count_mod_10):
114
- data_by_species_and_energy_range[mod_10]["rates"][i] = sci_dataset[
119
+ data_by_species_and_energy_range[mod_10]["counts"][i] = updated_dataset[
115
120
  "sectorates"
116
121
  ].values[i]
117
122
 
118
123
  # H has 3 energy ranges, 4He, CNO, NeMgSi have 2, and Fe has 1.
119
- # Aggregate sector rates and energy min/max values for each species.
124
+ # Aggregate sectored rates and energy min/max values for each species.
120
125
  # First, initialize dictionaries to store rates and min/max energy values by species
121
126
  data_by_species: dict = {
122
- value["species"]: {"rates": [], "energy_min": [], "energy_max": []}
127
+ value["species"]: {"counts": [], "energy_min": [], "energy_max": []}
123
128
  for value in data_by_species_and_energy_range.values()
124
129
  }
125
130
 
126
131
  for value in data_by_species_and_energy_range.values():
127
132
  species = value["species"]
128
- data_by_species[species]["rates"].append(value["rates"])
133
+ data_by_species[species]["counts"].append(value["counts"])
129
134
  data_by_species[species]["energy_min"].append(value["energy_min"])
130
135
  data_by_species[species]["energy_max"].append(value["energy_max"])
131
136
 
132
- # Add sector rates by species to the dataset
133
- for species_type, data in data_by_species.items():
134
- # Rates data has shape: energy_index, epoch, declination, azimuth
137
+ # Add sectored rates by species to the dataset
138
+ for species, data in data_by_species.items():
139
+ # Rates data has shape: energy_mean, epoch, azimuth, declination
135
140
  # Convert rates to numpy array and transpose axes to get
136
- # shape: epoch, energy_index, declination, azimuth
137
- rates_data = np.transpose(np.array(data["rates"]), axes=(1, 0, 2, 3))
141
+ # shape: epoch, energy_mean, azimuth, declination
142
+ rates_data = np.transpose(np.array(data["counts"]), axes=(1, 0, 2, 3))
138
143
 
139
- species = species_type.lower()
140
- sci_dataset[f"{species}_counts_sectored"] = xr.DataArray(
144
+ updated_dataset[f"{species}_sectored_counts"] = xr.DataArray(
141
145
  data=rates_data,
142
- dims=["epoch", f"{species}_energy_index", "declination", "azimuth"],
146
+ dims=["epoch", f"{species}_energy_mean", "azimuth", "declination"],
143
147
  name=f"{species}_counts_sectored",
144
148
  )
145
- sci_dataset[f"{species}_energy_min"] = xr.DataArray(
146
- data=np.array(data["energy_min"], dtype=np.int8),
147
- dims=[f"{species}_energy_index"],
148
- name=f"{species}_energy_min",
149
- )
150
- sci_dataset[f"{species}_energy_max"] = xr.DataArray(
151
- data=np.array(data["energy_max"], dtype=np.int8),
152
- dims=[f"{species}_energy_index"],
153
- name=f"{species}_energy_max",
154
- )
155
- # add energy index coordinate to the dataset
156
- sci_dataset.coords[f"{species}_energy_index"] = xr.DataArray(
157
- np.arange(sci_dataset.sizes[f"{species}_energy_index"], dtype=np.int8),
158
- dims=[f"{species}_energy_index"],
159
- name=f"{species}_energy_index",
149
+
150
+ # Add energy mean and deltas for each species
151
+ updated_dataset = add_energy_variables(
152
+ updated_dataset,
153
+ species,
154
+ np.array(data["energy_min"]),
155
+ np.array(data["energy_max"]),
160
156
  )
161
157
 
158
+ return updated_dataset
159
+
162
160
 
163
161
  def calculate_uncertainties(dataset: xr.Dataset) -> xr.Dataset:
164
162
  """
165
- Calculate uncertainties for each counts data variable in the dataset.
163
+ Calculate statistical uncertainties.
166
164
 
167
165
  Calculate the upper and lower uncertainties. The uncertainty for
168
166
  the raw Lev1A HIT data will be calculated as asymmetric Poisson
@@ -170,10 +168,10 @@ def calculate_uncertainties(dataset: xr.Dataset) -> xr.Dataset:
170
168
  See section 5.5 in the algorithm document for details.
171
169
 
172
170
  The upper uncertainty will be calculated as
173
- DELTA_PLUS = sqrt(counts + 1) + 1
171
+ uncert_plus = sqrt(counts + 1) + 1
174
172
 
175
173
  The lower uncertainty will be calculated as
176
- DELTA_MINUS = sqrt(counts)
174
+ uncert_minus = sqrt(counts)
177
175
 
178
176
  Parameters
179
177
  ----------
@@ -202,16 +200,16 @@ def calculate_uncertainties(dataset: xr.Dataset) -> xr.Dataset:
202
200
  "hdr_code_ok",
203
201
  "hdr_minute_cnt",
204
202
  "livetime_counter",
205
- "h_energy_min",
206
- "h_energy_max",
207
- "he4_energy_min",
208
- "he4_energy_max",
209
- "cno_energy_min",
210
- "cno_energy_max",
211
- "nemgsi_energy_min",
212
- "nemgsi_energy_max",
213
- "fe_energy_min",
214
- "fe_energy_max",
203
+ "h_energy_delta_minus",
204
+ "h_energy_delta_plus",
205
+ "he4_energy_delta_minus",
206
+ "he4_energy_delta_plus",
207
+ "cno_energy_delta_minus",
208
+ "cno_energy_delta_plus",
209
+ "nemgsi_energy_delta_minus",
210
+ "nemgsi_energy_delta_plus",
211
+ "fe_energy_delta_minus",
212
+ "fe_energy_delta_plus",
215
213
  ]
216
214
 
217
215
  # Counts data that need uncertainties calculated
@@ -226,13 +224,13 @@ def calculate_uncertainties(dataset: xr.Dataset) -> xr.Dataset:
226
224
  safe_values_plus = np.maximum(dataset[var] + 1, 0).astype(np.float32)
227
225
  safe_values_minus = np.maximum(dataset[var], 0).astype(np.float32)
228
226
 
229
- dataset[f"{var}_delta_plus"] = xr.DataArray(
227
+ dataset[f"{var}_stat_uncert_plus"] = xr.DataArray(
230
228
  np.where(
231
229
  mask, np.sqrt(safe_values_plus) + 1, dataset[var].astype(np.float32)
232
230
  ),
233
231
  dims=dataset[var].dims,
234
232
  )
235
- dataset[f"{var}_delta_minus"] = xr.DataArray(
233
+ dataset[f"{var}_stat_uncert_minus"] = xr.DataArray(
236
234
  np.where(mask, np.sqrt(safe_values_minus), dataset[var].astype(np.float32)),
237
235
  dims=dataset[var].dims,
238
236
  )
@@ -269,8 +267,8 @@ def process_science(
269
267
  # Decommutate and decompress the science data
270
268
  sci_dataset = decom_hit(dataset)
271
269
 
272
- # Organize sector rates by species type
273
- subcom_sectorates(sci_dataset)
270
+ # Organize sectored rates by species type
271
+ sci_dataset = subcom_sectorates(sci_dataset)
274
272
 
275
273
  # Split the science data into count rates and event datasets
276
274
  pha_raw_dataset = xr.Dataset(
@@ -282,18 +280,18 @@ def process_science(
282
280
  count_rates_dataset = calculate_uncertainties(count_rates_dataset)
283
281
 
284
282
  # Logical sources for the two products.
285
- logical_sources = ["imap_hit_l1a_count-rates", "imap_hit_l1a_pulse-height-events"]
283
+ logical_sources = ["imap_hit_l1a_counts", "imap_hit_l1a_direct-events"]
286
284
 
287
285
  datasets = []
288
286
  # Update attributes and dimensions
289
- for dataset, logical_source in zip(
287
+ for ds, logical_source in zip(
290
288
  [count_rates_dataset, pha_raw_dataset], logical_sources
291
289
  ):
292
- dataset.attrs = attr_mgr.get_global_attributes(logical_source)
290
+ ds.attrs = attr_mgr.get_global_attributes(logical_source)
293
291
 
294
292
  # TODO: Add CDF attributes to yaml once they're defined for L1A science data
295
293
  # Assign attributes and dimensions to each data array in the Dataset
296
- for field in dataset.data_vars.keys():
294
+ for field in ds.data_vars.keys():
297
295
  try:
298
296
  # Create a dict of dimensions using the DEPEND_I keys in the
299
297
  # attributes
@@ -302,19 +300,17 @@ def process_science(
302
300
  for key, value in attr_mgr.get_variable_attributes(field).items()
303
301
  if "DEPEND" in key
304
302
  }
305
- dataset[field].attrs = attr_mgr.get_variable_attributes(field)
306
- dataset[field].assign_coords(dims)
303
+ ds[field].attrs = attr_mgr.get_variable_attributes(field)
304
+ ds[field].assign_coords(dims)
307
305
  except KeyError:
308
306
  print(f"Field {field} not found in attribute manager.")
309
307
  logger.warning(f"Field {field} not found in attribute manager.")
310
308
 
311
309
  # Skip schema check for epoch to prevent attr_mgr from adding the
312
310
  # DEPEND_0 attribute which isn't required for epoch
313
- dataset.epoch.attrs = attr_mgr.get_variable_attributes(
314
- "epoch", check_schema=False
315
- )
311
+ ds.epoch.attrs = attr_mgr.get_variable_attributes("epoch", check_schema=False)
316
312
 
317
- datasets.append(dataset)
313
+ datasets.append(ds)
318
314
 
319
315
  logger.info(f"HIT L1A dataset created for {logical_source}")
320
316