imap-processing 0.9.0__py3-none-any.whl → 0.11.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 (243) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +749 -442
  3. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +7 -0
  4. imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +8 -2
  5. imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +0 -1
  6. imap_processing/cdf/config/imap_glows_l2_variable_attrs.yaml +358 -0
  7. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +59 -25
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +22 -0
  9. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +32 -8
  10. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +94 -5
  11. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +65 -37
  12. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +16 -1
  13. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +7 -0
  14. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +14 -14
  15. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +25 -24
  16. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +238 -0
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +100 -92
  18. imap_processing/cdf/utils.py +2 -2
  19. imap_processing/cli.py +45 -9
  20. imap_processing/codice/codice_l1a.py +104 -58
  21. imap_processing/codice/constants.py +111 -155
  22. imap_processing/codice/data/esa_sweep_values.csv +256 -256
  23. imap_processing/codice/data/lo_stepping_values.csv +128 -128
  24. imap_processing/ena_maps/ena_maps.py +519 -0
  25. imap_processing/ena_maps/utils/map_utils.py +145 -0
  26. imap_processing/ena_maps/utils/spatial_utils.py +226 -0
  27. imap_processing/glows/__init__.py +3 -0
  28. imap_processing/glows/ancillary/imap_glows_pipeline_settings_v001.json +52 -0
  29. imap_processing/glows/l1a/glows_l1a.py +72 -14
  30. imap_processing/glows/l1b/glows_l1b.py +2 -1
  31. imap_processing/glows/l1b/glows_l1b_data.py +25 -1
  32. imap_processing/glows/l2/glows_l2.py +324 -0
  33. imap_processing/glows/l2/glows_l2_data.py +156 -51
  34. imap_processing/hi/l1a/science_direct_event.py +57 -51
  35. imap_processing/hi/l1b/hi_l1b.py +43 -28
  36. imap_processing/hi/l1c/hi_l1c.py +225 -42
  37. imap_processing/hi/utils.py +20 -3
  38. imap_processing/hit/l0/constants.py +2 -2
  39. imap_processing/hit/l0/decom_hit.py +1 -1
  40. imap_processing/hit/l1a/hit_l1a.py +94 -13
  41. imap_processing/hit/l1b/hit_l1b.py +158 -9
  42. imap_processing/ialirt/l0/process_codicehi.py +156 -0
  43. imap_processing/ialirt/l0/process_codicelo.py +5 -2
  44. imap_processing/ialirt/packet_definitions/ialirt.xml +28 -20
  45. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +241 -0
  46. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +170 -0
  47. imap_processing/ialirt/packet_definitions/ialirt_swe.xml +258 -0
  48. imap_processing/ialirt/process_ephemeris.py +72 -40
  49. imap_processing/idex/decode.py +241 -0
  50. imap_processing/idex/idex_l1a.py +143 -81
  51. imap_processing/idex/idex_l1b.py +244 -10
  52. imap_processing/lo/l0/lo_science.py +61 -0
  53. imap_processing/lo/l1a/lo_l1a.py +98 -10
  54. imap_processing/lo/l1b/lo_l1b.py +2 -2
  55. imap_processing/lo/l1c/lo_l1c.py +2 -2
  56. imap_processing/lo/packet_definitions/lo_xtce.xml +1082 -9178
  57. imap_processing/mag/l0/decom_mag.py +2 -2
  58. imap_processing/mag/l1a/mag_l1a.py +7 -7
  59. imap_processing/mag/l1a/mag_l1a_data.py +62 -30
  60. imap_processing/mag/l1b/mag_l1b.py +11 -6
  61. imap_processing/quality_flags.py +18 -3
  62. imap_processing/spice/geometry.py +149 -177
  63. imap_processing/spice/kernels.py +26 -26
  64. imap_processing/spice/spin.py +233 -0
  65. imap_processing/spice/time.py +96 -31
  66. imap_processing/swapi/l1/swapi_l1.py +60 -31
  67. imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +363 -384
  68. imap_processing/swe/l1a/swe_l1a.py +8 -3
  69. imap_processing/swe/l1a/swe_science.py +24 -24
  70. imap_processing/swe/l1b/swe_l1b.py +2 -1
  71. imap_processing/swe/l1b/swe_l1b_science.py +181 -122
  72. imap_processing/swe/l2/swe_l2.py +337 -70
  73. imap_processing/swe/utils/swe_utils.py +28 -0
  74. imap_processing/tests/cdf/test_utils.py +2 -2
  75. imap_processing/tests/codice/conftest.py +20 -17
  76. imap_processing/tests/codice/data/validation/imap_codice_l1a_hskp_20241110193622_v0.0.0.cdf +0 -0
  77. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  78. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  79. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  80. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  81. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  82. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  83. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  84. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  85. imap_processing/tests/codice/test_codice_l0.py +55 -121
  86. imap_processing/tests/codice/test_codice_l1a.py +147 -59
  87. imap_processing/tests/conftest.py +81 -22
  88. imap_processing/tests/ena_maps/test_ena_maps.py +309 -0
  89. imap_processing/tests/ena_maps/test_map_utils.py +286 -0
  90. imap_processing/tests/ena_maps/test_spatial_utils.py +161 -0
  91. imap_processing/tests/glows/conftest.py +7 -1
  92. imap_processing/tests/glows/test_glows_l1a_cdf.py +3 -7
  93. imap_processing/tests/glows/test_glows_l1a_data.py +34 -6
  94. imap_processing/tests/glows/test_glows_l1b_data.py +29 -17
  95. imap_processing/tests/glows/test_glows_l2.py +101 -0
  96. imap_processing/tests/hi/conftest.py +3 -3
  97. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  98. imap_processing/tests/hi/data/l1/imap_his_pset-calibration-prod-config_20240101_v001.csv +31 -0
  99. imap_processing/tests/hi/test_hi_l1b.py +14 -9
  100. imap_processing/tests/hi/test_hi_l1c.py +136 -36
  101. imap_processing/tests/hi/test_l1a.py +0 -2
  102. imap_processing/tests/hi/test_science_direct_event.py +18 -14
  103. imap_processing/tests/hi/test_utils.py +16 -11
  104. imap_processing/tests/hit/helpers/__init__.py +0 -0
  105. imap_processing/tests/hit/helpers/l1_validation.py +405 -0
  106. imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
  107. imap_processing/tests/hit/test_decom_hit.py +8 -10
  108. imap_processing/tests/hit/test_hit_l1a.py +117 -180
  109. imap_processing/tests/hit/test_hit_l1b.py +149 -55
  110. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -0
  111. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +62 -0
  112. imap_processing/tests/ialirt/test_data/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  113. imap_processing/tests/ialirt/test_data/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  114. imap_processing/tests/ialirt/test_data/l0/eu_SWP_IAL_20240826_152033.csv +644 -0
  115. imap_processing/tests/ialirt/test_data/l0/hi_fsw_view_1_ccsds.bin +0 -0
  116. imap_processing/tests/ialirt/test_data/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +914 -0
  117. imap_processing/tests/ialirt/test_data/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  118. imap_processing/tests/ialirt/unit/test_process_codicehi.py +106 -0
  119. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +33 -5
  120. imap_processing/tests/ialirt/unit/test_process_swapi.py +85 -0
  121. imap_processing/tests/ialirt/unit/test_process_swe.py +106 -0
  122. imap_processing/tests/idex/conftest.py +29 -1
  123. imap_processing/tests/idex/test_data/compressed_2023_102_14_24_55.pkts +0 -0
  124. imap_processing/tests/idex/test_data/non_compressed_2023_102_14_22_26.pkts +0 -0
  125. imap_processing/tests/idex/test_idex_l0.py +6 -3
  126. imap_processing/tests/idex/test_idex_l1a.py +151 -1
  127. imap_processing/tests/idex/test_idex_l1b.py +124 -2
  128. imap_processing/tests/lo/test_lo_l1a.py +62 -2
  129. imap_processing/tests/lo/test_lo_science.py +85 -0
  130. imap_processing/tests/lo/validation_data/Instrument_FM1_T104_R129_20240803_ILO_SPIN_EU.csv +2 -0
  131. imap_processing/tests/mag/conftest.py +16 -0
  132. imap_processing/tests/mag/test_mag_decom.py +6 -4
  133. imap_processing/tests/mag/test_mag_l1a.py +36 -7
  134. imap_processing/tests/mag/test_mag_l1b.py +55 -4
  135. imap_processing/tests/mag/test_mag_validation.py +148 -0
  136. imap_processing/tests/mag/validation/L1a/T001/all_p_ones.txt +19200 -0
  137. imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-in.bin +0 -0
  138. imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-out.csv +17 -0
  139. imap_processing/tests/mag/validation/L1a/T002/all_n_ones.txt +19200 -0
  140. imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-in.bin +0 -0
  141. imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-out.csv +17 -0
  142. imap_processing/tests/mag/validation/L1a/T003/field_like.txt +19200 -0
  143. imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-in.bin +0 -0
  144. imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-out.csv +17 -0
  145. imap_processing/tests/mag/validation/L1a/T004/field_like.txt +19200 -0
  146. imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-in.bin +0 -0
  147. imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-out.csv +17 -0
  148. imap_processing/tests/mag/validation/L1a/T005/field_like_range_change.txt +19200 -0
  149. imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-in.bin +0 -0
  150. imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-out.csv +17 -0
  151. imap_processing/tests/mag/validation/L1a/T006/hdr_field.txt +19200 -0
  152. imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-in.bin +0 -0
  153. imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-out.csv +17 -0
  154. imap_processing/tests/mag/validation/L1a/T007/hdr_field_and_range_change.txt +19200 -0
  155. imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-in.bin +0 -0
  156. imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-out.csv +17 -0
  157. imap_processing/tests/mag/validation/L1a/T008/field_like_range_change.txt +19200 -0
  158. imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-in.bin +0 -0
  159. imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-out.csv +17 -0
  160. imap_processing/tests/mag/validation/L1b/T009/data.bin +0 -0
  161. imap_processing/tests/mag/validation/L1b/T009/field_like_all_ranges.txt +19200 -0
  162. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-in.csv +17 -0
  163. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +17 -0
  164. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +17 -0
  165. imap_processing/tests/mag/validation/L1b/T010/data.bin +0 -0
  166. imap_processing/tests/mag/validation/L1b/T010/field_like_all_ranges.txt +19200 -0
  167. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-in.csv +17 -0
  168. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-magi-out.csv +17 -0
  169. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-mago-out.csv +17 -0
  170. imap_processing/tests/mag/validation/L1b/T011/data.bin +0 -0
  171. imap_processing/tests/mag/validation/L1b/T011/field_like_all_ranges.txt +19200 -0
  172. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-in.csv +17 -0
  173. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +17 -0
  174. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +17 -0
  175. imap_processing/tests/spice/test_geometry.py +128 -133
  176. imap_processing/tests/spice/test_kernels.py +37 -37
  177. imap_processing/tests/spice/test_spin.py +184 -0
  178. imap_processing/tests/spice/test_time.py +43 -20
  179. imap_processing/tests/swapi/test_swapi_l1.py +11 -10
  180. imap_processing/tests/swapi/test_swapi_l2.py +13 -3
  181. imap_processing/tests/swe/test_swe_l1a.py +1 -1
  182. imap_processing/tests/swe/test_swe_l1b.py +20 -3
  183. imap_processing/tests/swe/test_swe_l1b_science.py +54 -35
  184. imap_processing/tests/swe/test_swe_l2.py +148 -5
  185. imap_processing/tests/test_cli.py +39 -7
  186. imap_processing/tests/test_quality_flags.py +19 -19
  187. imap_processing/tests/test_utils.py +3 -2
  188. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -3314
  189. imap_processing/tests/ultra/test_data/mock_data.py +161 -0
  190. imap_processing/tests/ultra/unit/conftest.py +73 -0
  191. imap_processing/tests/ultra/unit/test_badtimes.py +58 -0
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +87 -0
  193. imap_processing/tests/ultra/unit/test_de.py +61 -60
  194. imap_processing/tests/ultra/unit/test_ultra_l1a.py +3 -3
  195. imap_processing/tests/ultra/unit/test_ultra_l1b.py +51 -77
  196. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +5 -5
  197. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +114 -0
  198. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -26
  199. imap_processing/tests/ultra/unit/test_ultra_l1c.py +1 -1
  200. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +3 -3
  201. imap_processing/ultra/constants.py +11 -1
  202. imap_processing/ultra/l1a/ultra_l1a.py +2 -2
  203. imap_processing/ultra/l1b/badtimes.py +22 -5
  204. imap_processing/ultra/l1b/cullingmask.py +31 -5
  205. imap_processing/ultra/l1b/de.py +32 -37
  206. imap_processing/ultra/l1b/extendedspin.py +44 -20
  207. imap_processing/ultra/l1b/ultra_l1b.py +21 -22
  208. imap_processing/ultra/l1b/ultra_l1b_culling.py +190 -0
  209. imap_processing/ultra/l1b/ultra_l1b_extended.py +81 -30
  210. imap_processing/ultra/l1c/histogram.py +6 -2
  211. imap_processing/ultra/l1c/pset.py +6 -2
  212. imap_processing/ultra/l1c/ultra_l1c.py +2 -3
  213. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +4 -3
  214. imap_processing/ultra/utils/ultra_l1_utils.py +70 -14
  215. imap_processing/utils.py +2 -2
  216. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/METADATA +7 -2
  217. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/RECORD +235 -152
  218. imap_processing/tests/codice/data/eu_unit_lookup_table.csv +0 -101
  219. imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +0 -100
  220. imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +0 -100
  221. imap_processing/tests/codice/data/imap_codice_l0_raw_20241110_v001.pkts +0 -0
  222. imap_processing/tests/hi/test_data/l1a/imap_hi_l1a_45sensor-de_20250415_v000.cdf +0 -0
  223. imap_processing/tests/hit/test_data/sci_sample1.ccsds +0 -0
  224. imap_processing/tests/ultra/unit/test_spatial_utils.py +0 -125
  225. imap_processing/ultra/utils/spatial_utils.py +0 -221
  226. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.bin +0 -0
  227. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.csv +0 -0
  228. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_CNT.bin +0 -0
  229. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_DE.bin +0 -0
  230. /imap_processing/tests/hi/{test_data → data}/l0/H90_NHK_20241104.bin +0 -0
  231. /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_cnt_20241104.bin +0 -0
  232. /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_de_20241104.bin +0 -0
  233. /imap_processing/tests/hi/{test_data → data}/l0/README.txt +0 -0
  234. /imap_processing/tests/idex/{imap_idex_l0_raw_20231214_v001.pkts → test_data/imap_idex_l0_raw_20231214_v001.pkts} +0 -0
  235. /imap_processing/tests/idex/{impact_14_tof_high_data.txt → test_data/impact_14_tof_high_data.txt} +0 -0
  236. /imap_processing/tests/mag/{imap_mag_l1a_norm-magi_20251017_v001.cdf → validation/imap_mag_l1a_norm-magi_20251017_v001.cdf} +0 -0
  237. /imap_processing/tests/mag/{mag_l0_test_data.pkts → validation/mag_l0_test_data.pkts} +0 -0
  238. /imap_processing/tests/mag/{mag_l0_test_output.csv → validation/mag_l0_test_output.csv} +0 -0
  239. /imap_processing/tests/mag/{mag_l1_test_data.pkts → validation/mag_l1_test_data.pkts} +0 -0
  240. /imap_processing/tests/mag/{mag_l1a_test_output.csv → validation/mag_l1a_test_output.csv} +0 -0
  241. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/LICENSE +0 -0
  242. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/WHEEL +0 -0
  243. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/entry_points.txt +0 -0
