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
@@ -2,6 +2,9 @@
2
2
 
3
3
  import logging
4
4
 
5
+ import numpy as np
6
+ import numpy.typing as npt
7
+ import pandas as pd
5
8
  import xarray as xr
6
9
 
7
10
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
@@ -12,7 +15,96 @@ logger = logging.getLogger(__name__)
12
15
  TIME_PER_BIN = 0.167 # seconds
13
16
 
14
17
 
15
- def swapi_l2(l1_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
18
+ def solve_full_sweep_energy(
19
+ esa_lvl5_data: np.ndarray, esa_table_df: pd.DataFrame, lut_notes_df: pd.DataFrame
20
+ ) -> npt.NDArray:
21
+ """
22
+ Calculate the energy of each full sweep data.
23
+
24
+ Parameters
25
+ ----------
26
+ esa_lvl5_data : numpy.ndarray
27
+ The L1 data input.
28
+ esa_table_df : pandas.DataFrame
29
+ The ESA unit conversion table that contains first 63 energies.
30
+ lut_notes_df : pandas.DataFrame
31
+ The LUT notes table that contains the last 9 fine energies.
32
+
33
+ Returns
34
+ -------
35
+ energy : numpy.ndarray
36
+ The energy of each full sweep data.
37
+ """
38
+ # Read 0 - 62 energy steps' fixed energy value
39
+ fixed_energy_values = esa_table_df["Energy"].values[:63]
40
+
41
+ # Find last 9 fine energy values of all sweeps data
42
+ # -------------------------------------------------
43
+ # First, verify that all values in the LUT-notes table's 'ESA DAC (Hex)' column
44
+ # exactly matches a value in the esa_lvl5_data.
45
+ has_exact_match = np.isin(esa_lvl5_data, lut_notes_df["ESA DAC (Hex)"].values)
46
+ if not np.all(has_exact_match):
47
+ raise ValueError(
48
+ "These ESA_LVL5 values not found in lut-notes table: "
49
+ f"{esa_lvl5_data[np.where(~has_exact_match)[0]]} "
50
+ )
51
+
52
+ # Find index of 71st energy step for all sweeps data in lut-notes table.
53
+ # Tried using np.where(np.isin(...)) or df.index[np.isin(...)] to find the index
54
+ # of each value in esa_lvl5_data within the LUT table. However, these methods
55
+ # return only the unique matching indices — not one index per input value.
56
+ # For example, given the input:
57
+ # ['12F1', '12F1', '12F1', '12F1']
58
+ # np.where(np.isin(...)) would return:
59
+ # [336]
60
+ # because it finds that '12F1' exists in the LUT and only returns its position once.
61
+ # What we actually need is:
62
+ # [336, 336, 336, 336]
63
+ # — one index for *each* occurrence in the input, preserving its shape and order.
64
+ # Therefore, instead of relying on np.isin or similar, we explicitly use
65
+ # np.where in a loop to find the index of each value in esa_lvl5_data individually,
66
+ # ensuring the output array has the same shape as the input.
67
+
68
+ last_energy_step_indices = np.array(
69
+ [
70
+ np.where(lut_notes_df["ESA DAC (Hex)"].values == val)[0][0]
71
+ for val in esa_lvl5_data
72
+ ]
73
+ )
74
+ # Use back tracking steps to find all 9 fine energy value indices
75
+ # Eg. [0, -4, -8, ..., -28, -32]
76
+ steps = np.arange(9) * -4
77
+
78
+ # Find indices of last 9 fine energy values of all sweeps data
79
+ fine_energy_indices = last_energy_step_indices[:, None] + steps
80
+
81
+ # NOTE: Per SWAPI instruction, set every index that result in negative
82
+ # indices during back tracking to zero index. SWAPI calls this
83
+ # "flooring" the index. For example, if the 71st energy step index results
84
+ # in less than 32, then it would result in some negative indices. Eg.
85
+ # 71st index = 31
86
+ # nine fine energy indices = [31, 27, 23, 19, 15, 11, 7, 3, -1]
87
+ # flooring = [31, 27, 23, 19, 15, 11, 7, 3, 0]
88
+ fine_energy_indices[fine_energy_indices < 0] = 0
89
+
90
+ energy_values = lut_notes_df["Energy"].values[fine_energy_indices]
91
+
92
+ # Expand to match the number of rows in energy_values
93
+ first_63_values = np.tile(
94
+ fixed_energy_values, (energy_values.shape[0], 1)
95
+ ) # (epoch, 63)
96
+
97
+ # Append the first_63_values in front of energy_values
98
+ sweeps_energy_value = np.hstack((first_63_values, energy_values))
99
+
100
+ return sweeps_energy_value
101
+
102
+
103
+ def swapi_l2(
104
+ l1_dataset: xr.Dataset,
105
+ esa_table_df: pd.DataFrame,
106
+ lut_notes_df: pd.DataFrame,
107
+ ) -> xr.Dataset:
16
108
  """
17
109
  Produce science data to L2.
18
110
 
@@ -32,8 +124,10 @@ def swapi_l2(l1_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
32
124
  ----------
33
125
  l1_dataset : xarray.Dataset
34
126
  The L1 data input.
35
- data_version : str
36
- Version of the data product being created.
127
+ esa_table_df : pandas.DataFrame
128
+ The ESA unit conversion table that contains first 63 energies.
129
+ lut_notes_df : pandas.DataFrame
130
+ The LUT notes table that contains the last 9 fine energies.
37
131
 
38
132
  Returns
39
133
  -------
@@ -56,11 +150,29 @@ def swapi_l2(l1_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
56
150
  "lut_choice",
57
151
  "fpga_type",
58
152
  "fpga_rev",
153
+ "esa_lvl5",
59
154
  ]
60
155
  l2_dataset = l1_dataset[l1_data_keys]
61
156
 
157
+ # Find energy of each full sweep data
158
+ # -----------------------------------
159
+ # Convert unpacked ESA_LVL5 values to hex to match the LUT table
160
+ # value
161
+ esa_lvl5_hex = np.vectorize(lambda x: format(x, "X"))(l1_dataset["esa_lvl5"].values)
162
+ esa_energy = solve_full_sweep_energy(
163
+ esa_lvl5_hex,
164
+ esa_table_df=esa_table_df,
165
+ lut_notes_df=lut_notes_df,
166
+ )
167
+
168
+ l2_dataset["swp_esa_energy"] = xr.DataArray(
169
+ esa_energy,
170
+ name="esa_energy",
171
+ dims=["epoch", "energy"],
172
+ attrs=cdf_manager.get_variable_attributes("esa_energy"),
173
+ )
174
+
62
175
  # Update L2 specific attributes
63
- l2_dataset.attrs["Data_version"] = data_version
64
176
  l2_global_attrs = cdf_manager.get_global_attributes("imap_swapi_l2_sci")
65
177
  l2_dataset.attrs["Data_type"] = l2_global_attrs["Data_type"]
66
178
  l2_dataset.attrs["Logical_source"] = l2_global_attrs["Logical_source"]
@@ -6,6 +6,10 @@ other SWAPI processing modules.
6
6
  """
7
7
 
8
8
  from enum import IntEnum
9
+ from pathlib import Path
10
+
11
+ import numpy as np
12
+ import pandas as pd
9
13
 
10
14
 
11
15
  class SWAPIAPID(IntEnum):
@@ -23,3 +27,31 @@ class SWAPIMODE(IntEnum):
23
27
  LVSCI = 1
24
28
  HVENG = 2
25
29
  HVSCI = 3
30
+
31
+
32
+ def read_swapi_lut_table(file_path: Path) -> pd.DataFrame:
33
+ """
34
+ Read the LUT table from a CSV file.
35
+
36
+ Parameters
37
+ ----------
38
+ file_path : pathlib.Path
39
+ The path to the LUT table CSV file.
40
+
41
+ Returns
42
+ -------
43
+ pandas.DataFrame
44
+ The LUT table as a DataFrame.
45
+ """
46
+ df = pd.read_csv(file_path)
47
+
48
+ # Clean and convert 'Energy' column from comma-separated strings to integers
49
+ df["Energy"] = (
50
+ df["Energy"]
51
+ .astype(str)
52
+ .str.replace(",", "", regex=False)
53
+ .replace("Solve", -1)
54
+ .astype(np.int64)
55
+ )
56
+
57
+ return df
@@ -15,7 +15,7 @@ from imap_processing.utils import packet_file_to_datasets
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
- def swe_l1a(packet_file: str, data_version: str) -> xr.Dataset:
18
+ def swe_l1a(packet_file: str) -> xr.Dataset:
19
19
  """
20
20
  Will process SWE l0 data into l1a data.
21
21
 
@@ -27,9 +27,6 @@ def swe_l1a(packet_file: str, data_version: str) -> xr.Dataset:
27
27
  ----------
28
28
  packet_file : str
29
29
  Path where the raw packet file is stored.
30
- data_version : str
31
- Data version to write to CDF files and the Data_version CDF attribute.
32
- Should be in the format Vxxx.
33
30
 
34
31
  Returns
35
32
  -------
@@ -48,17 +45,13 @@ def swe_l1a(packet_file: str, data_version: str) -> xr.Dataset:
48
45
  if SWEAPID.SWE_SCIENCE in datasets_by_apid:
49
46
  logger.info("Processing SWE science data.")
50
47
  processed_data.append(
51
- swe_science(
52
- l0_dataset=datasets_by_apid[SWEAPID.SWE_SCIENCE],
53
- data_version=data_version,
54
- )
48
+ swe_science(l0_dataset=datasets_by_apid[SWEAPID.SWE_SCIENCE])
55
49
  )
56
50
 
57
51
  # Process non-science data
58
52
  # Define minimal CDF attrs for the non science dataset
59
53
  imap_attrs = ImapCdfAttributes()
60
54
  imap_attrs.add_instrument_global_attrs("swe")
61
- imap_attrs.add_global_attribute("Data_version", data_version)
62
55
  imap_attrs.add_instrument_variable_attrs("swe", "l1a")
63
56
  non_science_attrs = imap_attrs.get_variable_attributes("non_science_attrs")
64
57
  epoch_attrs = imap_attrs.get_variable_attributes("epoch", check_schema=False)
@@ -64,7 +64,7 @@ def decompressed_counts(cem_count: int) -> int:
64
64
  )
65
65
 
66
66
 
67
- def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
67
+ def swe_science(l0_dataset: xr.Dataset) -> xr.Dataset:
68
68
  """
69
69
  SWE L1a science processing.
70
70
 
@@ -97,10 +97,6 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
97
97
  l0_dataset : xarray.Dataset
98
98
  Raw packet data from SWE stored as an xarray dataset.
99
99
 
100
- data_version : str
101
- Data version for the 'Data_version' CDF attribute. This is the version of the
102
- output file.
103
-
104
100
  Returns
105
101
  -------
106
102
  dataset : xarray.Dataset
@@ -135,20 +131,19 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
135
131
  cdf_attrs = ImapCdfAttributes()
136
132
  cdf_attrs.add_instrument_global_attrs("swe")
137
133
  cdf_attrs.add_instrument_variable_attrs("swe", "l1a")
138
- cdf_attrs.add_global_attribute("Data_version", data_version)
139
134
 
140
135
  epoch_time = xr.DataArray(
141
136
  l0_dataset["epoch"],
142
137
  name="epoch",
143
138
  dims=["epoch"],
144
- attrs=cdf_attrs.get_variable_attributes("epoch"),
139
+ attrs=cdf_attrs.get_variable_attributes("epoch", check_schema=False),
145
140
  )
146
141
 
147
142
  spin_sector = xr.DataArray(
148
143
  np.arange(180),
149
144
  name="spin_sector",
150
145
  dims=["spin_sector"],
151
- attrs=cdf_attrs.get_variable_attributes("spin_sector"),
146
+ attrs=cdf_attrs.get_variable_attributes("spin_sector", check_schema=False),
152
147
  )
153
148
 
154
149
  # NOTE: LABL_PTR_1 should be CDF_CHAR.
@@ -156,14 +151,16 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
156
151
  spin_sector.values.astype(str),
157
152
  name="spin_sector_label",
158
153
  dims=["spin_sector"],
159
- attrs=cdf_attrs.get_variable_attributes("spin_sector_label"),
154
+ attrs=cdf_attrs.get_variable_attributes(
155
+ "spin_sector_label", check_schema=False
156
+ ),
160
157
  )
161
158
 
162
159
  cem_id = xr.DataArray(
163
160
  np.arange(swe_constants.N_CEMS),
164
161
  name="cem_id",
165
162
  dims=["cem_id"],
166
- attrs=cdf_attrs.get_variable_attributes("cem_id"),
163
+ attrs=cdf_attrs.get_variable_attributes("cem_id", check_schema=False),
167
164
  )
168
165
 
169
166
  # NOTE: LABL_PTR_2 should be CDF_CHAR.
@@ -171,7 +168,7 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
171
168
  cem_id.values.astype(str),
172
169
  name="cem_id_label",
173
170
  dims=["cem_id"],
174
- attrs=cdf_attrs.get_variable_attributes("cem_id_label"),
171
+ attrs=cdf_attrs.get_variable_attributes("cem_id_label", check_schema=False),
175
172
  )
176
173
 
177
174
  science_xarray = xr.DataArray(