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
@@ -1,6 +1,8 @@
1
1
  """Test coverage for imap_processing.hi.l1c.hi_l1c.py"""
2
2
 
3
+ from collections import namedtuple
3
4
  from unittest import mock
5
+ from unittest.mock import MagicMock
4
6
 
5
7
  import numpy as np
6
8
  import pandas as pd
@@ -9,9 +11,10 @@ import xarray as xr
9
11
 
10
12
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
13
  from imap_processing.cdf.utils import load_cdf, write_cdf
14
+ from imap_processing.hi.l1a.science_direct_event import DE_CLOCK_TICK_S
12
15
  from imap_processing.hi.l1c import hi_l1c
13
16
  from imap_processing.hi.l1c.hi_l1c import CalibrationProductConfig
14
- from imap_processing.hi.utils import HIAPID
17
+ from imap_processing.hi.utils import HIAPID, CoincidenceBitmap
15
18
 
16
19
 
17
20
  @pytest.fixture(scope="module")
@@ -24,46 +27,46 @@ def hi_test_cal_prod_config_path(hi_l1_test_data_path):
24
27
  @mock.patch("imap_processing.hi.l1c.hi_l1c.generate_pset_dataset")
25
28
  def test_hi_l1c(mock_generate_pset_dataset, hi_test_cal_prod_config_path):
26
29
  """Test coverage for hi_l1c function"""
27
- mock_generate_pset_dataset.return_value = xr.Dataset(attrs={"Data_version": None})
28
- pset = hi_l1c.hi_l1c(
29
- [xr.Dataset(), hi_test_cal_prod_config_path], data_version="99"
30
- )
31
- assert pset.attrs["Data_version"] == "99"
30
+ mock_generate_pset_dataset.return_value = xr.Dataset()
31
+ pset = hi_l1c.hi_l1c([xr.Dataset(), hi_test_cal_prod_config_path])[0]
32
+ # Empty attributes, global values get added in post-processing
33
+ assert pset.attrs == {}
32
34
 
33
35
 
34
36
  def test_hi_l1c_not_implemented():
35
37
  """Test coverage for hi_l1c function with unrecognized dependencies"""
36
38
  with pytest.raises(NotImplementedError):
37
- hi_l1c.hi_l1c([None, None], "0")
39
+ hi_l1c.hi_l1c([None, None])
38
40
 
39
41
 
40
- @pytest.mark.external_kernel()
42
+ @pytest.mark.external_test_data
43
+ @pytest.mark.external_kernel
41
44
  @pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
42
- def test_generate_pset_dataset(hi_l1_test_data_path, hi_test_cal_prod_config_path):
45
+ def test_generate_pset_dataset(
46
+ hi_l1_test_data_path, hi_test_cal_prod_config_path, use_fake_spin_data_for_time
47
+ ):
43
48
  """Test coverage for generate_pset_dataset function"""
49
+ use_fake_spin_data_for_time(482372987.999)
44
50
  l1b_de_path = hi_l1_test_data_path / "imap_hi_l1b_45sensor-de_20250415_v999.cdf"
45
51
  l1b_dataset = load_cdf(l1b_de_path)
46
52
  l1c_dataset = hi_l1c.generate_pset_dataset(
47
53
  l1b_dataset, hi_test_cal_prod_config_path
48
54
  )
49
55
 
50
- assert l1c_dataset.epoch.data[0] == np.mean(l1b_dataset.epoch.data[[0, -1]]).astype(
51
- np.int64
52
- )
56
+ assert l1c_dataset.epoch.data[0] == l1b_dataset.epoch.data[0].astype(np.int64)
53
57
 
54
58
  np.testing.assert_array_equal(l1c_dataset.despun_z.data.shape, (1, 3))
55
59
  np.testing.assert_array_equal(l1c_dataset.hae_latitude.data.shape, (1, 3600))