@@ -1,56 +1,156 @@
1
1
  """Test coverage for imap_processing.hi.l1c.hi_l1c.py"""
2
2
 
3
+ from unittest import mock
4
+
3
5
  import numpy as np
6
+ import pandas as pd
4
7
  import pytest
8
+ import xarray as xr
5
9
 
6
- from imap_processing.cdf.utils import write_cdf
7
- from imap_processing.hi.l1a.hi_l1a import hi_l1a
8
- from imap_processing.hi.l1b.hi_l1b import hi_l1b
10
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
+ from imap_processing.cdf.utils import load_cdf, write_cdf
9
12
  from imap_processing.hi.l1c import hi_l1c
13
+ from imap_processing.hi.l1c.hi_l1c import CalibrationProductConfig
10
14
  from imap_processing.hi.utils import HIAPID
11
15
 
12
16
 
13
- @pytest.mark.skip(
14
- reason="See TODO in test comments. Need to convert this test"
15
- "to use a test L1B file rather than running L1B on fake"
16
- "data."
17
- )
18
- def test_generate_pset_dataset(create_de_data):
19
- """Test coverage for generate_pset_dataset function"""
20
- # TODO: once things are more stable, check in an L1B DE file as test data?
21
- # For now, test using false de data run through l1a and l1b processing
22
- bin_data_path = create_de_data(HIAPID.H45_SCI_DE.value)
23
- processed_data = hi_l1a(bin_data_path, "002")
24
- l1b_dataset = hi_l1b(processed_data[0], "002")
17
+ @pytest.fixture(scope="module")
18
+ def hi_test_cal_prod_config_path(hi_l1_test_data_path):
19
+ return (
20
+ hi_l1_test_data_path / "imap_his_pset-calibration-prod-config_20240101_v001.csv"
21
+ )
25
22
 
