imap-processing 0.11.0__py3-none-any.whl → 0.12.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 (288) hide show
  1. imap_processing/__init__.py +10 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/excel_to_xtce.py +65 -16
  4. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -28
  5. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +365 -42
  6. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  7. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  8. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  9. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +26 -13
  10. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  11. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  12. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  13. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +6 -9
  14. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +1 -1
  15. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  16. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  17. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +9 -21
  18. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  19. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  20. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  21. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  22. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  23. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  24. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  25. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  26. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +48 -52
  27. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  28. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +2 -14
  29. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +51 -2
  30. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +29 -14
  31. imap_processing/cdf/utils.py +13 -7
  32. imap_processing/cli.py +23 -8
  33. imap_processing/codice/codice_l1a.py +207 -85
  34. imap_processing/codice/constants.py +1322 -568
  35. imap_processing/codice/decompress.py +2 -6
  36. imap_processing/ena_maps/ena_maps.py +480 -116
  37. imap_processing/ena_maps/utils/coordinates.py +19 -0
  38. imap_processing/ena_maps/utils/map_utils.py +14 -17
  39. imap_processing/ena_maps/utils/spatial_utils.py +45 -47
  40. imap_processing/hi/l1a/hi_l1a.py +24 -18
  41. imap_processing/hi/l1a/histogram.py +0 -1
  42. imap_processing/hi/l1a/science_direct_event.py +6 -8
  43. imap_processing/hi/l1b/hi_l1b.py +31 -39
  44. imap_processing/hi/l1c/hi_l1c.py +405 -17
  45. imap_processing/hi/utils.py +58 -12
  46. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  47. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  48. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  49. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  50. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  51. imap_processing/hit/hit_utils.py +173 -1
  52. imap_processing/hit/l0/constants.py +20 -11
  53. imap_processing/hit/l0/decom_hit.py +18 -4
  54. imap_processing/hit/l1a/hit_l1a.py +45 -54
  55. imap_processing/hit/l1b/constants.py +317 -0
  56. imap_processing/hit/l1b/hit_l1b.py +367 -18
  57. imap_processing/hit/l2/constants.py +281 -0
  58. imap_processing/hit/l2/hit_l2.py +614 -0
  59. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  60. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  61. imap_processing/ialirt/l0/parse_mag.py +246 -0
  62. imap_processing/ialirt/l0/process_swe.py +252 -0
  63. imap_processing/ialirt/packet_definitions/ialirt.xml +7 -3
  64. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  65. imap_processing/ialirt/utils/grouping.py +114 -0
  66. imap_processing/ialirt/utils/time.py +29 -0
  67. imap_processing/idex/atomic_masses.csv +22 -0
  68. imap_processing/idex/decode.py +2 -2
  69. imap_processing/idex/idex_constants.py +25 -0
  70. imap_processing/idex/idex_l1a.py +6 -7
  71. imap_processing/idex/idex_l1b.py +4 -31
  72. imap_processing/idex/idex_l2a.py +789 -0
  73. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +39 -33
  74. imap_processing/lo/l0/lo_science.py +6 -0
  75. imap_processing/lo/l1a/lo_l1a.py +0 -1
  76. imap_processing/lo/l1b/lo_l1b.py +177 -25
  77. imap_processing/mag/constants.py +8 -0
  78. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +6 -0
  79. imap_processing/mag/l0/decom_mag.py +10 -3
  80. imap_processing/mag/l1a/mag_l1a.py +22 -11
  81. imap_processing/mag/l1a/mag_l1a_data.py +28 -3
  82. imap_processing/mag/l1b/mag_l1b.py +190 -48
  83. imap_processing/mag/l1c/interpolation_methods.py +211 -0
  84. imap_processing/mag/l1c/mag_l1c.py +447 -9
  85. imap_processing/quality_flags.py +1 -0
  86. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  87. imap_processing/spacecraft/quaternions.py +123 -0
  88. imap_processing/spice/geometry.py +16 -19
  89. imap_processing/spice/repoint.py +120 -0
  90. imap_processing/swapi/l1/swapi_l1.py +4 -0
  91. imap_processing/swapi/l2/swapi_l2.py +0 -1
  92. imap_processing/swe/l1a/swe_l1a.py +47 -8
  93. imap_processing/swe/l1a/swe_science.py +5 -2
  94. imap_processing/swe/l1b/swe_l1b_science.py +103 -56
  95. imap_processing/swe/l2/swe_l2.py +60 -65
  96. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  97. imap_processing/swe/utils/swe_constants.py +63 -0
  98. imap_processing/swe/utils/swe_utils.py +85 -28
  99. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  100. imap_processing/tests/ccsds/test_excel_to_xtce.py +23 -20
  101. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  102. imap_processing/tests/codice/conftest.py +1 -1
  103. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  104. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  105. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  106. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  107. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  108. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  109. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  110. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  111. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  112. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  113. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  114. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  115. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  116. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  117. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  118. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  119. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  120. imap_processing/tests/codice/test_codice_l1a.py +110 -46
  121. imap_processing/tests/codice/test_decompress.py +4 -4
  122. imap_processing/tests/conftest.py +166 -10
  123. imap_processing/tests/ena_maps/conftest.py +51 -0
  124. imap_processing/tests/ena_maps/test_ena_maps.py +638 -109
  125. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  126. imap_processing/tests/ena_maps/test_spatial_utils.py +16 -20
  127. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  128. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  129. imap_processing/tests/hi/test_hi_l1b.py +12 -15
  130. imap_processing/tests/hi/test_hi_l1c.py +234 -6
  131. imap_processing/tests/hi/test_l1a.py +30 -0
  132. imap_processing/tests/hi/test_science_direct_event.py +1 -1
  133. imap_processing/tests/hi/test_utils.py +24 -2
  134. imap_processing/tests/hit/helpers/l1_validation.py +39 -39
  135. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  136. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  137. imap_processing/tests/hit/test_decom_hit.py +4 -0
  138. imap_processing/tests/hit/test_hit_l1a.py +24 -28
  139. imap_processing/tests/hit/test_hit_l1b.py +304 -40
  140. imap_processing/tests/hit/test_hit_l2.py +454 -0
  141. imap_processing/tests/hit/test_hit_utils.py +112 -2
  142. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  143. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  144. imap_processing/tests/ialirt/test_data/l0/461971383-404.bin +0 -0
  145. imap_processing/tests/ialirt/test_data/l0/461971384-405.bin +0 -0
  146. imap_processing/tests/ialirt/test_data/l0/461971385-406.bin +0 -0
  147. imap_processing/tests/ialirt/test_data/l0/461971386-407.bin +0 -0
  148. imap_processing/tests/ialirt/test_data/l0/461971387-408.bin +0 -0
  149. imap_processing/tests/ialirt/test_data/l0/461971388-409.bin +0 -0
  150. imap_processing/tests/ialirt/test_data/l0/461971389-410.bin +0 -0
  151. imap_processing/tests/ialirt/test_data/l0/461971390-411.bin +0 -0
  152. imap_processing/tests/ialirt/test_data/l0/461971391-412.bin +0 -0
  153. imap_processing/tests/ialirt/test_data/l0/sample_decoded_i-alirt_data.csv +383 -0
  154. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  155. imap_processing/tests/ialirt/unit/test_parse_mag.py +168 -0
  156. imap_processing/tests/ialirt/unit/test_process_swe.py +208 -3
  157. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  158. imap_processing/tests/idex/conftest.py +62 -6
  159. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  160. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  161. imap_processing/tests/idex/test_idex_l1a.py +48 -4
  162. imap_processing/tests/idex/test_idex_l1b.py +3 -3
  163. imap_processing/tests/idex/test_idex_l2a.py +383 -0
  164. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  165. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  166. imap_processing/tests/lo/test_lo_l1b.py +148 -4
  167. imap_processing/tests/lo/test_lo_science.py +1 -0
  168. imap_processing/tests/mag/conftest.py +69 -0
  169. imap_processing/tests/mag/test_mag_decom.py +1 -1
  170. imap_processing/tests/mag/test_mag_l1a.py +38 -0
  171. imap_processing/tests/mag/test_mag_l1b.py +34 -53
  172. imap_processing/tests/mag/test_mag_l1c.py +251 -20
  173. imap_processing/tests/mag/test_mag_validation.py +109 -25
  174. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  175. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  176. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  177. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  178. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  179. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  180. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  181. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  182. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  183. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  184. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  185. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  186. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  187. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  188. imap_processing/tests/mag/validation/imap_calibration_mag_20240229_v01.cdf +0 -0
  189. imap_processing/tests/spacecraft/__init__.py +0 -0
  190. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  191. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  192. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  193. imap_processing/tests/spice/test_geometry.py +6 -9
  194. imap_processing/tests/spice/test_repoint.py +111 -0
  195. imap_processing/tests/swapi/test_swapi_l1.py +7 -3
  196. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  197. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  198. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  199. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  200. imap_processing/tests/swe/test_swe_l1a.py +18 -0
  201. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  202. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  203. imap_processing/tests/swe/test_swe_l1b_science.py +23 -4
  204. imap_processing/tests/swe/test_swe_l2.py +112 -30
  205. imap_processing/tests/test_cli.py +2 -2
  206. imap_processing/tests/test_utils.py +138 -16
  207. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  208. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  209. 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
  210. imap_processing/tests/ultra/data/mock_data.py +341 -0
  211. imap_processing/tests/ultra/unit/conftest.py +69 -26
  212. imap_processing/tests/ultra/unit/test_badtimes.py +2 -0
  213. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -0
  214. imap_processing/tests/ultra/unit/test_de.py +12 -4
  215. imap_processing/tests/ultra/unit/test_decom_apid_881.py +44 -0
  216. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +78 -0
  217. imap_processing/tests/ultra/unit/test_ultra_l1a.py +28 -12
  218. imap_processing/tests/ultra/unit/test_ultra_l1b.py +34 -6
  219. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +22 -26
  220. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -51
  221. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +94 -52
  222. imap_processing/ultra/l0/decom_tools.py +6 -5
  223. imap_processing/ultra/l1a/ultra_l1a.py +28 -56
  224. imap_processing/ultra/l1b/de.py +72 -28
  225. imap_processing/ultra/l1b/extendedspin.py +12 -14
  226. imap_processing/ultra/l1b/ultra_l1b.py +34 -9
  227. imap_processing/ultra/l1b/ultra_l1b_culling.py +65 -29
  228. imap_processing/ultra/l1b/ultra_l1b_extended.py +64 -19
  229. imap_processing/ultra/l1c/spacecraft_pset.py +86 -0
  230. imap_processing/ultra/l1c/ultra_l1c.py +7 -4
  231. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +112 -61
  232. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  233. imap_processing/ultra/utils/ultra_l1_utils.py +20 -2
  234. imap_processing/utils.py +68 -28
  235. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/METADATA +8 -5
  236. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/RECORD +250 -199
  237. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  238. imap_processing/hi/l1a/housekeeping.py +0 -27
  239. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  240. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  241. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  242. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  243. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  244. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  245. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  246. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  247. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  248. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  249. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  250. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  251. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  252. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  253. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  254. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  255. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  256. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  257. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  258. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  259. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  260. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  261. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  262. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  263. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  264. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  265. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  266. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  267. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  268. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  269. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  270. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  271. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  272. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  273. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  274. imap_processing/ultra/l1c/pset.py +0 -40
  275. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  276. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  277. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  278. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  279. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  280. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  281. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  282. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  283. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  284. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  285. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  286. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/LICENSE +0 -0
  287. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/WHEEL +0 -0
  288. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,123 @@
