imap-processing 0.12.0__py3-none-any.whl → 0.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of imap-processing might be problematic. Click here for more details.

Files changed (272) hide show
  1. imap_processing/__init__.py +1 -0
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +1 -2
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -12
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +569 -0
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +5 -5
  9. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +20 -1
  10. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  11. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  12. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -0
  13. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  14. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +16 -0
  15. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +178 -5
  16. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -19
  18. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +8 -48
  19. imap_processing/cdf/utils.py +41 -33
  20. imap_processing/cli.py +463 -234
  21. imap_processing/codice/codice_l1a.py +260 -47
  22. imap_processing/codice/codice_l1b.py +51 -152
  23. imap_processing/codice/constants.py +38 -1
  24. imap_processing/ena_maps/ena_maps.py +658 -65
  25. imap_processing/ena_maps/utils/coordinates.py +1 -1
  26. imap_processing/ena_maps/utils/spatial_utils.py +10 -5
  27. imap_processing/glows/l1a/glows_l1a.py +28 -99
  28. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  29. imap_processing/glows/l1b/glows_l1b.py +1 -4
  30. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  31. imap_processing/glows/l2/glows_l2.py +2 -5
  32. imap_processing/hi/l1a/hi_l1a.py +31 -12
  33. imap_processing/hi/l1b/hi_l1b.py +80 -43
  34. imap_processing/hi/l1c/hi_l1c.py +12 -16
  35. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  36. imap_processing/hit/hit_utils.py +93 -35
  37. imap_processing/hit/l0/decom_hit.py +3 -1
  38. imap_processing/hit/l1a/hit_l1a.py +30 -25
  39. imap_processing/hit/l1b/constants.py +6 -2
  40. imap_processing/hit/l1b/hit_l1b.py +279 -318
  41. imap_processing/hit/l2/constants.py +37 -0
  42. imap_processing/hit/l2/hit_l2.py +373 -264
  43. imap_processing/ialirt/l0/parse_mag.py +138 -10
  44. imap_processing/ialirt/l0/process_swapi.py +69 -0
  45. imap_processing/ialirt/l0/process_swe.py +318 -22
  46. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -212
  47. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  48. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  49. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  50. imap_processing/ialirt/utils/grouping.py +1 -1
  51. imap_processing/idex/idex_constants.py +9 -1
  52. imap_processing/idex/idex_l0.py +22 -8
  53. imap_processing/idex/idex_l1a.py +75 -44
  54. imap_processing/idex/idex_l1b.py +9 -8
  55. imap_processing/idex/idex_l2a.py +79 -45
  56. imap_processing/idex/idex_l2b.py +120 -0
  57. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -39
  58. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  59. imap_processing/lo/l0/lo_science.py +1 -2
  60. imap_processing/lo/l1a/lo_l1a.py +1 -4
  61. imap_processing/lo/l1b/lo_l1b.py +527 -6
  62. imap_processing/lo/l1b/tof_conversions.py +11 -0
  63. imap_processing/lo/l1c/lo_l1c.py +1 -4
  64. imap_processing/mag/constants.py +43 -0
  65. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  66. imap_processing/mag/l1a/mag_l1a.py +2 -9
  67. imap_processing/mag/l1a/mag_l1a_data.py +10 -10
  68. imap_processing/mag/l1b/mag_l1b.py +84 -17
  69. imap_processing/mag/l1c/interpolation_methods.py +180 -3
  70. imap_processing/mag/l1c/mag_l1c.py +236 -70
  71. imap_processing/mag/l2/mag_l2.py +140 -0
  72. imap_processing/mag/l2/mag_l2_data.py +288 -0
  73. imap_processing/spacecraft/quaternions.py +1 -3
  74. imap_processing/spice/geometry.py +3 -3
  75. imap_processing/spice/kernels.py +0 -276
  76. imap_processing/spice/pointing_frame.py +257 -0
  77. imap_processing/spice/repoint.py +48 -19
  78. imap_processing/spice/spin.py +38 -33
  79. imap_processing/spice/time.py +24 -0
  80. imap_processing/swapi/l1/swapi_l1.py +16 -12
  81. imap_processing/swapi/l2/swapi_l2.py +116 -4
  82. imap_processing/swapi/swapi_utils.py +32 -0
  83. imap_processing/swe/l1a/swe_l1a.py +2 -9
  84. imap_processing/swe/l1a/swe_science.py +8 -11
  85. imap_processing/swe/l1b/swe_l1b.py +898 -23
  86. imap_processing/swe/l2/swe_l2.py +21 -77
  87. imap_processing/swe/utils/swe_constants.py +1 -0
  88. imap_processing/tests/ccsds/test_excel_to_xtce.py +1 -1
  89. imap_processing/tests/cdf/test_utils.py +14 -16
  90. imap_processing/tests/codice/conftest.py +44 -33
  91. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  92. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  93. imap_processing/tests/codice/test_codice_l1a.py +20 -11
  94. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  95. imap_processing/tests/conftest.py +78 -22
  96. imap_processing/tests/ena_maps/test_ena_maps.py +462 -33
  97. imap_processing/tests/ena_maps/test_spatial_utils.py +1 -1
  98. imap_processing/tests/glows/conftest.py +10 -14
  99. imap_processing/tests/glows/test_glows_decom.py +4 -4
  100. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  101. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  102. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  103. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  104. imap_processing/tests/glows/test_glows_l2.py +2 -8
  105. imap_processing/tests/hi/conftest.py +1 -1
  106. imap_processing/tests/hi/test_hi_l1b.py +10 -12
  107. imap_processing/tests/hi/test_hi_l1c.py +27 -24
  108. imap_processing/tests/hi/test_l1a.py +7 -9
  109. imap_processing/tests/hi/test_science_direct_event.py +2 -2
  110. imap_processing/tests/hit/helpers/l1_validation.py +44 -43
  111. imap_processing/tests/hit/test_decom_hit.py +1 -1
  112. imap_processing/tests/hit/test_hit_l1a.py +9 -9
  113. imap_processing/tests/hit/test_hit_l1b.py +172 -217
  114. imap_processing/tests/hit/test_hit_l2.py +380 -118
  115. imap_processing/tests/hit/test_hit_utils.py +122 -55
  116. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  117. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  118. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  119. imap_processing/tests/ialirt/unit/test_grouping.py +2 -2
  120. imap_processing/tests/ialirt/unit/test_parse_mag.py +71 -16
  121. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  122. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  123. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  124. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  125. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  126. imap_processing/tests/ialirt/unit/test_process_swe.py +115 -7
  127. imap_processing/tests/idex/conftest.py +72 -7
  128. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  129. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  130. imap_processing/tests/idex/test_idex_l0.py +33 -11
  131. imap_processing/tests/idex/test_idex_l1a.py +50 -23
  132. imap_processing/tests/idex/test_idex_l1b.py +104 -25
  133. imap_processing/tests/idex/test_idex_l2a.py +48 -32
  134. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  135. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  136. imap_processing/tests/lo/test_lo_l1b.py +371 -6
  137. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  138. imap_processing/tests/lo/test_lo_science.py +6 -7
  139. imap_processing/tests/lo/test_star_sensor.py +1 -1
  140. imap_processing/tests/mag/conftest.py +58 -9
  141. imap_processing/tests/mag/test_mag_decom.py +4 -3
  142. imap_processing/tests/mag/test_mag_l1a.py +13 -7
  143. imap_processing/tests/mag/test_mag_l1b.py +9 -9
  144. imap_processing/tests/mag/test_mag_l1c.py +151 -47
  145. imap_processing/tests/mag/test_mag_l2.py +130 -0
  146. imap_processing/tests/mag/test_mag_validation.py +144 -7
  147. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  148. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  149. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  150. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  151. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  152. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  153. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  154. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  155. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  156. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  157. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  158. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  159. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  160. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  161. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  162. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  163. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  164. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  165. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  166. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  167. imap_processing/tests/spacecraft/test_quaternions.py +1 -1
  168. imap_processing/tests/spice/test_data/fake_repoint_data.csv +4 -4
  169. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  170. imap_processing/tests/spice/test_geometry.py +3 -3
  171. imap_processing/tests/spice/test_kernels.py +1 -200
  172. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  173. imap_processing/tests/spice/test_repoint.py +20 -10
  174. imap_processing/tests/spice/test_spin.py +50 -9
  175. imap_processing/tests/spice/test_time.py +14 -0
  176. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  177. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  178. imap_processing/tests/swapi/test_swapi_l1.py +7 -9
  179. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  180. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  181. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  182. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  183. imap_processing/tests/swe/test_swe_l1a.py +6 -6
  184. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  185. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  186. imap_processing/tests/swe/test_swe_l2.py +82 -102
  187. imap_processing/tests/test_cli.py +171 -88
  188. imap_processing/tests/test_utils.py +2 -1
  189. imap_processing/tests/ultra/data/mock_data.py +49 -21
  190. imap_processing/tests/ultra/unit/conftest.py +53 -70
  191. imap_processing/tests/ultra/unit/test_badtimes.py +2 -4
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -6
  193. imap_processing/tests/ultra/unit/test_de.py +3 -10
  194. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  195. imap_processing/tests/ultra/unit/test_decom_apid_881.py +15 -16
  196. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  197. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  198. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  199. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +3 -4
  200. imap_processing/tests/ultra/unit/test_ultra_l1a.py +84 -307
  201. imap_processing/tests/ultra/unit/test_ultra_l1b.py +30 -12
  202. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  203. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +4 -1
  204. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +163 -29
  205. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  206. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +32 -43
  207. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  208. imap_processing/ultra/constants.py +1 -1
  209. imap_processing/ultra/l0/decom_tools.py +21 -34
  210. imap_processing/ultra/l0/decom_ultra.py +168 -204
  211. imap_processing/ultra/l0/ultra_utils.py +152 -136
  212. imap_processing/ultra/l1a/ultra_l1a.py +55 -243
  213. imap_processing/ultra/l1b/badtimes.py +1 -4
  214. imap_processing/ultra/l1b/cullingmask.py +2 -6
  215. imap_processing/ultra/l1b/de.py +62 -47
  216. imap_processing/ultra/l1b/extendedspin.py +8 -4
  217. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  218. imap_processing/ultra/l1b/ultra_l1b.py +3 -8
  219. imap_processing/ultra/l1b/ultra_l1b_culling.py +4 -4
  220. imap_processing/ultra/l1b/ultra_l1b_extended.py +236 -78
  221. imap_processing/ultra/l1c/histogram.py +2 -6
  222. imap_processing/ultra/l1c/spacecraft_pset.py +2 -4
  223. imap_processing/ultra/l1c/ultra_l1c.py +1 -5
  224. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +107 -60
  225. imap_processing/ultra/l2/ultra_l2.py +299 -0
  226. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  227. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  228. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  229. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  230. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  231. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  232. imap_processing/ultra/packet_definitions/README.md +38 -0
  233. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  234. imap_processing/ultra/utils/ultra_l1_utils.py +13 -12
  235. imap_processing/utils.py +1 -1
  236. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +3 -2
  237. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/RECORD +264 -225
  238. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  239. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +0 -6
  240. imap_processing/mag/l1b/__init__.py +0 -0
  241. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  242. imap_processing/swe/l1b/swe_l1b_science.py +0 -699
  243. imap_processing/tests/swe/test_swe_l1b_science.py +0 -103
  244. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  245. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  246. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  247. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  248. /imap_processing/tests/ialirt/{test_data → data}/l0/461971383-404.bin +0 -0
  249. /imap_processing/tests/ialirt/{test_data → data}/l0/461971384-405.bin +0 -0
  250. /imap_processing/tests/ialirt/{test_data → data}/l0/461971385-406.bin +0 -0
  251. /imap_processing/tests/ialirt/{test_data → data}/l0/461971386-407.bin +0 -0
  252. /imap_processing/tests/ialirt/{test_data → data}/l0/461971387-408.bin +0 -0
  253. /imap_processing/tests/ialirt/{test_data → data}/l0/461971388-409.bin +0 -0
  254. /imap_processing/tests/ialirt/{test_data → data}/l0/461971389-410.bin +0 -0
  255. /imap_processing/tests/ialirt/{test_data → data}/l0/461971390-411.bin +0 -0
  256. /imap_processing/tests/ialirt/{test_data → data}/l0/461971391-412.bin +0 -0
  257. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  258. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  259. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  260. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  261. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  262. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  263. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  264. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  265. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  266. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  267. /imap_processing/tests/ialirt/{test_data → data}/l0/sample_decoded_i-alirt_data.csv +0 -0
  268. /imap_processing/tests/mag/validation/{imap_calibration_mag_20240229_v01.cdf → calibration/imap_mag_l1b-calibration_20240229_v001.cdf} +0 -0
  269. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  270. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  271. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  272. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -6,15 +6,14 @@ import xarray as xr