26
- l1c_dataset = hi_l1c.generate_pset_dataset(l1b_dataset)
27
23
 
28
- assert l1c_dataset.epoch.data[0] == l1b_dataset.epoch.data[0]
24
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.generate_pset_dataset")
25
+ def test_hi_l1c(mock_generate_pset_dataset, hi_test_cal_prod_config_path):
26
+ """Test coverage for hi_l1c function"""
27
+ mock_generate_pset_dataset.return_value = xr.Dataset(attrs={"Data_version": None})
28
+ pset = hi_l1c.hi_l1c(
29
+ [xr.Dataset(), hi_test_cal_prod_config_path], data_version="99"
30
+ )
31
+ assert pset.attrs["Data_version"] == "99"
29
32
 
30
33
 
31
- def test_allocate_pset_dataset():
32
- """Test coverage for allocate_pset_dataset function"""
33
- n_esa_steps = 10
34
- n_calibration_prods = 5
35
- sensor_str = HIAPID.H90_SCI_DE.sensor
36
- dataset = hi_l1c.allocate_pset_dataset(n_esa_steps, sensor_str)
34
+ def test_hi_l1c_not_implemented():
35
+ """Test coverage for hi_l1c function with unrecognized dependencies"""
36
+ with pytest.raises(NotImplementedError):
37
+ hi_l1c.hi_l1c([None, None], "0")
37
38
 
