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
@@ -10,3 +10,21 @@ def test_cdf_creation():
10
10
  cem_raw_cdf_filepath = write_cdf(processed_data[0])
11
11
 
12
12
  assert cem_raw_cdf_filepath.name == "imap_swe_l1a_sci_20240510_v001.cdf"
13
+
14
+
15
+ def test_cdf_creation_hk():
16
+ test_data_path = "tests/swe/l0_data/2024051010_SWE_HK_packet.bin"
17
+ processed_data = swe_l1a(imap_module_directory / test_data_path, "001")
18
+
19
+ hk_cdf_filepath = write_cdf(processed_data[0])
20
+
21
+ assert hk_cdf_filepath.name == "imap_swe_l1a_hk_20240510_v001.cdf"
22
+
23
+
24
+ def test_cdf_creation_cem_raw():
25
+ test_data_path = "tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin"
26
+ processed_data = swe_l1a(imap_module_directory / test_data_path, "001")
27
+
28
+ cem_raw_cdf_filepath = write_cdf(processed_data[0])
29
+
30
+ assert cem_raw_cdf_filepath.name == "imap_swe_l1a_cem-raw_20240510_v001.cdf"
@@ -0,0 +1,52 @@
1
+ from dataclasses import fields
2
+
3
+ import pandas as pd
4
+ import pytest
5
+
6
+ from imap_processing import imap_module_directory
7
+ from imap_processing.ccsds.ccsds_data import CcsdsData
8
+ from imap_processing.swe.utils.swe_utils import SWEAPID
9
+ from imap_processing.utils import packet_file_to_datasets
10
+
11
+
12
+ @pytest.fixture(scope="session")
13
+ def decom_raw_cem_data():
14
+ """Read test data from file"""
15
+ test_folder_path = imap_module_directory / "tests/swe/l0_data"
16
+ packet_file = test_folder_path / "2024051011_SWE_CEM_RAW_packet.bin"
17
+ xtce_document = (
18
+ imap_module_directory / "swe/packet_definitions/swe_packet_definition.xml"
19
+ )
20
+ datasets_by_apid = packet_file_to_datasets(
21
+ packet_file, xtce_document, use_derived_value=False
22
+ )
23
+ return datasets_by_apid[SWEAPID.SWE_CEM_RAW]
24
+
25
+
26
+ def test_number_of_packets(decom_raw_cem_data):
27
+ """This test and validate number of packets."""
28
+ expected_number_of_packets = 25
29
+ assert len(decom_raw_cem_data) == expected_number_of_packets
30
+
31
+
32
+ def test_swe_raw_cem_data(decom_raw_cem_data):
33
+ """This test and validate raw data of SWE raw CEM data."""
34
+ # read validation data
35
+ test_data_path = imap_module_directory / "tests/swe/l0_validation_data"
36
+ raw_validation_data = pd.read_csv(
37
+ test_data_path / "idle_export_eu.SWE_CEM_RAW_20240510_092742.csv",
38
+ index_col="SHCOARSE",
39
+ )
40
+
41
+ first_data = decom_raw_cem_data.isel(epoch=0)
42
+ validation_data = raw_validation_data.loc[first_data["shcoarse"].values]
43
+
44
+ ccsds_header_keys = [field.name for field in fields(CcsdsData)]
45
+ ccsds_header_keys += ["SHCOARSE"]
46
+
47
+ # compare unpacked data to validation data
48
+ for key in first_data.keys():
49
+ if key.upper() in ccsds_header_keys:
50
+ continue
51
+ # check if the data is the same.
52
+ assert first_data[key] == validation_data[key.upper()]
@@ -0,0 +1,68 @@
1
+ from dataclasses import fields
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import pytest
6
+
7
+ from imap_processing import imap_module_directory
8
+ from imap_processing.ccsds.ccsds_data import CcsdsData
9
+ from imap_processing.swe.utils.swe_utils import SWEAPID
10
+ from imap_processing.utils import packet_file_to_datasets
11
+
12
+
13
+ @pytest.fixture(scope="session")
14
+ def decom_hk_data():
15
+ """Read test data from file"""
16
+ test_folder_path = imap_module_directory / "tests/swe/l0_data"
17
+ packet_file = test_folder_path / "2024051010_SWE_HK_packet.bin"
18
+ xtce_document = (
19
+ imap_module_directory / "swe/packet_definitions/swe_packet_definition.xml"
20
+ )
21
+ datasets_by_apid = packet_file_to_datasets(
22
+ packet_file,
23
+ xtce_document,
24
+ use_derived_value=True,
25
+ )
26
+ return datasets_by_apid[SWEAPID.SWE_APP_HK]
27
+
28
+
29
+ def test_swe_hk_data(decom_hk_data):
30
+ """This test and validate raw data of SWAPI raw housekeeping data."""
31
+ # read validation data
32
+ test_data_path = imap_module_directory / "tests/swe/l0_validation_data"
33
+
34
+ raw_validation_data = pd.read_csv(
35
+ test_data_path / "idle_export_eu.SWE_APP_HK_20240510_092742.csv",
36
+ index_col="SHCOARSE",
37
+ )
38
+
39
+ first_data = decom_hk_data.isel(epoch=0)
40
+ validation_data = raw_validation_data.loc[first_data["shcoarse"].values]
41
+
42
+ # TODO: check with SWE team
43
+ mismatched_keys = [
44
+ "HVPS_ESA_DAC",
45
+ ]
46
+
47
+ ccsds_header_keys = [field.name for field in fields(CcsdsData)]
48
+ ccsds_header_keys += ["SHCOARSE"]
49
+ # compare raw values of validation data
50
+ for key in first_data.keys():
51
+ data_key = key.upper()
52
+ if data_key in ccsds_header_keys:
53
+ continue
54
+
55
+ if data_key in mismatched_keys:
56
+ continue
57
+
58
+ # Compare derived string values to validation data
59
+ if str(first_data[key].dtype).startswith("<U"):
60
+ assert first_data[key].values == validation_data[data_key]
61
+ # Compare derived float values to validation data
62
+ elif first_data[key].dtype == "float64":
63
+ np.testing.assert_almost_equal(
64
+ first_data[key].values, validation_data[data_key], decimal=6
65
+ )
66
+ # Compare derived integer values to validation data
67
+ else:
68
+ assert first_data[key].values == validation_data[data_key]
@@ -9,6 +9,7 @@ from imap_processing.swe.l1b.swe_l1b_science import (
9
9
  apply_in_flight_calibration,
10
10
  get_indices_of_full_cycles,
11
11
  )
