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
@@ -0,0 +1,716 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import pytest
4
+ import xarray as xr
5
+
6
+ from imap_processing import imap_module_directory
7
+ from imap_processing.hit.l1a import hit_l1a
8
+ from imap_processing.hit.l1b.hit_l1b import (
9
+ SUMMED_PARTICLE_ENERGY_RANGE_MAPPING,
10
+ hit_l1b,
11
+ )
12
+ from imap_processing.hit.l2.hit_l2 import (
13
+ FILLVAL_FLOAT32,
14
+ N_AZIMUTH,
15
+ SECONDS_PER_10_MIN,
16
+ SECONDS_PER_MIN,
17
+ STANDARD_PARTICLE_ENERGY_RANGE_MAPPING,
18
+ VALID_SECTORED_SPECIES,
19
+ add_systematic_uncertainties,
20
+ add_total_uncertainties,
21
+ build_ancillary_dataset,
22
+ calculate_intensities,
23
+ calculate_intensities_for_a_species,
24
+ calculate_intensities_for_all_species,
25
+ get_species_ancillary_data,
26
+ hit_l2,
27
+ process_sectored_intensity_data,
28
+ process_standard_intensity_data,
29
+ process_summed_intensity_data,
30
+ reshape_for_sectored,
31
+ )
32
+
33
+
34
+ @pytest.fixture(scope="module")
35
+ def sci_packet_filepath():
36
+ """Set path to test data file"""
37
+ return imap_module_directory / "tests/hit/test_data/sci_sample.ccsds"
38
+
39
+
40
+ @pytest.fixture
41
+ def dependencies(sci_packet_filepath):
42
+ """Get dependencies for L2 processing"""
43
+ # Create dictionary of dependencies
44
+ data_dict = {}
45
+ l1a_datasets = hit_l1a.hit_l1a(sci_packet_filepath)
46
+ for l1a_dataset in l1a_datasets:
47
+ l1a_data_dict = {}
48
+ if l1a_dataset.attrs["Logical_source"] == "imap_hit_l1a_counts":
49
+ l1a_data_dict["imap_hit_l1a_counts"] = l1a_dataset
50
+ l1b_datasets = hit_l1b(l1a_data_dict)
51
+ for l1b_dataset in l1b_datasets:
52
+ data_dict[l1b_dataset.attrs["Logical_source"]] = l1b_dataset
53
+ return data_dict
54
+
55
+
56
+ @pytest.fixture
57
+ def l1b_summed_rates_dataset(dependencies):
58
+ """Get L1B summed rates dataset to test l2 processing function"""
59
+ return dependencies["imap_hit_l1b_summed-rates"]
60
+
61
+
62
+ @pytest.fixture
63
+ def l1b_standard_rates_dataset(dependencies):
64
+ """Get L1B standard rates dataset to test l2 processing function"""
65
+ return dependencies["imap_hit_l1b_standard-rates"]
66
+
67
+
68
+ @pytest.fixture
69
+ def l1b_sectored_rates_dataset(dependencies):
70
+ """Get L1B standard rates dataset to test l2 processing function"""
71
+ return dependencies["imap_hit_l1b_sectored-rates"]
72
+
73
+
74
+ def _check_ancillary_dataset(
75
+ ancillary_ds,
76
+ species_array,
77
+ delta_e,
78
+ geometry_factors,
79
+ efficiencies,
80
+ b,
81
+ expected_delta_time,
82
+ ):
83
+ # Helper function - not a test
84
+
85
+ shape = species_array.shape
86
+
87
+ # Assert that all expected variables are present
88
+ assert set(ancillary_ds.data_vars) == {
89
+ "delta_e",
90
+ "geometry_factor",
91
+ "efficiency",
92
+ "b",
93
+ "delta_time",
94
+ }
95
+
96
+ # Check that shapes match
97
+ assert ancillary_ds["delta_e"].shape == shape
98
+ assert ancillary_ds["delta_time"].shape == (len(species_array.coords["epoch"]),)
99
+
100
+ # Check values
101
+ np.testing.assert_array_equal(ancillary_ds["delta_e"].values, delta_e)
102
+ np.testing.assert_array_equal(
103
+ ancillary_ds["geometry_factor"].values, geometry_factors
104
+ )
105
+ np.testing.assert_array_equal(ancillary_ds["efficiency"].values, efficiencies)
106
+ np.testing.assert_array_equal(ancillary_ds["b"].values, b)
107
+ np.testing.assert_array_equal(
108
+ ancillary_ds["delta_time"].values,
109
+ np.full(len(species_array.epoch), expected_delta_time),
110
+ )
111
+
112
+ # Check coordinates match
113
+ for coord in species_array.coords:
114
+ assert coord in ancillary_ds.coords
115
+ np.testing.assert_array_equal(
116
+ species_array.coords[coord], ancillary_ds.coords[coord]
117
+ )
118
+
119
+
120
+ def test_build_ancillary_dataset_sectored():
121
+ """
122
+ Test the build_ancillary_dataset function for sectored data
123
+ """
124
+ np.random.seed(42) # Set a random seed for reproducibility
125
+ epoch = np.array(["2025-01-01T00:00", "2025-01-01T00:01"], dtype="datetime64[m]")
126
+ energy_mean = [1.8, 4, 6]
127
+ declination = np.arange(8)
128
+ azimuth = np.arange(15)
129
+
130
+ species_array = xr.DataArray(
131
+ data=np.random.rand(2, 3, 15, 8), # (epoch, energy_mean, azimuth, declination)
132
+ dims=("epoch", "energy_mean", "azimuth", "declination"),
133
+ coords={
134
+ "epoch": epoch,
135
+ "energy_mean": energy_mean,
136
+ "declination": declination,
137
+ "azimuth": azimuth,
138
+ },
139
+ name="h",
140
+ )
141
+
142
+ shape = species_array.shape
143
+ delta_e = np.full(shape, 1.0)
144
+ geometry_factors = np.full(shape, 2.0)
145
+ efficiencies = np.full(shape, 0.5)
146
+ b = np.full(shape, 0.1)
147
+
148
+ ancillary_ds = build_ancillary_dataset(
149
+ delta_e, geometry_factors, efficiencies, b, species_array
150
+ )
151
+ _check_ancillary_dataset(
152
+ ancillary_ds,
153
+ species_array,
154
+ delta_e,
155
+ geometry_factors,
156
+ efficiencies,
157
+ b,
158
+ SECONDS_PER_10_MIN,
159
+ )
160
+
161
+
162
+ def test_build_ancillary_dataset_nonsectored():
163
+ """
164
+ Test the build_ancillary_dataset function for non-sectored data.
165
+
166
+ Non-sectored datasets are either L2 standard or L2 summed datasets
167
+ They both have the same shape (epoch, energy_mean).
168
+ """
169
+ np.random.seed(42) # Set a random seed for reproducibility
170
+ epoch = np.array(["2025-01-01T00:00", "2025-01-01T00:01"], dtype="datetime64[m]")
171
+ energy_mean = [1.8, 4, 6]
172
+
173
+ species_array = xr.DataArray(
174
+ data=np.random.rand(2, 3), # (epoch, energy_mean)
175
+ dims=("epoch", "energy_mean"),
176
+ coords={"epoch": epoch, "energy_mean": energy_mean},
177
+ name="h",
178
+ )
179
+
180
+ shape = species_array.shape
181
+ delta_e = np.full(shape, 1.0)
182
+ geometry_factors = np.full(shape, 2.0)
183
+ efficiencies = np.full(shape, 0.5)
184
+ b = np.full(shape, 0.1)
185
+
186
+ ancillary_ds = build_ancillary_dataset(
187
+ delta_e, geometry_factors, efficiencies, b, species_array
188
+ )
189
+ _check_ancillary_dataset(
190
+ ancillary_ds,
191
+ species_array,
192
+ delta_e,
193
+ geometry_factors,
194
+ efficiencies,
195
+ b,
196
+ SECONDS_PER_MIN,
197
+ )
198
+
199
+
200
+ def test_get_species_ancillary_data():
201
+ """Test the get_species_ancillary_data function."""
202
+
203
+ # Mock ancillary data for dynamic threshold states 0 and 1
204
+ ancillary_data_frames = {
205
+ 0: pd.DataFrame(
206
+ {
207
+ "species": ["h", "h", "he", "he"],
208
+ "lower energy (mev)": [1, 2, 1, 2],
209
+ "delta e (mev)": [0.1, 0.2, 0.3, 0.4],
210
+ "geometry factor (cm2 sr)": [10, 20, 30, 40],
211
+ "efficiency": [0.9, 0.8, 0.7, 0.6],
212
+ "b": [0.01, 0.02, 0.03, 0.04],
213
+ }
214
+ ),
215
+ 1: pd.DataFrame(
216
+ {
217
+ "species": ["h", "h", "he", "he"],
218
+ "lower energy (mev)": [1, 2, 1, 2],
219
+ "delta e (mev)": [0.15, 0.25, 0.35, 0.45],
220
+ "geometry factor (cm2 sr)": [15, 25, 35, 45],
221
+ "efficiency": [0.85, 0.75, 0.65, 0.55],
222
+ "b": [0.015, 0.025, 0.035, 0.045],
223
+ }
224
+ ),
225
+ }
226
+
227
+ # Test for dynamic threshold state 0 and species "h"
228
+ result = get_species_ancillary_data(0, ancillary_data_frames, "h")
229
+ expected = {
230
+ "delta_e": np.array([[0.1], [0.2]]),
231
+ "geometry_factor": np.array([[10], [20]]),
232
+ "efficiency": np.array([[0.9], [0.8]]),
233
+ "b": np.array([[0.01], [0.02]]),
234
+ }
235
+ for key, value in expected.items():
236
+ np.testing.assert_array_equal(result[key], value)
237
+
238
+ # Test for dynamic threshold state 1 and species "he"
239
+ result = get_species_ancillary_data(1, ancillary_data_frames, "he")
240
+ expected = {
241
+ "delta_e": np.array([[0.35], [0.45]]),
242
+ "geometry_factor": np.array([[35], [45]]),
243
+ "efficiency": np.array([[0.65], [0.55]]),
244
+ "b": np.array([[0.035], [0.045]]),
245
+ }
246
+ for key in expected:
247
+ np.testing.assert_array_equal(result[key], expected[key])
248
+
249
+
250
+ def test_reshape_for_sectored():
251
+ """
252
+ Test the reshape_for_sectored function.
253
+ """
254
+ # Mock input data: 3D array (epoch, energy, declination)
255
+ np.random.seed(42) # Set a random seed for reproducibility
256
+ epoch, energy, declination = 2, 3, 8
257
+ input_array = np.random.rand(epoch, energy, declination)
258
+
259
+ # Expected output shape: 4D array (epoch, energy, azimuth, declination)
260
+ expected_shape = (epoch, energy, N_AZIMUTH, declination)
261
+
262
+ # Call the function
263
+ reshaped_array = reshape_for_sectored(input_array)
264
+
265
+ # Assertions
266
+ assert reshaped_array.shape == expected_shape, "Output shape mismatch"
267
+ for azimuth in range(N_AZIMUTH):
268
+ np.testing.assert_array_equal(
269
+ reshaped_array[:, :, azimuth, :],
270
+ input_array,
271
+ err_msg=f"Mismatch in azimuth dimension {azimuth}",
272
+ )
273
+
274
+
275
+ def test_calculate_intensities_for_all_species():
276
+ """Test the calculate_intensities_for_all_species function."""
277
+ # Sample input data
278
+ l2_dataset = xr.Dataset(
279
+ {
280
+ "dynamic_threshold_state": ("epoch", np.array([0, 1])),
281
+ "h": (
282
+ ("epoch", "h_energy_mean"),
283
+ np.array([[100, 200, 300], [400, 500, 600]]).astype("float32"),
284
+ ),
285
+ "h_energy_mean": (
286
+ "h_energy_mean",
287
+ np.array([1.0, 2.0, 3.0]).astype("float32"),
288
+ ),
289
+ "h_energy_delta_minus": (
290
+ "h_energy_mean",
291
+ np.array([0.1, 0.1, 0.1]).astype("float32"),
292
+ ),
293
+ "h_energy_delta_plus": (
294
+ "h_energy_mean",
295
+ np.array([0.1, 0.1, 0.1]).astype("float32"),
296
+ ),
297
+ "ni": (
298
+ ("epoch", "ni_energy_mean"),
299
+ np.array([[150, 250, 350], [450, 550, 650]]).astype("float32"),
300
+ ),
301
+ "ni_energy_mean": (
302
+ "ni_energy_mean",
303
+ np.array([1.5, 2.5, 3.5]).astype("float32"),
304
+ ),
305
+ "ni_energy_delta_minus": (
306
+ "ni_energy_mean",
307
+ np.array([0.1, 0.1, 0.1]).astype("float32"),
308
+ ),
309
+ "ni_energy_delta_plus": (
310
+ "ni_energy_mean",
311
+ np.array([0.1, 0.1, 0.1]).astype("float32"),
312
+ ),
313
+ }
314
+ )
315
+ ancillary_data_frames = {
316
+ 0: pd.DataFrame(
317
+ {
318
+ "species": ["h", "h", "h", "ni", "ni", "ni"],
319
+ "lower energy (mev)": [0.9, 1.9, 2.9, 1.4, 2.4, 3.4],
320
+ "delta e (mev)": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
321
+ "geometry factor (cm2 sr)": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
322
+ "efficiency": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
323
+ "b": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
324
+ }
325
+ ),
326
+ 1: pd.DataFrame(
327
+ {
328
+ "species": ["h", "h", "h", "ni", "ni", "ni"],
329
+ "lower energy (mev)": [0.9, 1.9, 2.9, 1.4, 2.4, 3.4],
330
+ "delta e (mev)": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
331
+ "geometry factor (cm2 sr)": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
332
+ "efficiency": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
333
+ "b": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
334
+ }
335
+ ),
336
+ }
337
+
338
+ # Expected output
339
+ expected_intensities_h = xr.DataArray(
340
+ [[8.333333, 16.666667, 25.0], [33.333333, 41.666667, 50.0]],
341
+ dims=["epoch", "h_energy_mean"],
342
+ )
343
+ expected_intensities_ni = xr.DataArray(
344
+ [[12.5, 20.833333, 29.166667], [37.5, 45.833333, 54.166667]],
345
+ dims=["epoch", "ni_energy_mean"],
346
+ )
347
+
348
+ # Call the function
349
+ l2_dataset = calculate_intensities_for_all_species(
350
+ l2_dataset, ancillary_data_frames, valid_data_variables=["h", "ni"]
351
+ )
352
+
353
+ # Assertions
354
+ (
355
+ np.testing.assert_allclose(
356
+ l2_dataset["h"].values, expected_intensities_h.values
357
+ ),
358
+ ("Intensities mismatch for H"),
359
+ )
360
+ (
361
+ np.testing.assert_allclose(
362
+ l2_dataset["ni"].values, expected_intensities_ni.values
363
+ ),
364
+ ("Intensities mismatch for He"),
365
+ )
366
+
367
+
368
+ def test_calculate_intensities_for_a_species():
369
+ """Test the calculate_intensities_for_a_species function."""
370
+ # Sample input data
371
+ species_variable = "h"
372
+ l2_dataset = xr.Dataset(
373
+ {
374
+ "h": (
375
+ ("epoch", "h_energy_mean"),
376
+ np.array([[100.0, 200.0, 300.0], [400.0, 500.0, 600.0]]).astype(
377
+ "float32"
378
+ ),
379
+ ),
380
+ "dynamic_threshold_state": ("epoch", np.array([0, 1])),
381
+ "h_energy_mean": (
382
+ "h_energy_mean",
383
+ np.array([1.0, 2.0, 3.0]).astype("float32"),
384
+ ),
385
+ "h_energy_delta_minus": (
386
+ "h_energy_mean",
387
+ np.array([0.1, 0.1, 0.1]).astype("float32"),
388
+ ),
389
+ }
390
+ )
391
+ ancillary_data_frames = {
392
+ 0: pd.DataFrame(
393
+ {
394
+ "species": ["h", "h", "h"],
395
+ "lower energy (mev)": [0.9, 1.9, 2.9],
396
+ "delta e (mev)": [0.2, 0.5, 0.5],
397
+ "geometry factor (cm2 sr)": [1.0, 1.0, 1.5],
398
+ "efficiency": [1, 1, 1],
399
+ "b": [0, 0, 0],
400
+ }
401
+ ),
402
+ 1: pd.DataFrame(
403
+ {
404
+ "species": ["h", "h", "h"],
405
+ "lower energy (mev)": [0.9, 1.9, 2.9],
406
+ "delta e (mev)": [0.4, 0.5, 0.5],
407
+ "geometry factor (cm2 sr)": [1.5, 1.51, 1.51],
408
+ "efficiency": [1, 1, 1],
409
+ "b": [0, 0, 0],
410
+ }
411
+ ),
412
+ }
413
+
414
+ # Expected output
415
+ expected_intensities = xr.DataArray(
416
+ [[8.333333, 6.666667, 6.666667], [11.111111, 11.037528, 13.245033]],
417
+ dims=["epoch", "h_energy_mean"],
418
+ )
419
+
420
+ # Call the function
421
+ l2_dataset = calculate_intensities_for_a_species(
422
+ species_variable, l2_dataset, ancillary_data_frames
423
+ )
424
+
425
+ # Assertions
426
+ (
427
+ np.testing.assert_allclose(l2_dataset["h"].values, expected_intensities.values),
428
+ ("Intensities mismatch"),
429
+ )
430
+
431
+
432
+ def test_calculate_intensities():
433
+ """Test the calculate_intensities function."""
434
+ # Create sample function inputs
435
+ rates = xr.DataArray(
436
+ data=[10.0, 20.0, FILLVAL_FLOAT32, 40.0],
437
+ dims=["epoch"],
438
+ coords={"epoch": [0, 1, 2, 3]},
439
+ )
440
+ factors = xr.Dataset(
441
+ {
442
+ "delta_time": ("epoch", [60.0, 60.0, 60.0, 60.0]),
443
+ "delta_e": ("epoch", [1.0, 1.0, 1.0, 1.0]),
444
+ "geometry_factor": ("epoch", [2.0, 2.0, 2.0, 2.0]),
445
+ "efficiency": ("epoch", [0.5, 0.5, 0.5, 0.5]),
446
+ "b": ("epoch", [0.0, 0, 0, 0]),
447
+ }
448
+ )
449
+
450
+ # Expected output
451
+ expected_intensity = xr.DataArray(
452
+ data=[0.1666667, 0.3333333, FILLVAL_FLOAT32, 0.6666667],
453
+ dims=["epoch"],
454
+ coords={"epoch": [0, 1, 2, 3]},
455
+ )
456
+
457
+ # Call the function
458
+ result = calculate_intensities(rates, factors)
459
+
460
+ # Assertions
461
+ xr.testing.assert_allclose(result, expected_intensity)
462
+
463
+
464
+ def test_add_systematic_uncertainties():
465
+ """Test the add_systematic_uncertainties function."""
466
+ # Create sample function inputs
467
+ np.random.seed(42) # Set a random seed for reproducibility
468
+ particle = "h"
469
+ datasets = [
470
+ xr.Dataset(
471
+ {"h": (("epoch", "h_energy_mean"), np.random.rand(2, 3).astype("float32"))}
472
+ ),
473
+ xr.Dataset(
474
+ {
475
+ "h": (
476
+ ("epoch", "h_energy_mean", "azimuth", "declination"),
477
+ np.random.rand(2, 3, 15, 8).astype("float32"),
478
+ )
479
+ }
480
+ ),
481
+ ]
482
+
483
+ for dataset in datasets:
484
+ # Call the function
485
+ updated_dataset = add_systematic_uncertainties(dataset, particle)
486
+ # Assertions
487
+ assert f"{particle}_sys_err_minus" in updated_dataset.data_vars
488
+ assert f"{particle}_sys_err_plus" in updated_dataset.data_vars
489
+ assert (
490
+ updated_dataset[f"{particle}_sys_err_minus"].shape
491
+ == dataset[particle].shape
492
+ )
493
+ assert (
494
+ updated_dataset[f"{particle}_sys_err_plus"].shape == dataset[particle].shape
495
+ )
496
+ np.testing.assert_array_equal(
497
+ updated_dataset[f"{particle}_sys_err_minus"].values, 0
498
+ )
499
+ np.testing.assert_array_equal(
500
+ updated_dataset[f"{particle}_sys_err_plus"].values, 0
501
+ )
502
+
503
+
504
+ def test_add_total_uncertainties():
505
+ # Create a sample dataset
506
+ np.random.seed(42) # Set a random seed for reproducibility
507
+ data = np.random.rand(10, 5).astype(np.float32)
508
+ stat_uncert_minus = np.random.rand(10, 5).astype(np.float32)
509
+ stat_uncert_plus = np.random.rand(10, 5).astype(np.float32)
510
+ sys_err_minus = np.zeros(
511
+ (10, 5), dtype=np.float32
512
+ ) # zeros, unless changed during mission
513
+ sys_err_plus = np.zeros(
514
+ (10, 5), dtype=np.float32
515
+ ) # zeros, unless changed during mission
516
+
517
+ dataset = xr.Dataset(
518
+ {
519
+ "particle": (("dim_0", "dim_1"), data),
520
+ "particle_stat_uncert_minus": (("dim_0", "dim_1"), stat_uncert_minus),
521
+ "particle_stat_uncert_plus": (("dim_0", "dim_1"), stat_uncert_plus),
522
+ "particle_sys_err_minus": (("dim_0", "dim_1"), sys_err_minus),
523
+ "particle_sys_err_plus": (("dim_0", "dim_1"), sys_err_plus),
524
+ }
525
+ )
526
+
527
+ # Call the function
528
+ updated_dataset = add_total_uncertainties(dataset, "particle")
529
+
530
+ # Assertions
531
+ np.testing.assert_array_almost_equal(
532
+ updated_dataset["particle_total_uncert_minus"].values,
533
+ np.sqrt(np.square(stat_uncert_minus) + np.square(sys_err_minus)),
534
+ )
535
+ np.testing.assert_array_almost_equal(
536
+ updated_dataset["particle_total_uncert_plus"].values,
537
+ np.sqrt(np.square(stat_uncert_plus) + np.square(sys_err_plus)),
538
+ )
539
+
540
+ # Check that the dimensions and attributes are preserved
541
+ assert (
542
+ updated_dataset["particle_total_uncert_minus"].dims == dataset["particle"].dims
543
+ )
544
+ assert (
545
+ updated_dataset["particle_total_uncert_plus"].dims == dataset["particle"].dims
546
+ )
547
+
548
+
549
+ def test_process_sectored_intensity_data(l1b_sectored_rates_dataset):
550
+ """Test the variables in the sectored intensity dataset"""
551
+
552
+ l2_sectored_intensity_dataset = process_sectored_intensity_data(
553
+ l1b_sectored_rates_dataset
554
+ )
555
+
556
+ # Check that a xarray dataset is returned
557
+ assert isinstance(l2_sectored_intensity_dataset, xr.Dataset)
558
+
559
+ valid_coords = {
560
+ "epoch",
561
+ "azimuth",
562
+ "declination",
563
+ "h_energy_mean",
564
+ "he4_energy_mean",
565
+ "cno_energy_mean",
566
+ "nemgsi_energy_mean",
567
+ "fe_energy_mean",
568
+ }
569
+
570
+ # Check that the dataset has the correct coords and variables
571
+ assert valid_coords == set(l2_sectored_intensity_dataset.coords), (
572
+ "Coordinates mismatch"
573
+ )
574
+
575
+ assert "dynamic_threshold_state" in l2_sectored_intensity_dataset.data_vars
576
+
577
+ for particle in VALID_SECTORED_SPECIES:
578
+ assert f"{particle}" in l2_sectored_intensity_dataset.data_vars
579
+ assert (
580
+ f"{particle}_stat_uncert_minus" in l2_sectored_intensity_dataset.data_vars
581
+ )
582
+ assert f"{particle}_stat_uncert_plus" in l2_sectored_intensity_dataset.data_vars
583
+ assert f"{particle}_sys_err_minus" in l2_sectored_intensity_dataset.data_vars
584
+ assert f"{particle}_sys_err_plus" in l2_sectored_intensity_dataset.data_vars
585
+ assert (
586
+ f"{particle}_energy_delta_minus" in l2_sectored_intensity_dataset.data_vars
587
+ )
588
+ assert (
589
+ f"{particle}_energy_delta_plus" in l2_sectored_intensity_dataset.data_vars
590
+ )
591
+
592
+
593
+ def test_process_summed_intensity_data(l1b_summed_rates_dataset):
594
+ """Test the variables in the summed intensity dataset"""
595
+
596
+ l2_summed_intensity_dataset = process_summed_intensity_data(
597
+ l1b_summed_rates_dataset
598
+ )
599
+
600
+ # Check that a xarray dataset is returned
601
+ assert isinstance(l2_summed_intensity_dataset, xr.Dataset)
602
+
603
+ valid_coords = {
604
+ "epoch",
605
+ "h_energy_mean",
606
+ "he3_energy_mean",
607
+ "he4_energy_mean",
608
+ "he_energy_mean",
609
+ "c_energy_mean",
610
+ "o_energy_mean",
611
+ "fe_energy_mean",
612
+ "n_energy_mean",
613
+ "si_energy_mean",
614
+ "mg_energy_mean",
615
+ "s_energy_mean",
616
+ "ar_energy_mean",
617
+ "ca_energy_mean",
618
+ "na_energy_mean",
619
+ "al_energy_mean",
620
+ "ne_energy_mean",
621
+ "ni_energy_mean",
622
+ }
623
+
624
+ # Check that the dataset has the correct coords and variables
625
+ assert valid_coords == set(l2_summed_intensity_dataset.coords), (
626
+ "Coordinates mismatch"
627
+ )
628
+
629
+ assert "dynamic_threshold_state" in l1b_summed_rates_dataset.data_vars
630
+
631
+ for particle in SUMMED_PARTICLE_ENERGY_RANGE_MAPPING.keys():
632
+ assert f"{particle}" in l2_summed_intensity_dataset.data_vars
633
+ assert f"{particle}_stat_uncert_minus" in l2_summed_intensity_dataset.data_vars
634
+ assert f"{particle}_stat_uncert_plus" in l2_summed_intensity_dataset.data_vars
635
+ assert f"{particle}_sys_err_minus" in l2_summed_intensity_dataset.data_vars
636
+ assert f"{particle}_sys_err_plus" in l2_summed_intensity_dataset.data_vars
637
+ assert f"{particle}_energy_delta_minus" in l2_summed_intensity_dataset.data_vars
638
+ assert f"{particle}_energy_delta_plus" in l2_summed_intensity_dataset.data_vars
639
+
640
+
641
+ def test_process_standard_intensity_data(l1b_standard_rates_dataset):
642
+ """Test the variables in the standard intensity dataset"""
643
+
644
+ l2_standard_intensity_dataset = process_standard_intensity_data(
645
+ l1b_standard_rates_dataset
646
+ )
647
+
648
+ # Check that a xarray dataset is returned
649
+ assert isinstance(l2_standard_intensity_dataset, xr.Dataset)
650
+
651
+ valid_coords = {
652
+ "epoch",
653
+ "h_energy_mean",
654
+ "he3_energy_mean",
655
+ "he4_energy_mean",
656
+ "he_energy_mean",
657
+ "c_energy_mean",
658
+ "n_energy_mean",
659
+ "o_energy_mean",
660
+ "ne_energy_mean",
661
+ "na_energy_mean",
662
+ "mg_energy_mean",
663
+ "al_energy_mean",
664
+ "si_energy_mean",
665
+ "s_energy_mean",
666
+ "ar_energy_mean",
667
+ "ca_energy_mean",
668
+ "fe_energy_mean",
669
+ "ni_energy_mean",
670
+ }
671
+
672
+ # Check that the dataset has the correct coords and variables
673
+ assert valid_coords == set(l2_standard_intensity_dataset.coords), (
674
+ "Coordinates mismatch"
675
+ )
676
+
677
+ assert "dynamic_threshold_state" in l1b_standard_rates_dataset.data_vars
678
+
679
+ for particle in STANDARD_PARTICLE_ENERGY_RANGE_MAPPING.keys():
680
+ assert f"{particle}" in l2_standard_intensity_dataset.data_vars
681
+ assert (
682
+ f"{particle}_stat_uncert_minus" in l2_standard_intensity_dataset.data_vars
683
+ )
684
+ assert f"{particle}_stat_uncert_plus" in l2_standard_intensity_dataset.data_vars
685
+ assert f"{particle}_sys_err_minus" in l2_standard_intensity_dataset.data_vars
686
+ assert f"{particle}_sys_err_plus" in l2_standard_intensity_dataset.data_vars
687
+ assert (
688
+ f"{particle}_energy_delta_minus" in l2_standard_intensity_dataset.data_vars
689
+ )
690
+ assert (
691
+ f"{particle}_energy_delta_plus" in l2_standard_intensity_dataset.data_vars
692
+ )
693
+
694
+
695
+ def test_hit_l2(dependencies):
696
+ """Test creating L2 datasets ready for CDF output
697
+
698
+ Creates a list of xarray datasets for L2 products.
699
+
700
+ Parameters
701
+ ----------
702
+ dependencies : dict
703
+ Dictionary of L1B datasets
704
+ """
705
+ # TODO: update assertions after science data processing is completed
706
+ l2_datasets = hit_l2(dependencies["imap_hit_l1b_summed-rates"])
707
+ assert len(l2_datasets) == 1
708
+ assert l2_datasets[0].attrs["Logical_source"] == "imap_hit_l2_summed-intensity"
709
+
710
+ l2_datasets = hit_l2(dependencies["imap_hit_l1b_standard-rates"])
711
+ assert len(l2_datasets) == 1
712
+ assert l2_datasets[0].attrs["Logical_source"] == "imap_hit_l2_standard-intensity"
713
+
714
+ l2_datasets = hit_l2(dependencies["imap_hit_l1b_sectored-rates"])
715
+ assert len(l2_datasets) == 1
716
+ assert l2_datasets[0].attrs["Logical_source"] == "imap_hit_l2_macropixel-intensity"