38
- assert dataset.epoch.size == 1
39
- assert dataset.spin_angle_bin.size == 3600
40
- assert dataset.esa_energy_step.size == n_esa_steps
41
- assert dataset.calibration_prod.size == n_calibration_prods
42
- np.testing.assert_array_equal(dataset.despun_z.data.shape, (1, 3))
43
- np.testing.assert_array_equal(dataset.hae_latitude.data.shape, (1, 3600))
44
- np.testing.assert_array_equal(dataset.hae_longitude.data.shape, (1, 3600))
39
+
40
+ @pytest.mark.external_kernel()
41
+ @pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
42
+ def test_generate_pset_dataset(hi_l1_test_data_path, hi_test_cal_prod_config_path):
43
+ """Test coverage for generate_pset_dataset function"""
44
+ l1b_de_path = hi_l1_test_data_path / "imap_hi_l1b_45sensor-de_20250415_v999.cdf"
45
+ l1b_dataset = load_cdf(l1b_de_path)
46
+ l1c_dataset = hi_l1c.generate_pset_dataset(
47
+ l1b_dataset, hi_test_cal_prod_config_path
48
+ )
49
+
50
+ assert l1c_dataset.epoch.data[0] == np.mean(l1b_dataset.epoch.data[[0, -1]]).astype(
51
+ np.int64
52
+ )
53
+
54
+ np.testing.assert_array_equal(l1c_dataset.despun_z.data.shape, (1, 3))
55
+ np.testing.assert_array_equal(l1c_dataset.hae_latitude.data.shape, (1, 3600))
56
+ np.testing.assert_array_equal(l1c_dataset.hae_longitude.data.shape, (1, 3600))
45
57
  for var in [
46
58
  "counts",
47
59
  "exposure_times",
48
60
  "background_rates",
49
61
  "background_rates_uncertainty",
50
62
  ]:
51
- np.testing.assert_array_equal(
52
- dataset[var].data.shape, (1, n_esa_steps, n_calibration_prods, 3600)
53
- )
54
- # Verify resulting CDF is ISTP compliant by writing to disk
55
- dataset.attrs["Data_version"] = 1
56
- write_cdf(dataset)
63
+ np.testing.assert_array_equal(l1c_dataset[var].data.shape, (1, 9, 2, 3600))
64
+
65
+ # Test ISTP compliance by writing CDF
66
+ l1c_dataset.attrs["Data_version"] = 1
67
+ write_cdf(l1c_dataset)
68
+
69
+
70
+ def test_empty_pset_dataset():
71
+ """Test coverage for empty_pset_dataset function"""
72
+ n_energy_steps = 8
73
+ l1b_esa_energy_steps = np.arange(n_energy_steps + 1).repeat(2)
74
+ n_calibration_prods = 5
75
+ sensor_str = HIAPID.H90_SCI_DE.sensor
76
+ dataset = hi_l1c.empty_pset_dataset(
77
+ l1b_esa_energy_steps, n_calibration_prods, sensor_str
78
+ )
79
+
80
+ assert dataset.epoch.size == 1
81
+ assert dataset.spin_angle_bin.size == 3600
82
+ assert dataset.esa_energy_step.size == n_energy_steps
83
+ np.testing.assert_array_equal(
84
+ dataset.esa_energy_step.data, np.arange(n_energy_steps) + 1
85
+ )
86
+ assert dataset.calibration_prod.size == n_calibration_prods
87
+
88
+ # verify that attrs defined in hi_pset_epoch have overwritten default
89
+ # epoch attributes
90
+ attr_mgr = ImapCdfAttributes()
91
+ attr_mgr.add_instrument_global_attrs("hi")
92
+ attr_mgr.add_instrument_variable_attrs(instrument="hi", level=None)
93
+ pset_epoch_attrs = attr_mgr.get_variable_attributes(
94
+ "hi_pset_epoch", check_schema=False
95
+ )
96
+ for k, v in pset_epoch_attrs.items():
97
+ assert k in dataset.epoch.attrs
98
+ assert dataset.epoch.attrs[k] == v
99
+
100
+
101
+ @pytest.mark.parametrize("sensor_str", ["90sensor", "45sensor"])
102
+ @mock.patch("imap_processing.spice.geometry.frame_transform")
103
+ @mock.patch("imap_processing.hi.l1c.hi_l1c.frame_transform")
104
+ def test_pset_geometry(mock_frame_transform, mock_geom_frame_transform, sensor_str):
105
+ """Test coverage for pset_geometry function"""
106
+ # pset_geometry uses both frame_transform and frame_transform_az_el. By mocking
107
+ # the frame_transform imported into hi_l1c as well as the geometry.frame_transform
108
+ # the underlying need for SPICE kernels is remove. Mock them both to just return
109
+ # the input position vectors.
110
+ mock_frame_transform.side_effect = lambda et, pos, from_frame, to_frame: pos
111
+ mock_geom_frame_transform.side_effect = lambda et, pos, from_frame, to_frame: pos
112
+
113
+ geometry_vars = hi_l1c.pset_geometry(0, sensor_str)
114
+
115
+ assert "despun_z" in geometry_vars
116
+ np.testing.assert_array_equal(geometry_vars["despun_z"].data, [[0, 0, 1]])
117
+
118
+ assert "hae_latitude" in geometry_vars
119
+ assert "hae_longitude" in geometry_vars
120
+ # frame_transform is mocked to return the input vectors. For Hi-90, we
121
+ # expect hae_latitude to be 0, and for Hi-45 we expect -45. Both sensors
122
+ # have an expected longitude to be 0.1 degree steps starting at 0.05
123
+ expected_latitude = 0 if sensor_str == "90sensor" else -45
124
+ np.testing.assert_array_equal(
125
+ geometry_vars["hae_latitude"].data, np.full((1, 3600), expected_latitude)
126
+ )
127
+ np.testing.assert_allclose(
128
+ geometry_vars["hae_longitude"].data,
129
+ np.arange(0.05, 360, 0.1, dtype=np.float32).reshape((1, 3600)),
130
+ atol=4e-05,
131
+ )
132
+
133
+
134
+ class TestCalibrationProductConfig:
135
+ """
136
+ All test coverage for the pd.DataFrame accessor extension "cal_prod_config".
137
+ """
138
+
139
+ def test_wrong_columns(self):
140
+ """Test coverage for a dataframe with the wrong columns."""
141
+ required_columns = CalibrationProductConfig.required_columns
142
+ for exclude_column_name in required_columns:
143
+ include_columns = set(required_columns) - {exclude_column_name}
144
+ df = pd.DataFrame({col: [1, 2, 3] for col in include_columns})
145
+ with pytest.raises(AttributeError, match="Required column*"):
146
+ _ = df.cal_prod_config.number_of_products
147
+
148
+ def test_from_csv(self, hi_test_cal_prod_config_path):
149
+ """Test coverage for read_csv function."""
150
+ df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
151
+ assert isinstance(df["coincidence_type_list"][0, 1], list)
152
+
153
+ def test_number_of_products(self, hi_test_cal_prod_config_path):
154
+ """Test coverage for number of products accessor."""
155
+ df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
156
+ assert df.cal_prod_config.number_of_products == 2
@@ -19,8 +19,6 @@ def test_sci_de_decom(hi_l0_test_data_path):
19
19
 