1
+ """Spacecraft quaternion processing."""
2
+
3
+ from pathlib import Path
4
+
5
+ import numpy as np
6
+ import xarray as xr
7
+
8
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
9
+ from imap_processing.spice.time import met_to_ttj2000ns
10
+ from imap_processing.utils import packet_file_to_datasets
11
+
12
+
13
+ def load_quaternion_packets(packet_file: Path | str) -> xr.Dataset:
14
+ """
15
+ Load the raw quaternion packets from the packet file.
16
+
17
+ Parameters
18
+ ----------
19
+ packet_file : Path
20
+ Path to the packet file containing the quaternions in apid 594.
21
+
22
+ Returns
23
+ -------
24
+ xarray.Dataset
25
+ Dataset containing the raw quaternion packets.
26
+ """
27
+ xtce_packet_definition = Path(__file__).parent / "packet_definitions/scid_x252.xml"
28
+ datasets_by_apid = packet_file_to_datasets(
29
+ packet_file=packet_file, xtce_packet_definition=xtce_packet_definition
30
+ )
31
+ return datasets_by_apid[0x252]
32
+
33
+
34
+ def assemble_quaternions(ds: xr.Dataset) -> xr.Dataset:
35
+ """
36
+ Assemble quaternions from the l1a dataset.
37
+
38
+ The quaternions are stored in separate variables for each component (x, y, z, s)
39
+ and for each 10 Hz sample of the 1s packet. i.e. there are 4 * 10 = 40 variables
40
+ in the initial dataset that we want to turn into 4 variables with a continuous
41
+ 10 Hz sampling period.
42
+
43
+ The output dataset will have a single dimension "epoch" that will be the time
44
+ associated with each of the 10 Hz samples. There are 4 data variables: "quat_x",
45
+ "quat_y", "quat_z", "quat_s".
46
+
47
+ Parameters
48
+ ----------
49
+ ds : xarray.Dataset
50
+ Input dataset containing the 10Hz quaternions from packet 0x252 (APID 594).
51
+
52
+ Returns
53
+ -------
54
+ xarray.Dataset
55
+ Output dataset with the quaternions assembled into 4 variables with a
56
+ continuous 10 Hz sampling period.
57
+ """
58
+ # Our time is only given for the first timestamp
59
+ # We then add to it 0.1 increments and ravel the array to associate a specific time
60
+ # with each of the 10 samples
61
+ time = (
62
+ ds["SCIENCEDATA1HZ_QUAT_10_HZ_TIME".lower()].values[:, np.newaxis]
63
+ + np.arange(0, 1, 0.1)
64
+ ).ravel()
65
+ output_ds = xr.Dataset(coords={"epoch": time})
66
+ base_name = "FSW_ACS_QUAT_10_HZ_BUFFERED".lower()
67
+ for quat_i, label in enumerate(["x", "y", "z", "s"]):
68
+ # 0, 1, 2, .. 9 // 10, 11, 12, .. 19 // 20, 21, 22, .. 29 // 30, 31, 32, .. 39
69
+ names = [f"{base_name}_{i + quat_i*10}" for i in range(10)]
70
+ quat = np.stack([ds[name] for name in names], axis=1).ravel()
71
+ output_ds[f"quat_{label}"] = ("epoch", quat)
72
+ return output_ds
73
+
74
+
75
+ def process_quaternions(packet_file: Path | str) -> tuple[xr.Dataset, xr.Dataset]:
76
+ """
77
+ Generate l1a and l1b datasets from a packet file containing the raw quaternions.
78
+
79
+ This produces two CDF files: one for the l1a quaternions and one for the l1b
80
+ quaternions. The l1b quaternions are assembled into 4 variables: "quat_x",
81
+ "quat_y", "quat_z", "quat_s".
82
+
83
+ Parameters
84
+ ----------
85
+ packet_file : Path
86
+ Path to the packet file containing the quaternions in apid 594.
87
+
88
+ Returns
89
+ -------
90
+ xarray.Dataset
91
+ Dataset containing the l1a quaternions.
92
+ xarray.Dataset
93
+ Dataset containing the l1b quaternions.
94
+ """
95
+ l1a_ds = load_quaternion_packets(packet_file)
96
+
97
+ # Assemble the quaternions into the correct components
98
+ l1b_ds = assemble_quaternions(l1a_ds)
99
+
100
+ # Update dataset global attributes
101
+ attr_mgr = ImapCdfAttributes()
102
+ attr_mgr.add_instrument_global_attrs("spacecraft")
103
+ # TODO: Allow version to be passed in
104
+ attr_mgr.add_global_attribute("Data_version", 1)
105
+ attr_mgr.add_instrument_variable_attrs(instrument="spacecraft", level=None)
106
+
107
+ l1a_ds.attrs.update(
108
+ attr_mgr.get_global_attributes("imap_spacecraft_l1a_quaternions")
109
+ )
110
+ l1b_ds.attrs.update(
111
+ attr_mgr.get_global_attributes("imap_spacecraft_l1b_quaternions")
112
+ )
113
+
114
+ # Update the epoch attribute
115
+ l1b_ds["epoch"] = met_to_ttj2000ns(l1b_ds["epoch"])
116
+ # check_schema=False keeps DEPEND_0 = '' from being auto added
117
+ epoch_attrs = attr_mgr.get_variable_attributes("epoch", check_schema=False)
118
+ l1b_ds["epoch"].attrs.update(epoch_attrs)
119
+
120
+ for var in ["quat_x", "quat_y", "quat_z", "quat_s"]:
121
+ l1b_ds[var].attrs.update(attr_mgr.get_variable_attributes(var))
122
+
123
+ return l1a_ds, l1b_ds
@@ -268,7 +268,7 @@ def frame_transform_az_el(
268
268
  spherical_coords_in = np.array(
269
269
  [np.ones_like(az_el[..., 0]), az_el[..., 0], az_el[..., 1]]
270
270
  ).T
271
- from_frame_cartesian = spherical_to_cartesian(spherical_coords_in, degrees=degrees)
271
+ from_frame_cartesian = spherical_to_cartesian(spherical_coords_in)
272
272
  # Transform to to_frame
273
273
  to_frame_cartesian = frame_transform(et, from_frame_cartesian, from_frame, to_frame)
274
274
  # Convert to spherical and extract azimuth/elevation
@@ -425,14 +425,14 @@ def cartesian_to_spherical(
425
425
  - r : Distance of the point from the origin.
426
426
  - azimuth : angle in the xy-plane
427
427
  In degrees if degrees parameter is True (by default):
428
- output range=[0, 360],
428
+ output range=[0, 360) degrees,
429
429
  otherwise in radians if degrees parameter is False:
430
- output range=[0, 2*pi].
430
+ output range=[0, 2*pi) radians.
431
431
  - elevation : angle from the xy-plane
432
432
  In degrees if degrees parameter is True (by default):
433
- output range=[0, 180],
433
+ output range=[-90, 90) degrees,
434
434
  otherwise in radians if degrees parameter is False:
435
- output range=[-pi/2, pi/2].
435
+ output range=[-pi/2, pi/2) radians.
436
436
  """
437
437
  # Magnitude of the velocity vector
438
438
  magnitude_v = np.linalg.norm(v, axis=-1, keepdims=True)
@@ -457,9 +457,9 @@ def cartesian_to_spherical(
457
457
  return spherical_coords
458
458
 
459
459
 
460
- def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) -> NDArray:
460
+ def spherical_to_cartesian(spherical_coords: NDArray) -> NDArray:
461
461
  """
462
- Convert spherical coordinates to Cartesian coordinates.
462
+ Convert spherical coordinates (angles in degrees) to Cartesian coordinates.
463
463
 
464
464
  Parameters
465
465
  ----------
@@ -468,11 +468,8 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
468
468
  the spherical coordinates (r, azimuth, elevation):
469
469
 
470
470
  - r : Distance of the point from the origin.
471
- - azimuth : angle in the xy-plane in radians [0, 2*pi].
472
- - elevation : angle from the xy-plane in radians [-pi/2, pi/2].
473
- degrees : bool
474
- Set to True if input azimuth and elevation angles are in degrees.
475
- Defaults to False.
471
+ - azimuth : angle in the xy-plane in degrees. Range is [0, 360) degrees.
472
+ - elevation : angle from the xy-plane in degrees. Range is [-90, 90) degrees.
476
473
 
477
474
  Returns
478
475
  -------
@@ -483,9 +480,9 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
483
480
  azimuth = spherical_coords[..., 1]
484
481
  elevation = spherical_coords[..., 2]
485
482
 
486
- if degrees:
487
- azimuth = np.radians(azimuth)
488
- elevation = np.radians(elevation)
483
+ # Convert to radians for numpy trigonometric operations
484
+ azimuth = np.deg2rad(azimuth)
485
+ elevation = np.deg2rad(elevation)
489
486
 
490
487
  x = r * np.cos(elevation) * np.cos(azimuth)
491
488
  y = r * np.cos(elevation) * np.sin(azimuth)
@@ -496,7 +493,7 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
496
493
  return cartesian_coords
497
494
 
498
495
 
499
- def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
496
+ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = True) -> NDArray:
500
497
  """
501
498
  Convert cartesian coordinates to latitudinal coordinates in radians.
502
499
 
@@ -511,7 +508,7 @@ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
511
508
  with x, y, z-components.
512
509
  degrees : bool
513
510
  If True, the longitude and latitude coords are returned in degrees.
514
- Defaults to False.
511
+ Defaults to True.
515
512
 
516
513
  Returns
517
514
  -------
@@ -532,7 +529,7 @@ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
532
529
 
533
530
  def solar_longitude(
534
531
  et: Union[np.ndarray, float],
535
- degrees: bool = False,
532
+ degrees: bool = True,
536
533
  ) -> Union[float, npt.NDArray]:
537
534
  """
538
535
  Compute the solar longitude of the Imap Spacecraft.
@@ -543,7 +540,7 @@ def solar_longitude(
543
540
  Ephemeris time(s) to at which to compute solar longitude.
544
541
  degrees : bool
545
542
  If True, the longitude is returned in degrees.
546
- Defaults to False.
543
+ Defaults to True.
547
544
 
548
545
  Returns
549
546
  -------
@@ -0,0 +1,120 @@
1
+ """Functions for retrieving repointing table data."""
2
+
3
+ import logging
4
+ import os
5
+ from pathlib import Path
6
+ from typing import Union
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+ from numpy import typing as npt
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def get_repoint_data() -> pd.DataFrame:
16
+ """
17
+ Read repointing file using environment variable and return as dataframe.
18
+
19
+ REPOINT_DATA_FILEPATH environment variable should point to a local
20
+ file where the repointing csv file is located.
21
+
22
+ Returns
23
+ -------
24
+ repoint_df : pd.DataFrame
25
+ The repointing csv loaded into a pandas dataframe. The dataframe will
26
+ contain the following columns:
27
+ - `repoint_start_time`: Starting MET time of each repoint maneuver.
28
+ - `repoint_end_time`: Ending MET time of each repoint maneuver.
29
+ - `repoint_id`: Unique ID number of each repoint maneuver.
30
+ """
31
+ repoint_data_filepath = os.getenv("REPOINT_DATA_FILEPATH")
32
+ if repoint_data_filepath is not None:
33
+ path_to_spin_file = Path(repoint_data_filepath)
34
+ else:
35
+ # Handle the case where the environment variable is not set
36
+ raise ValueError("REPOINT_DATA_FILEPATH environment variable is not set.")
37
+
38
+ logger.info(f"Reading repointing data from {path_to_spin_file}")
39
+ repoint_df = pd.read_csv(path_to_spin_file, comment="#")
40
+
41
+ return repoint_df
42
+
43
+
44
+ def interpolate_repoint_data(
45
+ query_met_times: Union[float, npt.NDArray],
46
+ ) -> pd.DataFrame:
47
+ """
48
+ Interpolate repointing data to the queried MET times.
49
+
50
+ In addition to the repoint start, end, and id values that come directly from
51
+ the universal repointing table, a column is added to the output dataframe
52
+ which indicates whether each query met time occurs during a repoint maneuver
53
+ i.e. between the repoint start and end times of a row in the repointing
54
+ table.
55
+
56
+ Query times that are more than 24-hours after that last repoint start time
57
+ in the repoint table will cause an error to be raised. The assumption here
58
+ is that we shouldn't be processing data that occurs that close to the next
59
+ expected repoint start time before getting an updated repoint table.
60
+
61
+ Parameters
62
+ ----------
63
+ query_met_times : float or np.ndarray
64
+ Query times in Mission Elapsed Time (MET).
65
+
66
+ Returns
67
+ -------
68
+ repoint_df : pandas.DataFrame
69
+ Repoint table data interpolated such that there is one row
70
+ for each of the queried MET times. Output columns are:
71
+ - `repoint_start_time`
72
+ - `repoint_end_time`
73
+ - `repoint_id`
74
+ - `repoint_in_progress`
75
+
76
+ Raises
77
+ ------
78
+ ValueError : If any of the query_met_times are before the first repoint
79
+ start time or after the last repoint start time plus 24-hours.
80
+ """
81
+ repoint_df = get_repoint_data()
82
+
83
+ # Ensure query_met_times is an array
84
+ query_met_times = np.atleast_1d(query_met_times)
85
+
86
+ # Make sure no query times are before the first repoint in the dataframe.
87
+ repoint_df_start_time = repoint_df["repoint_start_time"].values[0]
88
+ if np.any(query_met_times < repoint_df_start_time):
89
+ bad_times = query_met_times[query_met_times < repoint_df_start_time]
90
+ raise ValueError(
91
+ f"{bad_times.size} query times are before the first repoint start "
92
+ f" time in the repoint table. {bad_times=}, {repoint_df_start_time=}"
93
+ )
94
+ # Make sure that no query times are after the valid range of the dataframe.
95
+ # We approximate the end time of the table by adding 24 hours to the last
96
+ # known repoint start time.
97
+ repoint_df_end_time = repoint_df["repoint_start_time"].values[-1] + 24 * 60 * 60
98
+ if np.any(query_met_times >= repoint_df_end_time):
99
+ bad_times = query_met_times[query_met_times >= repoint_df_end_time]
100
+ raise ValueError(
101
+ f"{bad_times.size} query times are after the valid time of the "
102
+ f"pointing table. The valid end time is 24-hours after the last "
103
+ f"repoint_start_time. {bad_times=}, {repoint_df_end_time=}"
104
+ )
105
+
106
+ # Find the row index for each queried MET time such that:
107
+ # repoint_start_time[i] <= MET < repoint_start_time[i+1]
108
+ row_indices = (
109
+ np.searchsorted(repoint_df["repoint_start_time"], query_met_times, side="right")
110
+ - 1
111
+ )
112
+ out_df = repoint_df.iloc[row_indices]
113
+
114
+ # Add a column indicating if the query time is during a repoint or not.
115
+ # The table already has the correct row for each query time, so we
116
+ # only need to check if the query time is less than the repoint end time to
117
+ # get the same result as `repoint_start_time <= query_met_times < repoint_end_time`.
118
+ out_df["repoint_in_progress"] = query_met_times < out_df["repoint_end_time"].values
119
+
120
+ return out_df
@@ -509,6 +509,10 @@ def process_swapi_science(
509
509
  # since we are not processing in real-time, the ground processing
510
510
  # algorithm should use the closest timestamp HK packet to fill in
511
511
  # the data quality for the SCI data per SWAPI team.
512
+
513
+ # Drop duplicate epoch values in HK data. Otherwise, the nearest
514
+ # method will not work as expected because .sel requires unique values.
515
+ hk_dataset = hk_dataset.drop_duplicates("epoch")
512
516
  good_sweep_times = good_sweep_sci["epoch"].data
513
517
  good_sweep_hk_data = hk_dataset.sel({"epoch": good_sweep_times}, method="nearest")
514
518
 
@@ -62,7 +62,6 @@ def swapi_l2(l1_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
62
62
  # Update L2 specific attributes
63
63
  l2_dataset.attrs["Data_version"] = data_version
64
64
  l2_global_attrs = cdf_manager.get_global_attributes("imap_swapi_l2_sci")
65
- l2_dataset.attrs["Data_level"] = l2_global_attrs["Data_level"]
66
65
  l2_dataset.attrs["Data_type"] = l2_global_attrs["Data_type"]
67
66
  l2_dataset.attrs["Logical_source"] = l2_global_attrs["Logical_source"]
68
67
  l2_dataset.attrs["Logical_source_description"] = l2_global_attrs[
@@ -5,6 +5,7 @@ import logging
5
5
  import xarray as xr
6
6
 
7
7
  from imap_processing import imap_module_directory
8
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
8
9
  from imap_processing.swe.l1a.swe_science import swe_science
9
10
  from imap_processing.swe.utils.swe_utils import (
10
11
  SWEAPID,
@@ -42,12 +43,50 @@ def swe_l1a(packet_file: str, data_version: str) -> xr.Dataset:
42
43
  packet_file, xtce_document, use_derived_value=False
43
44
  )
44
45
 
45
- if SWEAPID.SWE_SCIENCE not in datasets_by_apid:
46
- logger.info("No science data found in packet file.")
47
- return []
48
- # TODO: figure out how to handle non-science data
49
- return [
50
- swe_science(
51
- l0_dataset=datasets_by_apid[SWEAPID.SWE_SCIENCE], data_version=data_version
46
+ processed_data = []
47
+
48
+ if SWEAPID.SWE_SCIENCE in datasets_by_apid:
49
+ logger.info("Processing SWE science data.")
50
+ processed_data.append(
51
+ swe_science(
52
+ l0_dataset=datasets_by_apid[SWEAPID.SWE_SCIENCE],
53
+ data_version=data_version,
54
+ )
55
+ )
56
+
57
+ # Process non-science data
58
+ # Define minimal CDF attrs for the non science dataset
59
+ imap_attrs = ImapCdfAttributes()
60
+ imap_attrs.add_instrument_global_attrs("swe")
61
+ imap_attrs.add_global_attribute("Data_version", data_version)
62
+ imap_attrs.add_instrument_variable_attrs("swe", "l1a")
63
+ non_science_attrs = imap_attrs.get_variable_attributes("non_science_attrs")
64
+ epoch_attrs = imap_attrs.get_variable_attributes("epoch", check_schema=False)
65
+
66
+ if SWEAPID.SWE_APP_HK in datasets_by_apid:
67
+ logger.info("Processing SWE housekeeping data.")
68
+ hk_ds = datasets_by_apid[SWEAPID.SWE_APP_HK]
69
+ hk_ds.attrs.update(imap_attrs.get_global_attributes("imap_swe_l1a_hk"))
70
+ hk_ds["epoch"].attrs.update(epoch_attrs)
71
+ # Add attrs to HK data variables
72
+ for var_name in hk_ds.data_vars:
73
+ hk_ds[var_name].attrs.update(non_science_attrs)
74
+ processed_data.append(hk_ds)
75
+
76
+ if SWEAPID.SWE_CEM_RAW in datasets_by_apid:
77
+ logger.info("Processing SWE CEM raw data.")
78
+ cem_raw_ds = datasets_by_apid[SWEAPID.SWE_CEM_RAW]
79
+ cem_raw_ds.attrs.update(
80
+ imap_attrs.get_global_attributes("imap_swe_l1a_cem-raw")
52
81
  )
53
- ]
82
+ cem_raw_ds["epoch"].attrs.update(epoch_attrs)
83
+
84
+ # Add attrs to CEM raw data variables
85
+ for var_name in cem_raw_ds.data_vars:
86
+ cem_raw_ds[var_name].attrs.update(non_science_attrs)
87
+ processed_data.append(cem_raw_ds)
88
+
89
+ if len(processed_data) == 0:
90
+ logger.info("Data contains unknown APID.")
91
+
92
+ return processed_data
@@ -6,6 +6,7 @@ import numpy as np
6
6
  import xarray as xr
7
7
 
8
8
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
9
+ from imap_processing.swe.utils import swe_constants
9
10
  from imap_processing.swe.utils.swe_utils import SWEAPID
10
11
 
11
12
  logger = logging.getLogger(__name__)
@@ -119,7 +120,9 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
119
120
  # 4. Reshape the data to 180 x 7
120
121
  raw_science_array = np.array(
121
122
  [
122
- np.frombuffer(binary_string, dtype=np.uint8).reshape(180, 7)
123
+ np.frombuffer(binary_string, dtype=np.uint8).reshape(
124
+ 180, swe_constants.N_CEMS
125
+ )
123
126
  for binary_string in l0_dataset["science_data"].values
124
127
  ]
125
128
  )
@@ -157,7 +160,7 @@ def swe_science(l0_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
157
160
  )
158
161
 
159
162
  cem_id = xr.DataArray(
160
- np.arange(7),
163
+ np.arange(swe_constants.N_CEMS),
161
164
  name="cem_id",
162
165
  dims=["cem_id"],
163
166
  attrs=cdf_attrs.get_variable_attributes("cem_id"),