12
+ from imap_processing.swe.utils import swe_constants
12
13
 
13
14
 
14
15
  @pytest.fixture(scope="session")
@@ -57,8 +58,17 @@ def test_in_flight_calibration_factor(mock_read_in_flight_cal_data, l1a_test_dat
57
58
 
58
59
  input_time = 453051355.0
59
60
  input_count = 19967
60
- one_full_cycle_data = np.full((24, 30, 7), input_count)
61
- acquisition_time = np.full((24, 30), input_time)
61
+ one_full_cycle_data = np.full(
62
+ (
63
+ swe_constants.N_ESA_STEPS,
64
+ swe_constants.N_ANGLE_SECTORS,
65
+ swe_constants.N_CEMS,
66
+ ),
67
+ input_count,
68
+ )
69
+ acquisition_time = np.full(
70
+ (swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS), input_time
71
+ )
62
72
 
63
73
  # Test that calibration factor is within correct range given test data
64
74
  expected_cal_factor = 1 + ((2 - 1) / (453051900 - 453051300)) * (
@@ -72,13 +82,22 @@ def test_in_flight_calibration_factor(mock_read_in_flight_cal_data, l1a_test_dat
72
82
 
73
83
  np.testing.assert_allclose(
74
84
  calibrated_count,
75
- np.full((24, 30, 7), input_count * expected_cal_factor),
85
+ np.full(
86
+ (
87
+ swe_constants.N_ESA_STEPS,
88
+ swe_constants.N_ANGLE_SECTORS,
89
+ swe_constants.N_CEMS,
90
+ ),
91
+ input_count * expected_cal_factor,
92
+ ),
76
93
  rtol=1e-9,
77
94
  )
78
95
 
79
96
  # Check for value outside of calibration time range
80
97
  input_time = 1.0
81
- acquisition_time = np.full((24, 30), input_time)
98
+ acquisition_time = np.full(
99
+ (swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS), input_time
100
+ )
82
101
 
83
102
  with pytest.raises(ValueError, match="Acquisition min/max times: "):
84
103
  apply_in_flight_calibration(one_full_cycle_data, acquisition_time)
@@ -10,8 +10,6 @@ from imap_processing.cdf.utils import write_cdf
10
10
  from imap_processing.swe.l1a.swe_l1a import swe_l1a
11
11
  from imap_processing.swe.l1b.swe_l1b import swe_l1b
12
12
  from imap_processing.swe.l2.swe_l2 import (
13
- ENERGY_CONVERSION_FACTOR,
14
- VELOCITY_CONVERSION_FACTOR,
15
13
  calculate_flux,
16
14
  calculate_phase_space_density,
17
15
  find_angle_bin_indices,
@@ -19,17 +17,25 @@ from imap_processing.swe.l2.swe_l2 import (
19
17
  put_data_into_angle_bins,
20
18
  swe_l2,
21
19
  )
22
- from imap_processing.swe.utils.swe_utils import read_lookup_table
20
+ from imap_processing.swe.utils import swe_constants
21
+ from imap_processing.swe.utils.swe_utils import (
22
+ read_lookup_table,
23
+ )
23
24
 
24
25
 
25
26
  def test_get_particle_energy():
26
27
  """Test get_particle_energy function."""
27
28
  all_energy = get_particle_energy()
28
- expected_energy = read_lookup_table()["esa_v"].values * ENERGY_CONVERSION_FACTOR
29
+ expected_energy = (
30
+ read_lookup_table()["esa_v"].values * swe_constants.ENERGY_CONVERSION_FACTOR
31
+ )
29
32
  np.testing.assert_array_equal(all_energy["energy"], expected_energy)
30
33
 
31
34
 
32
- @patch("imap_processing.swe.l2.swe_l2.GEOMETRIC_FACTORS", new=np.full(7, 1))
35
+ @patch(
36
+ "imap_processing.swe.utils.swe_constants.GEOMETRIC_FACTORS",
37
+ new=np.full(swe_constants.N_CEMS, 1),
38
+ )
33
39
  @patch(
34
40
  "imap_processing.swe.l2.swe_l2.get_particle_energy",
35
41
  return_value=pd.DataFrame(
@@ -50,21 +56,34 @@ def test_calculate_phase_space_density(patch_get_particle_energy):
50
56
  {
51
57
  "science_data": (
52
58
  ["epoch", "energy", "angle", "cem"],
53
- np.full((total_sweeps, 24, 30, 7), 1),
59
+ np.full(
60
+ (
61
+ total_sweeps,
62
+ swe_constants.N_ESA_STEPS,
63
+ swe_constants.N_ANGLE_SECTORS,
64
+ swe_constants.N_CEMS,
65
+ ),
66
+ 1,
67
+ ),
68
+ ),
69
+ "acq_duration": (
70
+ ["epoch", "cycle"],
71
+ np.full((total_sweeps, swe_constants.N_QUARTER_CYCLES), 80.0),
54
72
  ),
55
- "acq_duration": (["epoch", "cycle"], np.full((total_sweeps, 4), 80.0)),
56
73
  "esa_table_num": (
57
74
  ["epoch", "cycle"],
58
- np.repeat([0, 1], 4).reshape(total_sweeps, 4),
75
+ np.repeat([0, 1], swe_constants.N_QUARTER_CYCLES).reshape(
76
+ total_sweeps, swe_constants.N_QUARTER_CYCLES
77
+ ),
59
78
  ),
60
79
  }
61
80
  )
62
81
  phase_space_density_ds = calculate_phase_space_density(l1b_dataset)
63
82
  assert phase_space_density_ds["phase_space_density"].shape == (
64
83
  total_sweeps,
65
- 24,
66
- 30,
67
- 7,
84
+ swe_constants.N_ESA_STEPS,
85
+ swe_constants.N_ANGLE_SECTORS,
86
+ swe_constants.N_CEMS,
68
87
  )
69
88
 
70
89
  # Test that first sweep has correct values. In patch,
@@ -72,16 +91,34 @@ def test_calculate_phase_space_density(patch_get_particle_energy):
72
91
  # 2. we have set energy to 1.
73
92
  # 3. we have set science_data to 1.
74
93
  # Using this in the formula, we calculate expected density value.
75
- expected_calculated_density = (2 * 1) / (1 * VELOCITY_CONVERSION_FACTOR * 1**2)
76
- expected_density = np.full((24, 30, 7), expected_calculated_density)
94
+ expected_calculated_density = (2 * 1) / (
95
+ 1 * swe_constants.VELOCITY_CONVERSION_FACTOR * 1**2
96
+ )
97
+ expected_density = np.full(
98
+ (
99
+ swe_constants.N_ESA_STEPS,
100
+ swe_constants.N_ANGLE_SECTORS,
101
+ swe_constants.N_CEMS,
102
+ ),
103
+ expected_calculated_density,
104
+ )
77
105
  np.testing.assert_array_equal(
78
106
  phase_space_density_ds["phase_space_density"][0].data, expected_density
79
107
  )
80
108
 
81
109
  # Test that second sweep has correct values, similar to first sweep,
82
110
  # but with energy 2.
83
- expected_calculated_density = (2 * 1) / (1 * VELOCITY_CONVERSION_FACTOR * 2**2)
84
- expected_density = np.full((24, 30, 7), expected_calculated_density)
111
+ expected_calculated_density = (2 * 1) / (
112
+ 1 * swe_constants.VELOCITY_CONVERSION_FACTOR * 2**2
113
+ )
114
+ expected_density = np.full(
115
+ (
116
+ swe_constants.N_ESA_STEPS,
117
+ swe_constants.N_ANGLE_SECTORS,
118
+ swe_constants.N_CEMS,
119
+ ),
120
+ expected_calculated_density,
121
+ )
85
122
  np.testing.assert_array_equal(
86
123
  phase_space_density_ds["phase_space_density"][1].data, expected_density
87
124
  )
@@ -96,18 +133,36 @@ def test_calculate_flux():
96
133
  {
97
134
  "science_data": (
98
135
  ["epoch", "energy", "angle", "cem"],
99
- np.full((total_sweeps, 24, 30, 7), 1),
136
+ np.full(
137
+ (
138
+ total_sweeps,
139
+ swe_constants.N_ESA_STEPS,
140
+ swe_constants.N_ANGLE_SECTORS,
141
+ swe_constants.N_CEMS,
142
+ ),
143
+ 1,
144
+ ),
145
+ ),
146
+ "acq_duration": (
147
+ ["epoch", "cycle"],
148
+ np.full((total_sweeps, swe_constants.N_QUARTER_CYCLES), 80.0),
100
149
  ),
101
- "acq_duration": (["epoch", "cycle"], np.full((total_sweeps, 4), 80.0)),
102
150
  "esa_table_num": (
103
151
  ["epoch", "cycle"],
104
- np.repeat([0, 1], 4).reshape(total_sweeps, 4),
152
+ np.repeat([0, 1], swe_constants.N_QUARTER_CYCLES).reshape(
153
+ total_sweeps, swe_constants.N_QUARTER_CYCLES
154
+ ),
105
155
  ),
106
156
  }
107
157
  )
108
158
 
109
159
  flux = calculate_flux(l1b_dataset)
110
- assert flux.shape == (total_sweeps, 24, 30, 7)
160
+ assert flux.shape == (
161
+ total_sweeps,
162
+ swe_constants.N_ESA_STEPS,
163
+ swe_constants.N_ANGLE_SECTORS,
164
+ swe_constants.N_CEMS,
165
+ )
111
166
  assert type(flux) == np.ndarray
112
167
 
113
168
 
@@ -142,18 +197,19 @@ def test_find_angle_bin_indices():
142
197
  def test_put_data_into_angle_bins():
143
198
  """Test put_data_into_angle_bins function."""
144
199
  num_cycles = 1
145
- num_esa_step = 24
146
- num_angle_bins = 30
147
- num_cems = 7
148
200
  # Create test counts data to test
149
201
  # Find all even numbers in the range 0 to 30
150
202
  even_numbers = np.arange(0, 30, 2)
151
203
  # repeat it twice now to get:
152
204
  # [0, 0, 2, 2, ...., 28, 28]
153
205
  example_data = np.repeat(even_numbers, 2)
154
- energy_angle_test_data = np.tile(example_data, (num_cycles, num_esa_step, 1))
206
+ energy_angle_test_data = np.tile(
207
+ example_data, (num_cycles, swe_constants.N_ESA_STEPS, 1)
208
+ )
155
209
  # Expand to include 7 CEMs by repeating across last dimension
156
- test_data = np.repeat(energy_angle_test_data[..., np.newaxis], num_cems, axis=-1)
210
+ test_data = np.repeat(
211
+ energy_angle_test_data[..., np.newaxis], swe_constants.N_CEMS, axis=-1
212
+ )
157
213
 
158
214
  # Took this example from intermediate output from actual data
159
215
  angle_bins_example = [
@@ -190,16 +246,28 @@ def test_put_data_into_angle_bins():
190
246
  ]
191
247
  # Now data with every row to be same as angle_bins_example
192
248
  test_angle_bin_indices_data = np.full(
193
- (num_cycles, num_esa_step, num_angle_bins), angle_bins_example
249
+ (num_cycles, swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS),
250
+ angle_bins_example,
194
251
  )
195
252
 
196
253
  binned_data = put_data_into_angle_bins(test_data, test_angle_bin_indices_data)
197
- assert binned_data.shape == (num_cycles, num_esa_step, num_angle_bins, num_cems)
254
+ assert binned_data.shape == (
255
+ num_cycles,
256
+ swe_constants.N_ESA_STEPS,
257
+ swe_constants.N_ANGLE_BINS,
258
+ swe_constants.N_CEMS,
259
+ )
198
260
 
199
261
  # Test that the binned data has correct values in correct bins by
200
262
  # checking that odd number columns are filled with nan
201
263
  expected_binned_data = np.full(
202
- (num_cycles, num_esa_step, num_angle_bins, num_cems), np.nan
264
+ (
265
+ num_cycles,
266
+ swe_constants.N_ESA_STEPS,
267
+ swe_constants.N_ANGLE_BINS,
268
+ swe_constants.N_CEMS,
269
+ ),
270
+ np.nan,
203
271
  )
204
272
  np.testing.assert_array_equal(
205
273
  binned_data[0, 0, 1::2, 0], expected_binned_data[0, 0, 1::2, 0]
@@ -259,9 +327,23 @@ def test_swe_l2(mock_read_in_flight_cal_data, use_fake_spin_data_for_time):
259
327
  l2_dataset = swe_l2(l1b_dataset[0], "002")
260
328
 
261
329
  assert type(l2_dataset) == xr.Dataset
262
- assert l2_dataset["phase_space_density_spin_sector"].shape == (6, 24, 30, 7)
263
- assert l2_dataset["flux_spin_sector"].shape == (6, 24, 30, 7)
264
- assert l2_dataset["acquisition_time"].shape == (6, 24, 30)
330
+ assert l2_dataset["phase_space_density_spin_sector"].shape == (
331
+ 6,
332
+ swe_constants.N_ESA_STEPS,
333
+ swe_constants.N_ANGLE_SECTORS,
334
+ swe_constants.N_CEMS,
335
+ )
336
+ assert l2_dataset["flux_spin_sector"].shape == (
337
+ 6,
338
+ swe_constants.N_ESA_STEPS,
339
+ swe_constants.N_ANGLE_SECTORS,
340
+ swe_constants.N_CEMS,
341
+ )
342
+ assert l2_dataset["acquisition_time"].shape == (
343
+ 6,
344
+ swe_constants.N_ESA_STEPS,
345
+ swe_constants.N_ANGLE_SECTORS,
346
+ )
265
347
 
266
348
  # Write L2 to CDF
267
349
  l2_cdf_filepath = write_cdf(l2_dataset)
@@ -62,8 +62,8 @@ def test_main(mock_instrument):
62
62
  @pytest.mark.parametrize(
63
63
  "instrument, data_level, raises_value_error",
64
64
  [
65
- ("mag", "l0", ""),
66
- ("foo", "l0", "foo is not in the supported .*"),
65
+ ("mag", "l1a", ""),
66
+ ("foo", "l1a", "foo is not in the supported .*"),
67
67
  ("codice", "l1z", "l1z is not a supported .*"),
68
68
  ],
69
69
  )
@@ -11,20 +11,29 @@ from imap_processing import imap_module_directory, utils
11
11
  def test_convert_raw_to_eu(tmp_path):
12
12
  """Test coverage for utils.convert_raw_to_eu()"""
13
13
  # Generate a csv for testing
14
+ # Include segmented and unsegmented polyvals
15
+ dn_cutoff = 2
14
16
  test_df = pd.DataFrame(
15
17
  data={
16
- "packetName": ["PACKET_0", "PACKET_0", "PACKET_1"],
17
- "mnemonic": ["FIELD_0", "FIELD_1", "FIELD_0"],
18
- "convertAs": ["UNSEGMENTED_POLY", "UNSEGMENTED_POLY", "FOO_METHOD"],
19
- "c0": [0, 1, 2],
20
- "c1": [0, 1, 2],
21
- "c2": [0, 0, 2],
22
- "c3": [0, 0, 2],
23
- "c4": [0, 0, 2],
24
- "c5": [0, 1, 2],
25
- "c6": [0, 0, 2],
26
- "c7": [0, 0, 2],
27
- "unit": ["a", "b", "c"],
18
+ "packetName": ["PACKET_0", "PACKET_0", "PACKET_2", "PACKET_2", "PACKET_1"],
19
+ "mnemonic": ["FIELD_0", "FIELD_1", "FIELD_2", "FIELD_2", "FIELD_0"],
20
+ "convertAs": [
21
+ "UNSEGMENTED_POLY",
22
+ "UNSEGMENTED_POLY",
23
+ "SEGMENTED_POLY",
24
+ "SEGMENTED_POLY",
25
+ "FOO_METHOD",
26
+ ],
27
+ "dn_range_start": [0, 0, 1, dn_cutoff + 1, 0],
28
+ "dn_range_stop": [0, 0, dn_cutoff, 4, 0],
29
+ "c0": [0, 1, 3, 4, 2],
30
+ "c1": [0, 1, 3, 4, 2],
31
+ "c2": [0, 0, 3, 4, 2],
32
+ "c3": [0, 0, 3, 4, 2],
33
+ "c5": [0, 1, 3, 4, 2],
34
+ "c6": [0, 0, 3, 4, 2],
35
+ "c7": [0, 0, 3, 4, 2],
36
+ "unit": ["a", "b", "d", "d", "c"],
28
37
  }
29
38
  )
30
39
  test_csv = tmp_path / "test_convert_table.csv"
@@ -36,11 +45,13 @@ def test_convert_raw_to_eu(tmp_path):
36
45
  n_packets = 3
37
46
  field_0 = np.arange(n_packets)
38
47
  field_1 = np.arange(n_packets) + 10
48
+ field_2 = np.arange(n_packets) + 1
39
49
  time = np.arange(n_packets) + 1000
40
50
  dn_dataset = xr.Dataset(
41
51
  data_vars=dict(
42
52
  FIELD_0=(["time"], field_0),
43
53
  FIELD_1=(["time"], field_1),
54
+ FIELD_2=(["time"], field_2),
44
55
  ),
45
56
  coords=dict(
46
57
  time=time,
@@ -53,7 +64,7 @@ def test_convert_raw_to_eu(tmp_path):
53
64
 
54
65
  # Check the converted values by manually doing the polynomial math
55
66
  np.testing.assert_array_equal(eu_dataset["FIELD_0"].data, np.zeros(n_packets))
56
- assert eu_dataset["FIELD_0"].attrs["units"] == test_df["unit"].iloc[0]
67
+ assert eu_dataset["FIELD_0"].attrs["UNITS"] == test_df["unit"].iloc[0]
57
68
 
58
69
  field_1_coeffs = (
59
70
  test_df[test_df["mnemonic"] == "FIELD_1"].filter(regex=r"c\d").values[0]
@@ -63,14 +74,125 @@ def test_convert_raw_to_eu(tmp_path):
63
74
  field_1_compare += coeff * np.power(field_1, p)
64
75
  np.testing.assert_array_equal(eu_dataset["FIELD_1"].data, field_1_compare)
65
76
 
77
+ eu_dataset = utils.convert_raw_to_eu(
78
+ dn_dataset.copy(), test_csv.absolute(), "PACKET_2", comment="#"
79
+ )
80
+ # Test the segmented polynomials
81
+ field_2_coeffs = (
82
+ test_df[test_df["mnemonic"] == "FIELD_2"].filter(regex=r"c\d").values
83
+ )
84
+ field_2_compare_seg_1 = np.zeros(len(field_2[field_2 <= dn_cutoff]))
85
+ field_2_compare_seg_2 = np.zeros(len(field_2[field_2 > dn_cutoff]))
86
+ for p, coeff in enumerate(field_2_coeffs[0]):
87
+ field_2_compare_seg_1 += coeff * np.power(field_2[field_2 <= dn_cutoff], p)
88
+ for p, coeff in enumerate(field_2_coeffs[1]):
89
+ field_2_compare_seg_2 += coeff * np.power(field_2[field_2 > dn_cutoff], p)
90
+
91
+ field_2_compare = np.concatenate([field_2_compare_seg_1, field_2_compare_seg_2])
92
+ np.testing.assert_array_equal(eu_dataset["FIELD_2"].data, field_2_compare)
93
+
94
+ assert eu_dataset["FIELD_2"].attrs["UNITS"] == test_df["unit"].iloc[2]
66
95
  # Check that a ValueError is raised for unexpected conversion specified in
67
96
  # conversion table "convertAs" column
68
- with pytest.raises(ValueError, match=r"Unexpected conversion type: .*"):
69
- eu_dataset = utils.convert_raw_to_eu(
97
+ with pytest.raises(
98
+ ValueError,
99
+ match="Column 'convertAs' must all be UNSEGMENTED_POLY or "
100
+ "SEGMENTED_POLY for a packet name and mnemonic",
101
+ ):
102
+ utils.convert_raw_to_eu(
70
103
  dn_dataset.copy(), test_csv.absolute(), "PACKET_1", comment="#"
71
104
  )
72
105
 
73
106
 
107
+ def test_segmented_poly_out_of_range(tmp_path):
108
+ """Test that a value error is thrown if a raw DN value is out of range"""
109
+ # Generate a csv for testing
110
+ test_df = pd.DataFrame(
111
+ data={
112
+ "packetName": ["PACKET_0", "PACKET_0"],
113
+ "mnemonic": ["FIELD_0", "FIELD_0"],
114
+ "convertAs": ["SEGMENTED_POLY", "SEGMENTED_POLY"],
115
+ # Make ranges higher than DNs
116
+ "dn_range_start": [100, 201],
117
+ "dn_range_stop": [200, 400],
118
+ "c0": [0, 1],
119
+ "c1": [0, 1],
120
+ "c2": [0, 1],
121
+ "c3": [0, 1],
122
+ "c5": [0, 1],
123
+ "c6": [0, 1],
124
+ "c7": [0, 1],
125
+ "unit": ["a", "b"],
126
+ }
127
+ )
128
+ test_csv = tmp_path / "test_convert_table.csv"
129
+ with open(test_csv, "w") as f:
130
+ f.write("# Comment on first line of file\n")
131
+ test_df.to_csv(f, index=False)
132
+
133
+ # Generate a fake dataset for testing
134
+ n_packets = 3
135
+ field_0 = np.arange(n_packets)
136
+ time = np.arange(n_packets) + 1000
137
+ dn_dataset = xr.Dataset(
138
+ data_vars=dict(
139
+ FIELD_0=(["time"], field_0),
140
+ ),
141
+ coords=dict(
142
+ time=time,
143
+ ),
144
+ )
145
+ # Check that a ValueError is raised for DNs not in any ranges
146
+ with pytest.raises(
147
+ ValueError, match="Raw DN values found outside of the expected range"
148
+ ):
149
+ utils.convert_raw_to_eu(
150
+ dn_dataset.copy(), test_csv.absolute(), "PACKET_0", comment="#"
151
+ )
152
+
153
+
154
+ def test_unsegmented_poly_multiple_rows(tmp_path):
155
+ """Test that a value error is thrown if there are multiple rows with the same
156
+ mnemonic and packet name and convertAs is UNSEGMENTED_POLY"""
157
+ # Generate a csv for testing
158
+ test_df = pd.DataFrame(
159
+ data={
160
+ "packetName": ["PACKET_0", "PACKET_0"],
161
+ "mnemonic": ["FIELD_0", "FIELD_0"],
162
+ "convertAs": ["UNSEGMENTED_POLY", "UNSEGMENTED_POLY"],
163
+ "c0": [0, 1],
164
+ "c1": [0, 1],
165
+ "c2": [0, 1],
166
+ "c3": [0, 1],
167
+ "c5": [0, 1],
168
+ "c6": [0, 1],
169
+ "c7": [0, 1],
170
+ "unit": ["a", "a"],
171
+ }
172
+ )
173
+ test_csv = tmp_path / "test_convert_table.csv"
174
+ with open(test_csv, "w") as f:
175
+ f.write("# Comment on first line of file\n")
176
+ test_df.to_csv(f, index=False)
177
+
178
+ # Generate a fake dataset for testing
179
+ field_0 = np.arange(3)
180
+ dn_dataset = xr.Dataset(
181
+ data_vars=dict(
182
+ FIELD_0=(["time"], field_0),
183
+ )
184
+ )
185
+ # Check that a ValueError is raised for DNs not in any ranges
186
+ with pytest.raises(
187
+ ValueError,
188
+ match="For unsegmented polynomial conversions, there should "
189
+ "only be one row per mnemonic and packet name",
190
+ ):
191
+ utils.convert_raw_to_eu(
192
+ dn_dataset.copy(), test_csv.absolute(), "PACKET_0", comment="#"
193
+ )
194
+
195
+
74
196
  @pytest.mark.parametrize(
75
197
  "use_derived_value, expected_mode",
76
198
  [(True, np.array(["HVENG", "HVSCI"])), (False, np.array([2, 3]))],
@@ -100,7 +222,7 @@ def test_packet_file_to_datasets(use_derived_value, expected_mode):
100
222
 
101
223
 
102
224
  def test_packet_file_to_datasets_flat_definition():
103
- test_file = "tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts"
225
+ test_file = "tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts"
104
226
  packet_files = imap_module_directory / test_file
105
227
  packet_definition = (
106
228
  imap_module_directory / "idex/packet_definitions/idex_packet_definition.xml"