20
20
  # Write to CDF
21
21
  cdf_filename = "imap_hi_l1a_90sensor-de_20241105_v001.cdf"
22
- # TODO: Dropping duplicates to ignore ISTP for now. Should be fixed by #1186
23
- processed_data[0] = processed_data[0].sortby("epoch").groupby("epoch").first()
24
22
  cdf_filepath = write_cdf(processed_data[0])
25
23
  assert cdf_filepath.name == cdf_filename
26
24
 
@@ -37,22 +37,26 @@ def test_parse_direct_events():
37
37
  def test_create_dataset():
38
38
  """Test create_dataset"""
39
39
  # dummy data to test create_dataset
40
+ n_packets = 3
41
+ n_events = 4
40
42
  data_dict = {
41
- "trigger_id": [1, 2, 3],
42
- "tof_1": [512, 512, 512],
43
- "tof_2": [512, 512, 512],
44
- "tof_3": [512, 512, 512],
45
- "de_tag": [1, 2, 3],
46
- "meta_seconds": [433522962, 433522962, 433522962],
47
- "meta_subseconds": [512, 512, 512],
48
- "esa_step": [4, 4, 4],
49
- "ccsds_met": [433522961, 433522961, 433522961],
50
- "src_seq_ctr": [10, 10, 10],
51
- "pkt_len": [146, 146, 146],
52
- "last_spin_num": [4, 4, 4],
53
- "spin_invalids": [0, 0, 0],
43
+ "ccsds_met": np.arange(n_packets) + 433522961,
44
+ "src_seq_ctr": np.arange(n_packets) + 10,
45
+ "pkt_len": np.full(n_packets, 146),
46
+ "last_spin_num": np.arange(n_packets) + 3,
47
+ "spin_invalids": np.zeros(n_packets),
48
+ "esa_step": np.full(n_packets, 4),
49
+ "meta_seconds": np.arange(n_packets) + 433522960,
50
+ "meta_subseconds": np.full(n_packets, 500),
51
+ "trigger_id": [1 + i % 3 for i in range(n_events)],
52
+ "tof_1": [450] * n_events,
53
+ "tof_2": [450] * n_events,
54
+ "tof_3": [450] * n_events,
55
+ "de_tag": [i for i in range(n_events)],
56
+ "ccsds_index": [int(i / n_events * n_packets) for i in range(n_events)],
54
57
  }