56
60
  np.testing.assert_array_equal(l1c_dataset.hae_longitude.data.shape, (1, 3600))
61
+ np.testing.assert_array_equal(l1c_dataset.exposure_times.data.shape, (1, 9, 3600))
57
62
  for var in [
58
63
  "counts",
59
- "exposure_times",
60
64
  "background_rates",
61
65
  "background_rates_uncertainty",
62
66
  ]:
63
67
  np.testing.assert_array_equal(l1c_dataset[var].data.shape, (1, 9, 2, 3600))
64
68
 
65
69
  # Test ISTP compliance by writing CDF
66
- l1c_dataset.attrs["Data_version"] = 1
67
70
  write_cdf(l1c_dataset)
68
71
 
69
72
 
@@ -74,7 +77,7 @@ def test_empty_pset_dataset():
74
77
  n_calibration_prods = 5
75
78
  sensor_str = HIAPID.H90_SCI_DE.sensor
76
79
  dataset = hi_l1c.empty_pset_dataset(
77
- l1b_esa_energy_steps, n_calibration_prods, sensor_str
80
+ 100, l1b_esa_energy_steps, n_calibration_prods, sensor_str
78
81
  )
79
82
 
80
83
  assert dataset.epoch.size == 1
@@ -131,6 +134,225 @@ def test_pset_geometry(mock_frame_transform, mock_geom_frame_transform, sensor_s
131
134
  )
132
135
 
133
136
 