6
6
  from imap_processing import imap_module_directory
7
7
  from imap_processing.hit.l1a import hit_l1a
8
8
  from imap_processing.hit.l1b.hit_l1b import (
9
- PARTICLE_ENERGY_RANGE_MAPPING,
10
- SummedCounts,
11
- add_energy_variables,
12
- add_rates_to_dataset,
13
- calculate_summed_counts,
14
- create_particle_data_arrays,
9
+ SUMMED_PARTICLE_ENERGY_RANGE_MAPPING,
10
+ calculate_rates,
15
11
  hit_l1b,
12
+ process_sectored_rates_data,
16
13
  process_standard_rates_data,
17
14
  process_summed_rates_data,
15
+ subset_data_for_sectored_counts,
16
+ sum_livetime_10min,
18
17
  )
19
18
  from imap_processing.tests.hit.helpers.l1_validation import (
20
19
  prepare_standard_rates_validation_data,
@@ -41,219 +40,137 @@ def sci_packet_filepath():
41
40
  return imap_module_directory / "tests/hit/test_data/sci_sample.ccsds"
42
41
 
43
42
 
44
- @pytest.fixture()
43
+ @pytest.fixture
45
44
  def dependencies(packet_filepath, sci_packet_filepath):
46
45
  """Get dependencies for L1B processing"""
47
46
  # Create dictionary of dependencies and add CCSDS packet file
48
47
  data_dict = {"imap_hit_l0_raw": packet_filepath}
49
48
  # Add L1A datasets
50
- l1a_datasets = hit_l1a.hit_l1a(packet_filepath, "001")
49
+ l1a_datasets = hit_l1a.hit_l1a(packet_filepath)
51
50
  # TODO: Remove this when HIT provides a packet file with all apids.
52
- l1a_datasets.extend(hit_l1a.hit_l1a(sci_packet_filepath, "001"))
51
+ l1a_datasets.extend(hit_l1a.hit_l1a(sci_packet_filepath))
53
52
  for dataset in l1a_datasets:
54
53
  data_dict[dataset.attrs["Logical_source"]] = dataset
55
54
  return data_dict
56
55
 
57
56
 
58
- @pytest.fixture()
57
+ @pytest.fixture
59
58
  def l1b_hk_dataset(dependencies):
60
59
  """Get the housekeeping dataset"""
61
- datasets = hit_l1b(dependencies, "001")
60
+ datasets = hit_l1b(dependencies)
62
61
  for dataset in datasets:
63
62
  if dataset.attrs["Logical_source"] == "imap_hit_l1b_hk":
64
63
  return dataset
65
64
 
66
65
 
67
- @pytest.fixture()
66
+ @pytest.fixture
68
67
  def l1b_standard_rates_dataset(dependencies):
69
68
  """Get the standard rates dataset"""
70
- # TODO: use this fixture in future unit test to validate the standard rates dataset
71
- datasets = hit_l1b(dependencies, "001")
69
+ datasets = hit_l1b(dependencies)
72
70
  for dataset in datasets:
73
71
  if dataset.attrs["Logical_source"] == "imap_hit_l1b_standard-rates":
74
72
  return dataset
75
73
 
76
74
 
77
- @pytest.fixture()
75
+ @pytest.fixture
78
76
  def l1a_counts_dataset(sci_packet_filepath):
79
77
  """Get L1A counts dataset to test l1b processing functions"""
80
- l1a_datasets = hit_l1a.hit_l1a(sci_packet_filepath, "001")
78
+ l1a_datasets = hit_l1a.hit_l1a(sci_packet_filepath)
81
79
  for dataset in l1a_datasets:
82
80
  if dataset.attrs["Logical_source"] == "imap_hit_l1a_counts":
83
81
  return dataset
84
82
 
85
83
 
86
- @pytest.fixture()
87
- def livetime(l1a_counts_dataset):
84
+ @pytest.fixture
85
+ def livetime(l1a_counts_dataset: xr.Dataset) -> xr.DataArray:
88
86
  """Calculate livetime for L1A counts dataset"""
89
- return l1a_counts_dataset["livetime_counter"] / 270
87
+ return xr.DataArray(l1a_counts_dataset["livetime_counter"] / 270)
90
88
 
91
89
 
92
- def test_calculate_summed_counts():
93
- # Create a mock raw_counts_dataset
90
+ def test_calculate_rates():
91
+ """Test the calculate_rates function"""
92
+
93
+ # Create a sample dataset
94
94
  data = {
95
- "l2fgrates": (
96
- ("epoch", "index"),
97
- np.array([[1, 2, 3, 4, 5]] * 5, dtype=np.int64),
98
- ),
99
- "l3fgrates": (
100
- ("epoch", "index"),
101
- np.array([[6, 7, 8, 9, 10]] * 5, dtype=np.int64),
102
- ),
103
- "penfgrates": (
104
- ("epoch", "index"),
105
- np.array([[11, 12, 13, 14, 15]] * 5, dtype=np.int64),
106
- ),
107
- "l2fgrates_delta_minus": (
108
- ("epoch", "index"),
109
- np.zeros((5, 5), dtype=np.float32),
110
- ),
111
- "l3fgrates_delta_minus": (
112
- ("epoch", "index"),
113
- np.full((5, 5), 0.01, dtype=np.float32),
114
- ),
115
- "penfgrates_delta_minus": (
116
- ("epoch", "index"),
117
- np.full((5, 5), 0.001, dtype=np.float32),
95
+ "counts": (("epoch",), np.array([100, 200, 300], dtype=np.float32)),
96
+ "counts_stat_uncert_minus": (
97
+ ("epoch",),
98
+ np.array([10, 20, 30], dtype=np.float32),
118
99
  ),
119
- "l2fgrates_delta_plus": (
120
- ("epoch", "index"),
121
- np.full((5, 5), 0.02, dtype=np.float32),
100
+ "counts_stat_uncert_plus": (
101
+ ("epoch",),
102
+ np.array([15, 25, 35], dtype=np.float32),
122
103
  ),
123
- "l3fgrates_delta_plus": (
124
- ("epoch", "index"),
125
- np.full((5, 5), 0.002, dtype=np.float32),
126
- ),
127
- "penfgrates_delta_plus": (
128
- ("epoch", "index"),
129
- np.full((5, 5), 0.003, dtype=np.float32),
130
- ),
131
- }
132
- coords = {"epoch": np.arange(5), "index": np.arange(5)}
133
- raw_counts_dataset = xr.Dataset(data, coords=coords)
134
-
135
- # Define count_indices
136
- count_indices = {
137
- "R2": [0, 1],
138
- "R3": [2, 3],
139
- "R4": [4],
140
104
  }
105
+ coords = {"epoch": np.array([0, 1, 2], dtype=np.float32)}
106
+ dataset = xr.Dataset(data, coords=coords)
141
107
 
142
- # Call the function
143
- summed_counts, summed_counts_delta_minus, summed_counts_delta_plus = (
144
- calculate_summed_counts(raw_counts_dataset, count_indices)
145
- )
108
+ # Create a sample livetime array
109
+ livetime = xr.DataArray(np.array([10, 20, 30], dtype=np.float32), dims="epoch")
146
110
 
147
- # Expected values based on `count_indices`
148
- expected_summed_counts = np.array([35, 35, 35, 35, 35])
149
- expected_summed_counts_delta_minus = np.array([0.021, 0.021, 0.021, 0.021, 0.021])
150
- expected_summed_counts_delta_plus = np.array([0.047, 0.047, 0.047, 0.047, 0.047])
111
+ # Call the function
112
+ result = calculate_rates(dataset, "counts", livetime)
151
113
 
152
- # Assertions
153
- assert summed_counts.shape == (5,)
154
- assert summed_counts_delta_minus.shape == (5,)
155
- assert summed_counts_delta_plus.shape == (5,)
114
+ # Check the results
115
+ expected_counts = np.array([10, 10, 10], dtype=np.float32)
116
+ expected_counts_uncert_minus = np.array([1, 1, 1], dtype=np.float32)
117
+ expected_counts_uncert_plus = np.array([1.5, 1.25, 1.1666666], dtype=np.float32)
156
118
 
157
- np.testing.assert_array_almost_equal(summed_counts.values, expected_summed_counts)
158
- np.testing.assert_array_almost_equal(
159
- summed_counts_delta_minus.values, expected_summed_counts_delta_minus
119
+ np.testing.assert_allclose(result["counts"].values, expected_counts)
120
+ np.testing.assert_allclose(
121
+ result["counts_stat_uncert_minus"].values, expected_counts_uncert_minus
160
122
  )
161
- np.testing.assert_array_almost_equal(
162
- summed_counts_delta_plus.values, expected_summed_counts_delta_plus
123
+ np.testing.assert_allclose(
124
+ result["counts_stat_uncert_plus"].values, expected_counts_uncert_plus
163
125
  )
164
126
 
165
- # Check dtype consistency
166
- assert summed_counts.dtype == np.int64, f"Unexpected dtype: {summed_counts.dtype}"
167
- assert (
168
- summed_counts_delta_minus.dtype == np.float32
169
- ), f"Unexpected dtype: {summed_counts_delta_minus.dtype}"
170
- assert (
171
- summed_counts_delta_plus.dtype == np.float32
172
- ), f"Unexpected dtype: {summed_counts_delta_plus.dtype}"
173
-
174
127
 
175
- def test_add_rates_to_dataset():
176
- # Create a sample dataset
177
- dataset = xr.Dataset(
178
- {
179
- "epoch": ("epoch", np.arange(10)),
180
- "livetime": ("epoch", np.random.rand(10) + 1), # Avoid division by zero
181
- }
128
+ def test_sum_livetime_10min():
129
+ """Test the sum_livetime_10min function."""
130
+ # Create a sample livetime DataArray
131
+ livetime_values = np.arange(1, 31) # 30 epochs with values 1 to 30
132
+ livetime = xr.DataArray(
133
+ livetime_values, dims=["epoch"], coords={"epoch": np.arange(30)}
182
134
  )
183
135
 
184
- # Add empty data arrays for a sample particle
185
- particle = "test_particle"
186
- dataset[particle] = xr.DataArray(
187
- data=np.zeros((10, 5), dtype=np.float32),
188
- dims=["epoch", f"{particle}_energy_index"],
136
+ # Expected result: sum of every 10 values repeated 10 times
137
+ expected_values = np.repeat(
138
+ [sum(livetime_values[i : i + 10]) for i in range(0, 30, 10)], 10
189
139
  )
190
- dataset[f"{particle}_delta_minus"] = xr.DataArray(
191
- data=np.zeros((10, 5), dtype=np.float32),
192
- dims=["epoch", f"{particle}_energy_index"],
193
- )
194
- dataset[f"{particle}_delta_plus"] = xr.DataArray(
195
- data=np.zeros((10, 5), dtype=np.float32),
196
- dims=["epoch", f"{particle}_energy_index"],
197
- )
198
-
199
- # Set the random seed for reproducibility
200
- np.random.seed(42)
201
-
202
- # Define the summed counts with random values in a namedtuple
203
- summed_counts = SummedCounts(
204
- xr.DataArray(np.random.rand(10), dims=["epoch"]),
205
- xr.DataArray(np.random.rand(10), dims=["epoch"]),
206
- xr.DataArray(np.random.rand(10), dims=["epoch"]),
140
+ expected_livetime = xr.DataArray(
141
+ expected_values, dims=["epoch"], coords={"epoch": np.arange(30)}
207
142
  )
208
143
 
209
144
  # Call the function
210
- updated_dataset = add_rates_to_dataset(
211
- dataset, particle, 0, summed_counts, dataset["livetime"]
212
- )
145
+ result = sum_livetime_10min(livetime)
213
146
 
214
- # Check the results
215
- np.testing.assert_array_almost_equal(
216
- updated_dataset[particle][:, 0].values,
217
- summed_counts.summed_counts / dataset["livetime"].values,
218
- )
219
- np.testing.assert_array_almost_equal(
220
- updated_dataset[f"{particle}_delta_minus"][:, 0].values,
221
- summed_counts.summed_counts_delta_minus / dataset["livetime"].values,
222
- )
223
- np.testing.assert_array_almost_equal(
224
- updated_dataset[f"{particle}_delta_plus"][:, 0].values,
225
- summed_counts.summed_counts_delta_plus / dataset["livetime"].values,
226
- )
147
+ # Assert the result is as expected
148
+ xr.testing.assert_equal(result, expected_livetime)
227
149
 
228
150
 
229
- def test_add_energy_variables():
230
- dataset = xr.Dataset()
231
- particle = "test_particle"
232
- energy_min = np.array([1.8, 4.0, 6.0], dtype=np.float32)
233
- energy_max = np.array([2.2, 6.0, 10.0], dtype=np.float32)
234
- result = add_energy_variables(dataset, particle, energy_min, energy_max)
235
- assert f"{particle}_energy_min" in result.data_vars
236
- assert f"{particle}_energy_max" in result.data_vars
237
- assert np.all(result[f"{particle}_energy_min"].values == energy_min)
238
- assert np.all(result[f"{particle}_energy_max"].values == energy_max)
239
-
240
-
241
- def test_create_particle_data_arrays():
242
- dataset = xr.Dataset()
243
- particle = "test_particle"
244
- result = create_particle_data_arrays(
245
- dataset, particle, num_energy_ranges=3, epoch_size=10
151
+ def test_subset_data_for_sectored_counts():
152
+ """Test the subset_data_for_sectored_counts function."""
153
+ # Create a sample L1A counts dataset
154
+ l1a_counts_dataset = xr.Dataset(
155
+ {
156
+ "hdr_minute_cnt": ("epoch", np.arange(105, 135)),
157
+ "h_sectored_counts": ("epoch", np.arange(0, 30)),
158
+ "he4_sectored_counts": ("epoch", np.arange(0, 30)),
159
+ },
246
160
  )
247
161
 
248
- assert f"{particle}" in result.data_vars
249
- assert f"{particle}_delta_minus" in result.data_vars
250
- assert f"{particle}_delta_plus" in result.data_vars
251
- assert f"{particle}_energy_index" in result.coords
162
+ # Create a sample livetime data array
163
+ livetime = xr.DataArray(np.arange(1.0, 31.0, dtype=np.float32), dims=["epoch"])
252
164
 
253
- for var in result.data_vars:
254
- assert result[var].shape == (10, 3)
165
+ # Call the function
166
+ subset_dataset, subset_livetime = subset_data_for_sectored_counts(
167
+ l1a_counts_dataset, livetime
168
+ )
255
169
 
256
- assert result[f"{particle}_energy_index"].shape == (3,)
170
+ # Check the results
171
+ assert subset_dataset.dims["epoch"] == 10
172
+ assert len(subset_livetime["epoch"]) == 10
173
+ assert np.all(subset_dataset["hdr_minute_cnt"].values % 10 == np.arange(10))
257
174
 
258
175
 
259
176
  def test_process_summed_rates_data(l1a_counts_dataset, livetime):
@@ -266,23 +183,23 @@ def test_process_summed_rates_data(l1a_counts_dataset, livetime):
266
183
 
267
184
  valid_coords = {
268
185
  "epoch",
269
- "h_energy_index",
270
- "he3_energy_index",
271
- "he4_energy_index",
272
- "he_energy_index",
273
- "c_energy_index",
274
- "o_energy_index",
275
- "fe_energy_index",
276
- "n_energy_index",
277
- "si_energy_index",
278
- "mg_energy_index",
279
- "s_energy_index",
280
- "ar_energy_index",
281
- "ca_energy_index",
282
- "na_energy_index",
283
- "al_energy_index",
284
- "ne_energy_index",
285
- "ni_energy_index",
186
+ "h_energy_mean",
187
+ "he3_energy_mean",
188
+ "he4_energy_mean",
189
+ "he_energy_mean",
190
+ "c_energy_mean",
191
+ "o_energy_mean",
192
+ "fe_energy_mean",
193
+ "n_energy_mean",
194
+ "si_energy_mean",
195
+ "mg_energy_mean",
196
+ "s_energy_mean",
197
+ "ar_energy_mean",
198
+ "ca_energy_mean",
199
+ "na_energy_mean",
200
+ "al_energy_mean",
201
+ "ne_energy_mean",
202
+ "ni_energy_mean",
286
203
  }
287
204
 
288
205
  # Check that the dataset has the correct coords and variables
@@ -290,12 +207,12 @@ def test_process_summed_rates_data(l1a_counts_dataset, livetime):
290
207
 
291
208
  assert "dynamic_threshold_state" in l1b_summed_rates_dataset.data_vars
292
209
 
293
- for particle in PARTICLE_ENERGY_RANGE_MAPPING.keys():
210
+ for particle in SUMMED_PARTICLE_ENERGY_RANGE_MAPPING.keys():
294
211
  assert f"{particle}" in l1b_summed_rates_dataset.data_vars
295
- assert f"{particle}_delta_minus" in l1b_summed_rates_dataset.data_vars
296
- assert f"{particle}_delta_plus" in l1b_summed_rates_dataset.data_vars
297
- assert f"{particle}_energy_min" in l1b_summed_rates_dataset.data_vars
298
- assert f"{particle}_energy_max" in l1b_summed_rates_dataset.data_vars
212
+ assert f"{particle}_stat_uncert_minus" in l1b_summed_rates_dataset.data_vars
213
+ assert f"{particle}_stat_uncert_plus" in l1b_summed_rates_dataset.data_vars
214
+ assert f"{particle}_energy_delta_minus" in l1b_summed_rates_dataset.data_vars
215
+ assert f"{particle}_energy_delta_plus" in l1b_summed_rates_dataset.data_vars
299
216
 
300
217
 
301
218
  def test_process_standard_rates_data(l1a_counts_dataset, livetime):
@@ -321,30 +238,30 @@ def test_process_standard_rates_data(l1a_counts_dataset, livetime):
321
238
  "ialirtrates",
322
239
  "l4fgrates",
323
240
  "l4bgrates",
324
- "sngrates_delta_plus",
325
- "coinrates_delta_plus",
326
- "pbufrates_delta_plus",
327
- "l2fgrates_delta_plus",
328
- "l2bgrates_delta_plus",
329
- "l3fgrates_delta_plus",
330
- "l3bgrates_delta_plus",
331
- "penfgrates_delta_plus",
332
- "penbgrates_delta_plus",
333
- "ialirtrates_delta_plus",
334
- "l4fgrates_delta_plus",
335
- "l4bgrates_delta_plus",
336
- "sngrates_delta_minus",
337
- "coinrates_delta_minus",
338
- "pbufrates_delta_minus",
339
- "l2fgrates_delta_minus",
340
- "l2bgrates_delta_minus",
341
- "l3fgrates_delta_minus",
342
- "l3bgrates_delta_minus",
343
- "penfgrates_delta_minus",
344
- "penbgrates_delta_minus",
345
- "ialirtrates_delta_minus",
346
- "l4fgrates_delta_minus",
347
- "l4bgrates_delta_minus",
241
+ "sngrates_stat_uncert_plus",
242
+ "coinrates_stat_uncert_plus",
243
+ "pbufrates_stat_uncert_plus",
244
+ "l2fgrates_stat_uncert_plus",
245
+ "l2bgrates_stat_uncert_plus",
246
+ "l3fgrates_stat_uncert_plus",
247
+ "l3bgrates_stat_uncert_plus",
248
+ "penfgrates_stat_uncert_plus",
249
+ "penbgrates_stat_uncert_plus",
250
+ "ialirtrates_stat_uncert_plus",
251
+ "l4fgrates_stat_uncert_plus",
252
+ "l4bgrates_stat_uncert_plus",
253
+ "sngrates_stat_uncert_minus",
254
+ "coinrates_stat_uncert_minus",
255
+ "pbufrates_stat_uncert_minus",
256
+ "l2fgrates_stat_uncert_minus",
257
+ "l2bgrates_stat_uncert_minus",
258
+ "l3fgrates_stat_uncert_minus",
259
+ "l3bgrates_stat_uncert_minus",
260
+ "penfgrates_stat_uncert_minus",
261
+ "penbgrates_stat_uncert_minus",
262
+ "ialirtrates_stat_uncert_minus",
263
+ "l4fgrates_stat_uncert_minus",
264
+ "l4bgrates_stat_uncert_minus",
348
265
  "dynamic_threshold_state",
349
266
  }
350
267
 
@@ -366,12 +283,49 @@ def test_process_standard_rates_data(l1a_counts_dataset, livetime):
366
283
  ]
367
284
 
368
285
  # Check that the dataset has the correct variables
369
- assert valid_data_vars == set(
370
- l1b_standard_rates_dataset.data_vars.keys()
371
- ), "Data variables mismatch"
372
- assert valid_coords == list(
373
- l1b_standard_rates_dataset.coords
374
- ), "Coordinates mismatch"
286
+ assert valid_data_vars == set(l1b_standard_rates_dataset.data_vars.keys()), (
287
+ "Data variables mismatch"
288
+ )
289
+ assert valid_coords == list(l1b_standard_rates_dataset.coords), (
290
+ "Coordinates mismatch"
291
+ )
292
+
293
+
294
+ def test_process_sectored_rates_data(l1a_counts_dataset, livetime):
295
+ """Test the variables in the sectored rates dataset"""
296
+
297
+ l1b_sectored_rates_dataset = process_sectored_rates_data(
298
+ l1a_counts_dataset, livetime
299
+ )
300
+
301
+ # Check that a xarray dataset is returned
302
+ assert isinstance(l1b_sectored_rates_dataset, xr.Dataset)
303
+
304
+ valid_coords = {
305
+ "epoch",
306
+ "declination",
307
+ "azimuth",
308
+ "h_energy_mean",
309
+ "he4_energy_mean",
310
+ "cno_energy_mean",
311
+ "nemgsi_energy_mean",
312
+ "fe_energy_mean",
313
+ }
314
+
315
+ # Check that the dataset has the correct coords and variables
316
+ assert valid_coords == set(l1b_sectored_rates_dataset.coords), (
317
+ "Coordinates mismatch"
318
+ )
319
+
320
+ assert "dynamic_threshold_state" in l1b_sectored_rates_dataset.data_vars
321
+
322
+ particles = ["h", "he4", "cno", "nemgsi", "fe"]
323
+ for particle in particles:
324
+ assert f"{particle}" in l1b_sectored_rates_dataset.data_vars
325
+ assert f"{particle}_stat_uncert_minus" in l1b_sectored_rates_dataset.data_vars
326
+ assert f"{particle}_stat_uncert_plus" in l1b_sectored_rates_dataset.data_vars
327
+ assert f"{particle}_energy_delta_minus" in l1b_sectored_rates_dataset.data_vars
328
+ assert f"{particle}_energy_delta_plus" in l1b_sectored_rates_dataset.data_vars
375
329
 
376
330
 
377
331
  def test_hit_l1b_hk_dataset_variables(l1b_hk_dataset):
@@ -561,9 +515,9 @@ def test_validate_l1b_standard_rates_data(l1b_standard_rates_dataset):
561
515
  validation_data = prepare_standard_rates_validation_data(validation_data)
562
516
 
563
517
  for field in validation_data.columns:
564
- assert (
565
- field in l1b_standard_rates_dataset.data_vars.keys()
566
- ), f"Field {field} not found in actual data variables"
518
+ assert field in l1b_standard_rates_dataset.data_vars.keys(), (
519
+ f"Field {field} not found in actual data variables"
520
+ )
567
521
  for frame in range(validation_data.shape[0]):
568
522
  np.testing.assert_allclose(
569
523
  l1b_standard_rates_dataset[field][frame].data,
@@ -592,7 +546,7 @@ def test_hit_l1b_missing_apid(sci_packet_filepath):
592
546
  # Create a dependency dictionary with a science CCSDS packet file
593
547
  # excluding the housekeeping apid
594
548
  dependency = {"imap_hit_l0_raw": sci_packet_filepath}
595
- datasets = hit_l1b(dependency, "001")
549
+ datasets = hit_l1b(dependency)
596
550
  assert len(datasets) == 0
597
551
 
598
552
 
@@ -607,11 +561,12 @@ def test_hit_l1b(dependencies):
607
561
  Dictionary of L1A datasets and CCSDS packet file path
608
562
  """
609
563
  # TODO: update assertions after science data processing is completed
610
- datasets = hit_l1b(dependencies, "001")
564
+ datasets = hit_l1b(dependencies)
611
565
 
612
- assert len(datasets) == 3
566
+ assert len(datasets) == 4
613
567
  for dataset in datasets:
614
568
  assert isinstance(dataset, xr.Dataset)
615
569
  assert datasets[0].attrs["Logical_source"] == "imap_hit_l1b_hk"
616
570
  assert datasets[1].attrs["Logical_source"] == "imap_hit_l1b_standard-rates"
617
571
  assert datasets[2].attrs["Logical_source"] == "imap_hit_l1b_summed-rates"
572
+ assert datasets[3].attrs["Logical_source"] == "imap_hit_l1b_sectored-rates"