55
58
 
56
59
  # Test for good data
57
60
  dataset = create_dataset(data_dict)
58
- assert dataset["epoch"].shape == (3,)
61
+ assert dataset["epoch"].shape == (n_packets,)
62
+ assert dataset["event_met"].shape == (n_events,)
@@ -44,14 +44,14 @@ def test_parse_sensor_number(test_str, expected):
44
44
 
45
45
 
46
46
  @pytest.mark.parametrize(
47
- "name, shape, expected_shape",
47
+ "name, shape, fill_value, expected_shape",
48
48
  [
49
- ("despun_z", (1, 3), (1, 3)),
50
- ("hae_latitude", None, (1, 360)),
51
- ("counts", None, (1, 10, 5, 360)),
49
+ ("despun_z", (1, 3), None, (1, 3)),
50
+ ("hae_latitude", None, 0, (1, 360)),
51
+ ("counts", None, None, (1, 10, 5, 360)),
52
52
  ],
53
53
  )
54
- def test_full_dataarray(name, shape, expected_shape):
54
+ def test_full_dataarray(name, shape, fill_value, expected_shape):
55
55
  """Test coverage for full_dataarray function"""
56
56
  coords = {
57
57
  "epoch": xr.DataArray(np.array([0])),
@@ -61,25 +61,28 @@ def test_full_dataarray(name, shape, expected_shape):
61
61
  }