137
+ @pytest.mark.external_test_data
138
+ def test_pset_counts(hi_l1_test_data_path, hi_test_cal_prod_config_path):
139
+ """Test coverage for pset_counts function."""
140
+ l1b_de_path = hi_l1_test_data_path / "imap_hi_l1b_45sensor-de_20250415_v999.cdf"
141
+ l1b_dataset = load_cdf(l1b_de_path)
142
+ cal_config_df = hi_l1c.CalibrationProductConfig.from_csv(
143
+ hi_test_cal_prod_config_path
144
+ )
145
+ empty_pset = hi_l1c.empty_pset_dataset(
146
+ 100,
147
+ l1b_dataset.esa_energy_step.data,
148
+ cal_config_df.cal_prod_config.number_of_products,
149
+ HIAPID.H90_SCI_DE.sensor,
150
+ )
151
+ counts_var = hi_l1c.pset_counts(empty_pset.coords, cal_config_df, l1b_dataset)
152
+ assert "counts" in counts_var
153
+
154
+
155
+ def test_get_tof_window_mask():
156
+ """Test coverage for get_tof_window_mask function."""
157
+ # Create a synthetic dataframe with required columns containing data
158
+ # intended to test all aspects of the function.
159
+ fill_vals = {
160
+ "tof_ab": -11,
161
+ "tof_ac1": -12,
162
+ "tof_bc1": -13,
163
+ "tof_c1c2": -14,
164
+ }
165
+ Row = namedtuple(
166
+ "Row",
167
+ [
168
+ "Index",
169
+ "tof_ab_low",
170
+ "tof_ab_high",
171
+ "tof_ac1_low",
172
+ "tof_ac1_high",
173
+ "tof_bc1_low",
174
+ "tof_bc1_high",
175
+ "tof_c1c2_low",
176
+ "tof_c1c2_high",
177
+ ],
178
+ )
179
+ prod_config_row = Row((1, 0), 0, 1, -1, 2, 1, 5, 4, 6)
180
+ synth_df = pd.DataFrame(
181
+ {
182
+ "tof_ab": np.array(
183
+ [0, 2, 1, 0, -1, -5, -11], dtype=np.int32
184
+ ), # T, F, T, T, F, F, FILL
185
+ "tof_ac1": np.array(
186
+ [-1, 2, -2, 0, 3, 0, -12], dtype=np.int32
187
+ ), # T, T, F, T, F, T, FILL
188
+ "tof_bc1": np.array(
189
+ [1, 5, 3, 0, 6, 2, -13], dtype=np.int32
190
+ ), # T, T, T, F, F, T, FILL
191
+ "tof_c1c2": np.array(
192
+ [4, 6, 5, 3, 7, -9, -14], dtype=np.int32
193
+ ), # T, T, T, F, F, F, FILL
194
+ },
195
+ )
196
+ expected_mask = np.array([True, False, False, False, False, False, True])
197
+ window_mask = hi_l1c.get_tof_window_mask(synth_df, prod_config_row, fill_vals)
198
+ np.testing.assert_array_equal(expected_mask, window_mask)
199
+
200
+
201
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.get_spin_data", return_value=None)
202
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.get_instrument_spin_phase")
203
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.get_de_clock_ticks_for_esa_step")
204
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.find_second_de_packet_data")
205
+ def test_pset_exposure(
206
+ mock_find_second_de_packet_data,
207
+ mock_de_clock_ticks,
208
+ mock_spin_phase,
209
+ mock_spin_data,
210
+ ):
211
+ """Test coverage for pset_exposure function"""
212
+ empty_pset = hi_l1c.empty_pset_dataset(
213
+ 100, np.arange(2) + 1, 2, HIAPID.H90_SCI_DE.sensor
214
+ )
215
+ # Set the mock of find_second_de_packet_data to return a xr.Dataset
216
+ # with some dummy data. ESA 1 will get binned data once, ESA 2 will get
217
+ # binned data twice.
218
+ mock_find_second_de_packet_data.return_value = xr.Dataset(
219
+ coords={"epoch": xr.DataArray(np.arange(3), dims=["epoch"])},
220
+ data_vars={
221
+ "ccsds_met": xr.DataArray(np.arange(3), dims=["epoch"]),
222
+ "esa_energy_step": xr.DataArray(np.array([1, 2, 2]), dims=["epoch"]),
223
+ },
224
+ )
225
+ # Set mock of get_de_clock_ticks_for_esa_step and spin phase to generate
226
+ # deterministic histogram values.
227
+ # ESA step 1 should have repeating values of 3, 1.
228
+ # ESA step 2 should have repeating values of 6, 2
229
+ mock_spin_phase.return_value = np.concat(
230
+ [hi_l1c.SPIN_PHASE_BIN_CENTERS, hi_l1c.SPIN_PHASE_BIN_CENTERS[::2]]
231
+ )
232
+ mock_de_clock_ticks.return_value = (
233
+ np.zeros(hi_l1c.N_SPIN_BINS + hi_l1c.N_SPIN_BINS // 2),
234
+ np.concat([np.ones(hi_l1c.N_SPIN_BINS), np.ones(hi_l1c.N_SPIN_BINS // 2) * 2]),
235
+ )
236
+
237
+ # The above mocks mean no data needs to be in the l1b_dataset. It
238
+ # only needs to provide a logical source that contains "90sensor".
239
+ l1b_dataset = MagicMock()
240
+ l1b_dataset.attrs = {"Logical_source": "90sensor"}
241
+
242
+ # All the setup is done, call the pset_exposure function
243
+ exposure_dict = hi_l1c.pset_exposure(empty_pset.coords, l1b_dataset)
244
+
245
+ # Based on the spin phase and clock_tick mocks, the expected clock ticks are:
246
+ # - Repeated values of 3, 1 for the first half of the spin bins
247
+ # - Repeated values of 3, 2 for the second half of the spin bins
248
+ expected_values = np.stack(
249
+ [
250
+ np.tile([3, 1], hi_l1c.N_SPIN_BINS // 2),
251
+ np.tile([6, 2], hi_l1c.N_SPIN_BINS // 2),
252
+ ]
253
+ ).astype(float)[None, :, :]
254
+ # Convert expected clock ticks to seconds
255
+ expected_values *= DE_CLOCK_TICK_S
256
+ np.testing.assert_allclose(
257
+ exposure_dict["exposure_times"].data,
258
+ expected_values,
259
+ atol=DE_CLOCK_TICK_S / 100,
260
+ )
261
+
262
+
263
+ def test_find_second_de_packet_data():
264
+ """Test coverage for find_second_de_packet_data function"""
265
+ # Create a test l1b_dataset
266
+ # Expect to remove index 0 and 5 due to missing esa_step pair
267
+ # Expect to remove index 11 due to 0 being a calibration step
268
+ # Expect to return indices 2, 4, 7, 9, 13
269
+ esa_steps = np.array([1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 0, 0, 7, 7])
270
+ l1b_dataset = xr.Dataset(
271
+ coords={
272
+ "epoch": xr.DataArray(
273
+ np.arange(esa_steps.size),
274
+ dims=["epoch"],
275
+ ),
276
+ "event_met": xr.DataArray(
277
+ np.arange(10),
278
+ dims=["event_met"],
279
+ ),
280
+ },
281
+ data_vars={
282
+ "esa_step": xr.DataArray(
283
+ esa_steps,
284
+ dims=["epoch"],
285
+ ),
286
+ "coincidence_type": xr.DataArray(
287
+ np.ones(10),
288
+ dims=["event_met"],
289
+ ),
290
+ },
291
+ )
292
+ subset = hi_l1c.find_second_de_packet_data(l1b_dataset)
293
+ np.testing.assert_array_equal(subset.epoch.data, np.array([2, 4, 7, 9, 13]))
294
+
295
+
296
+ @pytest.fixture(scope="module")
297
+ def fake_spin_df():
298
+ """Generate a synthetic spin dataframe"""
299
+ # Generate some spin periods that vary by a random fraction of a second
300
+ spin_period = np.full(10, 15) + np.random.randn(10) / 10
301
+ d = {
302
+ "spin_start_met": np.add.accumulate(spin_period),
303
+ "spin_period_sec": spin_period,
304
+ }
305
+ spin_df = pd.DataFrame.from_dict(d)
306
+ return spin_df
307
+
308
+
309
+ def test_get_de_clock_ticks_for_esa_step(fake_spin_df):
310
+ """Test coverage for get_de_clock_ticks_for_esa_step function."""
311
+
312
+ # Test nominal cases where CCSDS met falls after 8th spin start and before
313
+ # the end spin in the table + 1/2 spin period
314
+ for _, spin_row in fake_spin_df.iloc[8:].iterrows():
315
+ for ccsds_met in np.linspace(
316
+ spin_row.spin_start_met,
317
+ spin_row.spin_start_met + np.floor(spin_row.spin_period_sec / 2),
318
+ 10,
319
+ ):
320
+ clock_tick_mets, clock_tick_weights = (
321
+ hi_l1c.get_de_clock_ticks_for_esa_step(ccsds_met, fake_spin_df)
322
+ )
323
+ np.testing.assert_array_equal(clock_tick_mets.shape, clock_tick_mets.shape)
324
+ # Verify last weight entry
325
+ exp_final_weight = (
326
+ np.absolute(
327
+ fake_spin_df.spin_start_met.to_numpy() - clock_tick_mets[-1]
328
+ ).min()
329
+ / DE_CLOCK_TICK_S
330
+ )
331
+ assert clock_tick_weights[-1] == exp_final_weight
332
+ assert np.all(clock_tick_weights[:-1] == 1)
333
+
334
+
335
+ def test_get_de_clock_ticks_for_esa_step_exceptions(fake_spin_df):
336
+ """Test the exception logic in the get_de_clock_ticks_for_esa_step function."""
337
+ # Test the ccsds_met being > 1/2 spin period past the spin start
338
+ bad_ccsds_met = (
339
+ fake_spin_df.iloc[8].spin_start_met
340
+ + fake_spin_df.iloc[8].spin_period_sec / 2
341
+ + 0.1
342
+ )
343
+ with pytest.raises(
344
+ ValueError, match="The difference between ccsds_met and spin_start_met"
345
+ ):
346
+ hi_l1c.get_de_clock_ticks_for_esa_step(bad_ccsds_met, fake_spin_df)
347
+
348
+ # Test the ccsds_met being too close to the start of the spin table
349
+ bad_ccsds_met = fake_spin_df.iloc[7].spin_start_met
350
+ with pytest.raises(
351
+ ValueError, match="Error determining start/end time for exposure time"
352
+ ):
353
+ hi_l1c.get_de_clock_ticks_for_esa_step(bad_ccsds_met, fake_spin_df)
354
+
355
+
134
356
  class TestCalibrationProductConfig:
135
357
  """
136
358
  All test coverage for the pd.DataFrame accessor extension "cal_prod_config".
@@ -138,7 +360,7 @@ class TestCalibrationProductConfig:
138
360
 
139
361
  def test_wrong_columns(self):
140
362
  """Test coverage for a dataframe with the wrong columns."""
141
- required_columns = CalibrationProductConfig.required_columns
363
+ required_columns = hi_l1c.CalibrationProductConfig.required_columns
142
364
  for exclude_column_name in required_columns:
143
365
  include_columns = set(required_columns) - {exclude_column_name}
144
366
  df = pd.DataFrame({col: [1, 2, 3] for col in include_columns})
@@ -147,10 +369,19 @@ class TestCalibrationProductConfig:
147
369
 
148
370
  def test_from_csv(self, hi_test_cal_prod_config_path):
149
371
  """Test coverage for read_csv function."""
372
+ df = hi_l1c.CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
373
+ assert isinstance(df["coincidence_type_list"][0, 1], tuple)
374
+
375
+ def test_added_coincidence_type_values_column(self, hi_test_cal_prod_config_path):
150
376
  df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
151
- assert isinstance(df["coincidence_type_list"][0, 1], list)
377
+ assert "coincidence_type_values" in df.columns
378
+ for _, row in df.iterrows():
379
+ for detect_string, val in zip(
380
+ row["coincidence_type_list"], row["coincidence_type_values"]
381
+ ):
382
+ assert val == CoincidenceBitmap.detector_hit_str_to_int(detect_string)
152
383
 
153
384
  def test_number_of_products(self, hi_test_cal_prod_config_path):
154
385
  """Test coverage for number of products accessor."""
155
- df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
386
+ df = hi_l1c.CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
156
387
  assert df.cal_prod_config.number_of_products == 2
@@ -1,4 +1,5 @@
1
1
  import numpy as np
2
+ import pandas as pd
2
3
 
3
4
  from imap_processing.cdf.utils import write_cdf
4
5
  from imap_processing.hi.l1a.hi_l1a import hi_l1a
@@ -10,29 +11,56 @@ def test_sci_de_decom(hi_l0_test_data_path):
10
11
  """Test science direct event data"""
11
12
 
12
13
  bin_data_path = hi_l0_test_data_path / "H90_sci_de_20241104.bin"
13
- processed_data = hi_l1a(bin_data_path, data_version="001")
14
+ processed_data = hi_l1a(bin_data_path)
14
15
 
15
16
  assert processed_data[0].attrs["Logical_source"] == "imap_hi_l1a_90sensor-de"
16
- assert processed_data[0].attrs["Data_version"] == "001"
17
17
 
18
18
  # TODO: Verify correct unpacking of sample data. Issue: #1186
19
19
 
20
20
  # Write to CDF
21
- cdf_filename = "imap_hi_l1a_90sensor-de_20241105_v001.cdf"
21
+ cdf_filename = "imap_hi_l1a_90sensor-de_20241105_v999.cdf"
22
22
  cdf_filepath = write_cdf(processed_data[0])
23
23
  assert cdf_filepath.name == cdf_filename
24
24
 
25
25
 
26
+ def test_diag_fee_decom(hi_l0_test_data_path):
27
+ """Test diag_fee data"""
28
+ bin_data_path = hi_l0_test_data_path / "H45_diag_fee_20250208.bin"
29
+ processed_data = hi_l1a(packet_file_path=bin_data_path)
30
+ dataset = processed_data[0]
31
+ cdf_filepath = write_cdf(processed_data[0], istp=False)
32
+ assert cdf_filepath.name == "imap_hi_l1a_45sensor-diagfee_20250208_v999.cdf"
33
+
34
+ assert np.unique(processed_data[0]["pkt_apid"].values) == HIAPID.H45_DIAG_FEE.value
35
+
36
+ validation_df = pd.read_csv(
37
+ hi_l0_test_data_path / "H45_diag_fee_20250208_verify.csv"
38
+ )
39
+ val_to_test_map = {
40
+ "PHVERNO": "version",
41
+ "PHTYPE": "type",
42
+ "PHSHF": "sec_hdr_flg",
43
+ "PHAPID": "pkt_apid",
44
+ "PHGROUPF": "seq_flgs",
45
+ "PHSEQCNT": "src_seq_ctr",
46
+ "PHDLEN": "pkt_len",
47
+ }
48
+ for col_name, series in validation_df.items():
49
+ if col_name == "timestamp":
50
+ continue
51
+ ds_var_name = val_to_test_map.get(col_name, col_name.lower())
52
+ np.testing.assert_array_equal(series.values, dataset[ds_var_name].data)
53
+
54
+
26
55
  def test_app_nhk_decom(hi_l0_test_data_path):
27
56
  """Test housekeeping data"""
28
57
 
29
58
  # Unpack housekeeping data
30
59
  bin_data_path = hi_l0_test_data_path / "H90_NHK_20241104.bin"
31
- processed_data = hi_l1a(packet_file_path=bin_data_path, data_version="001")
60
+ processed_data = hi_l1a(packet_file_path=bin_data_path)
32
61
 
33
62
  assert np.unique(processed_data[0]["pkt_apid"].values) == HIAPID.H90_APP_NHK.value
34
63
  assert processed_data[0].attrs["Logical_source"] == "imap_hi_l1a_90sensor-hk"
35
- assert processed_data[0].attrs["Data_version"] == "001"
36
64
  # TODO: compare with validation data once we have it. Issue: #1184
37
65
 
38
66
  # Write CDF
@@ -40,13 +68,13 @@ def test_app_nhk_decom(hi_l0_test_data_path):
40
68
 
41
69
  # TODO: ask Vivek about this date mismatch between the file name
42
70
  # and the data. May get resolved when we have good sample data.
43
- assert cem_raw_cdf_filepath.name == "imap_hi_l1a_90sensor-hk_20241105_v001.cdf"
71
+ assert cem_raw_cdf_filepath.name == "imap_hi_l1a_90sensor-hk_20241105_v999.cdf"
44
72
 
45
73
 
46
74
  def test_app_hist_decom(hi_l0_test_data_path):
47
75
  """Test histogram (SCI_CNT) data"""
48
76
  bin_data_path = hi_l0_test_data_path / "H90_sci_cnt_20241104.bin"
49
- processed_data = hi_l1a(packet_file_path=bin_data_path, data_version="001")
77
+ processed_data = hi_l1a(packet_file_path=bin_data_path)
50
78
 
51
79
  assert processed_data[0].attrs["Logical_source"] == "imap_hi_l1a_90sensor-hist"
52
80
  # TODO: compare with validation data once we have it. Issue: #1185
@@ -21,8 +21,8 @@ def test_parse_direct_events():
21
21
  # Encode the random events data into a bit-string
22
22
  bin_str = ""
23
23
  for i in range(n_events):
24
- bin_str += f"{exp_dict['trigger_id'][i]:02b}" # 2-bits for trigger_id
25
24
  bin_str += f"{exp_dict['de_tag'][i]:016b}" # 16-bits for de_tag
25
+ bin_str += f"{exp_dict['trigger_id'][i]:02b}" # 2-bits for trigger_id
26
26
  bin_str += f"{exp_dict['tof_1'][i]:010b}" # 10-bits for tof_1
27
27
  bin_str += f"{exp_dict['tof_2'][i]:010b}" # 10-bits for tof_2
28
28
  bin_str += f"{exp_dict['tof_3'][i]:010b}" # 10-bits for tof_3
@@ -30,8 +30,8 @@ def test_parse_direct_events():
30
30
  bytes_obj = bytes([int(bin_str[i : i + 8], 2) for i in range(0, len(bin_str), 8)])
31
31
  # Parse the fake events and check values
32
32
  de_dict = parse_direct_events(bytes_obj)
33
- for key in exp_dict.keys():
34
- np.testing.assert_array_equal(de_dict[key], exp_dict[key])
33
+ for key, expected_val in exp_dict.items():
34
+ np.testing.assert_array_equal(de_dict[key], expected_val)
35
35
 
36
36
 
37
37
  def test_create_dataset():
@@ -7,6 +7,7 @@ import xarray as xr
7
7
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
8
8
  from imap_processing.hi.utils import (
9
9
  HIAPID,
10
+ CoincidenceBitmap,
10
11
  create_dataset_variables,
11
12
  full_dataarray,
12
13
  parse_sensor_number,
@@ -74,13 +75,13 @@ def test_full_dataarray(name, shape, fill_value, expected_shape):
74
75
  @pytest.mark.parametrize(
75
76
  "var_names, shape, fill_value, lookup_str",
76
77
  [
77
- (["delta_t_ab", "delta_t_ac1"], 5, None, "hi_de_{0}"),
78
+ (["tof_ab", "tof_ac1"], 5, None, "hi_de_{0}"),
78
79
  (["hae_latitude"], (3, 5), 0, "hi_pset_{0}"),
79
80
  ],
80
81
  )
81
82
  def test_create_dataset_variables(var_names, shape, fill_value, lookup_str):
82
83
  """Test coverage for `imap_processing.hi.utils.create_dataset_variables`"""
83
- var_names = ["delta_t_ab", "delta_t_ac1", "delta_t_bc1"]
84
+ var_names = ["tof_ab", "tof_ac1", "tof_bc1"]
84
85
  l1b_de_vars = create_dataset_variables(
85
86
  var_names, shape, fill_value=fill_value, att_manager_lookup_str="hi_de_{0}"
86
87
  )
@@ -100,3 +101,24 @@ def test_create_dataset_variables(var_names, shape, fill_value, lookup_str):
100
101
  assert data_array.shape == shape
101
102
  expected_fill_value = fill_value if fill_value is not None else attrs["FILLVAL"]
102
103
  np.testing.assert_array_equal(data_array, expected_fill_value)
104
+
105
+
106
+ @pytest.mark.parametrize(
107
+ "sensor_hit_str, expected_val",
108
+ [
109
+ ("ABC1C2", 15),
110
+ ("ABC1", 14),
111
+ ("AB", 12),
112
+ ("AC1C2", 11),
113
+ ("AC1", 10),
114
+ ("A", 8),
115
+ ("BC1C2", 7),
116
+ ("BC1", 6),
117
+ ("B", 4),
118
+ ("C1C2", 3),
119
+ ("C1", 2),
120
+ ],
121
+ )
122
+ def test_coincidence_type_string_to_int(sensor_hit_str, expected_val):
123
+ """Test coverage for coincidence_type_string_to_int function"""
124
+ assert CoincidenceBitmap.detector_hit_str_to_int(sensor_hit_str) == expected_val