62
62
  cdf_manager = ImapCdfAttributes()
63
63
  cdf_manager.add_instrument_variable_attrs(instrument="hi", level=None)
64
+ attrs = cdf_manager.get_variable_attributes(f"hi_pset_{name}")
64
65
 
65
66
  dataarray = full_dataarray(
66
- name, cdf_manager.get_variable_attributes(f"hi_pset_{name}"), coords, shape
67
+ name, attrs, coords=coords, shape=shape, fill_value=fill_value
67
68
  )
68
69
  assert dataarray.data.shape == expected_shape
70
+ expected_fill_value = fill_value if fill_value is not None else attrs["FILLVAL"]
71
+ np.testing.assert_array_equal(dataarray.data, expected_fill_value)
69
72
 
70
73
 
71
74
  @pytest.mark.parametrize(
72
- "var_names, shape, lookup_str",
75
+ "var_names, shape, fill_value, lookup_str",
73
76
  [
74
- (["delta_t_ab", "delta_t_ac1"], 5, "hi_de_{0}"),
75
- (["hae_latitude"], (3, 5), "hi_pset_{0}"),
77
+ (["delta_t_ab", "delta_t_ac1"], 5, None, "hi_de_{0}"),
78
+ (["hae_latitude"], (3, 5), 0, "hi_pset_{0}"),
76
79
  ],
77
80
  )
78
- def test_create_dataset_variables(var_names, shape, lookup_str):
81
+ def test_create_dataset_variables(var_names, shape, fill_value, lookup_str):
79
82
  """Test coverage for `imap_processing.hi.utils.create_dataset_variables`"""
80
83
  var_names = ["delta_t_ab", "delta_t_ac1", "delta_t_bc1"]
81
84
  l1b_de_vars = create_dataset_variables(
82
- var_names, shape, att_manager_lookup_str="hi_de_{0}"
85
+ var_names, shape, fill_value=fill_value, att_manager_lookup_str="hi_de_{0}"
83
86
  )
84
87
  assert len(l1b_de_vars) == len(var_names)
85
88
  attr_mgr = ImapCdfAttributes()
@@ -95,3 +98,5 @@ def test_create_dataset_variables(var_names, shape, lookup_str):
95
98
  assert data_array.size == shape
96
99
  else:
97
100
  assert data_array.shape == shape
101
+ expected_fill_value = fill_value if fill_value is not None else attrs["FILLVAL"]
102
+ np.testing.assert_array_equal(data_array, expected_fill_value)
File without changes