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

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

Potentially problematic release.


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

Files changed (415) hide show
  1. imap_processing/__init__.py +11 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +66 -18
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +24 -40
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +934 -42
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  9. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  10. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  11. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -14
  12. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  13. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  14. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  15. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +25 -9
  16. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  17. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  18. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  19. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  20. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +23 -20
  21. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  22. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  23. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  24. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  25. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  26. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  27. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  28. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  29. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  30. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +64 -52
  31. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  32. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +180 -19
  33. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  34. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +80 -17
  35. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +32 -57
  36. imap_processing/cdf/utils.py +52 -38
  37. imap_processing/cli.py +477 -233
  38. imap_processing/codice/codice_l1a.py +466 -131
  39. imap_processing/codice/codice_l1b.py +51 -152
  40. imap_processing/codice/constants.py +1360 -569
  41. imap_processing/codice/decompress.py +2 -6
  42. imap_processing/ena_maps/ena_maps.py +1103 -146
  43. imap_processing/ena_maps/utils/coordinates.py +19 -0
  44. imap_processing/ena_maps/utils/map_utils.py +14 -17
  45. imap_processing/ena_maps/utils/spatial_utils.py +55 -52
  46. imap_processing/glows/l1a/glows_l1a.py +28 -99
  47. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  48. imap_processing/glows/l1b/glows_l1b.py +1 -4
  49. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  50. imap_processing/glows/l2/glows_l2.py +2 -5
  51. imap_processing/hi/l1a/hi_l1a.py +54 -29
  52. imap_processing/hi/l1a/histogram.py +0 -1
  53. imap_processing/hi/l1a/science_direct_event.py +6 -8
  54. imap_processing/hi/l1b/hi_l1b.py +111 -82
  55. imap_processing/hi/l1c/hi_l1c.py +416 -32
  56. imap_processing/hi/utils.py +58 -12
  57. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  58. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  59. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  60. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  61. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  62. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  63. imap_processing/hit/hit_utils.py +235 -5
  64. imap_processing/hit/l0/constants.py +20 -11
  65. imap_processing/hit/l0/decom_hit.py +21 -5
  66. imap_processing/hit/l1a/hit_l1a.py +71 -75
  67. imap_processing/hit/l1b/constants.py +321 -0
  68. imap_processing/hit/l1b/hit_l1b.py +377 -67
  69. imap_processing/hit/l2/constants.py +318 -0
  70. imap_processing/hit/l2/hit_l2.py +723 -0
  71. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  72. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  73. imap_processing/ialirt/l0/parse_mag.py +374 -0
  74. imap_processing/ialirt/l0/process_swapi.py +69 -0
  75. imap_processing/ialirt/l0/process_swe.py +548 -0
  76. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -208
  77. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  78. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  79. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  80. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  81. imap_processing/ialirt/utils/grouping.py +114 -0
  82. imap_processing/ialirt/utils/time.py +29 -0
  83. imap_processing/idex/atomic_masses.csv +22 -0
  84. imap_processing/idex/decode.py +2 -2
  85. imap_processing/idex/idex_constants.py +33 -0
  86. imap_processing/idex/idex_l0.py +22 -8
  87. imap_processing/idex/idex_l1a.py +81 -51
  88. imap_processing/idex/idex_l1b.py +13 -39
  89. imap_processing/idex/idex_l2a.py +823 -0
  90. imap_processing/idex/idex_l2b.py +120 -0
  91. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +11 -11
  92. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  93. imap_processing/lo/l0/lo_science.py +7 -2
  94. imap_processing/lo/l1a/lo_l1a.py +1 -5
  95. imap_processing/lo/l1b/lo_l1b.py +702 -29
  96. imap_processing/lo/l1b/tof_conversions.py +11 -0
  97. imap_processing/lo/l1c/lo_l1c.py +1 -4
  98. imap_processing/mag/constants.py +51 -0
  99. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  100. imap_processing/mag/l0/decom_mag.py +10 -3
  101. imap_processing/mag/l1a/mag_l1a.py +23 -19
  102. imap_processing/mag/l1a/mag_l1a_data.py +35 -10
  103. imap_processing/mag/l1b/mag_l1b.py +259 -50
  104. imap_processing/mag/l1c/interpolation_methods.py +388 -0
  105. imap_processing/mag/l1c/mag_l1c.py +621 -17
  106. imap_processing/mag/l2/mag_l2.py +140 -0
  107. imap_processing/mag/l2/mag_l2_data.py +288 -0
  108. imap_processing/quality_flags.py +1 -0
  109. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  110. imap_processing/spacecraft/quaternions.py +121 -0
  111. imap_processing/spice/geometry.py +19 -22
  112. imap_processing/spice/kernels.py +0 -276
  113. imap_processing/spice/pointing_frame.py +257 -0
  114. imap_processing/spice/repoint.py +149 -0
  115. imap_processing/spice/spin.py +38 -33
  116. imap_processing/spice/time.py +24 -0
  117. imap_processing/swapi/l1/swapi_l1.py +20 -12
  118. imap_processing/swapi/l2/swapi_l2.py +116 -5
  119. imap_processing/swapi/swapi_utils.py +32 -0
  120. imap_processing/swe/l1a/swe_l1a.py +44 -12
  121. imap_processing/swe/l1a/swe_science.py +13 -13
  122. imap_processing/swe/l1b/swe_l1b.py +898 -23
  123. imap_processing/swe/l2/swe_l2.py +75 -136
  124. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  125. imap_processing/swe/utils/swe_constants.py +64 -0
  126. imap_processing/swe/utils/swe_utils.py +85 -28
  127. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  128. imap_processing/tests/ccsds/test_excel_to_xtce.py +24 -21
  129. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  130. imap_processing/tests/cdf/test_utils.py +14 -16
  131. imap_processing/tests/codice/conftest.py +44 -33
  132. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  133. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  134. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  135. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  136. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  137. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  138. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  139. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  140. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  141. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  142. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  143. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  144. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  145. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  146. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  147. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  148. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  149. imap_processing/tests/codice/test_codice_l1a.py +126 -53
  150. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  151. imap_processing/tests/codice/test_decompress.py +4 -4
  152. imap_processing/tests/conftest.py +239 -27
  153. imap_processing/tests/ena_maps/conftest.py +51 -0
  154. imap_processing/tests/ena_maps/test_ena_maps.py +1068 -110
  155. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  156. imap_processing/tests/ena_maps/test_spatial_utils.py +17 -21
  157. imap_processing/tests/glows/conftest.py +10 -14
  158. imap_processing/tests/glows/test_glows_decom.py +4 -4
  159. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  160. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  161. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  162. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  163. imap_processing/tests/glows/test_glows_l2.py +2 -8
  164. imap_processing/tests/hi/conftest.py +1 -1
  165. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  166. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  167. imap_processing/tests/hi/test_hi_l1b.py +22 -27
  168. imap_processing/tests/hi/test_hi_l1c.py +249 -18
  169. imap_processing/tests/hi/test_l1a.py +35 -7
  170. imap_processing/tests/hi/test_science_direct_event.py +3 -3
  171. imap_processing/tests/hi/test_utils.py +24 -2
  172. imap_processing/tests/hit/helpers/l1_validation.py +74 -73
  173. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  174. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  175. imap_processing/tests/hit/test_decom_hit.py +5 -1
  176. imap_processing/tests/hit/test_hit_l1a.py +32 -36
  177. imap_processing/tests/hit/test_hit_l1b.py +300 -81
  178. imap_processing/tests/hit/test_hit_l2.py +716 -0
  179. imap_processing/tests/hit/test_hit_utils.py +184 -7
  180. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  181. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  182. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  183. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  184. imap_processing/tests/ialirt/data/l0/461971383-404.bin +0 -0
  185. imap_processing/tests/ialirt/data/l0/461971384-405.bin +0 -0
  186. imap_processing/tests/ialirt/data/l0/461971385-406.bin +0 -0
  187. imap_processing/tests/ialirt/data/l0/461971386-407.bin +0 -0
  188. imap_processing/tests/ialirt/data/l0/461971387-408.bin +0 -0
  189. imap_processing/tests/ialirt/data/l0/461971388-409.bin +0 -0
  190. imap_processing/tests/ialirt/data/l0/461971389-410.bin +0 -0
  191. imap_processing/tests/ialirt/data/l0/461971390-411.bin +0 -0
  192. imap_processing/tests/ialirt/data/l0/461971391-412.bin +0 -0
  193. imap_processing/tests/ialirt/data/l0/sample_decoded_i-alirt_data.csv +383 -0
  194. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  195. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  196. imap_processing/tests/ialirt/unit/test_parse_mag.py +223 -0
  197. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  198. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  199. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  200. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  201. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  202. imap_processing/tests/ialirt/unit/test_process_swe.py +319 -6
  203. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  204. imap_processing/tests/idex/conftest.py +127 -6
  205. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  206. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  207. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  208. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  209. imap_processing/tests/idex/test_idex_l0.py +33 -11
  210. imap_processing/tests/idex/test_idex_l1a.py +92 -21
  211. imap_processing/tests/idex/test_idex_l1b.py +106 -27
  212. imap_processing/tests/idex/test_idex_l2a.py +399 -0
  213. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  214. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  215. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  216. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  217. imap_processing/tests/lo/test_lo_l1b.py +515 -6
  218. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  219. imap_processing/tests/lo/test_lo_science.py +7 -7
  220. imap_processing/tests/lo/test_star_sensor.py +1 -1
  221. imap_processing/tests/mag/conftest.py +120 -2
  222. imap_processing/tests/mag/test_mag_decom.py +5 -4
  223. imap_processing/tests/mag/test_mag_l1a.py +51 -7
  224. imap_processing/tests/mag/test_mag_l1b.py +40 -59
  225. imap_processing/tests/mag/test_mag_l1c.py +354 -19
  226. imap_processing/tests/mag/test_mag_l2.py +130 -0
  227. imap_processing/tests/mag/test_mag_validation.py +247 -26
  228. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  229. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  230. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  231. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  232. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  233. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  234. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  235. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  236. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  237. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  238. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  239. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  240. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  241. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  242. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  243. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  244. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  245. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  246. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  247. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  248. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  249. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  250. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  251. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  252. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  253. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  254. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  255. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  256. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  257. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  258. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  259. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  260. imap_processing/tests/mag/validation/calibration/imap_mag_l1b-calibration_20240229_v001.cdf +0 -0
  261. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  262. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  263. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  264. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  265. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  266. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  267. imap_processing/tests/spice/test_geometry.py +9 -12
  268. imap_processing/tests/spice/test_kernels.py +1 -200
  269. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  270. imap_processing/tests/spice/test_repoint.py +121 -0
  271. imap_processing/tests/spice/test_spin.py +50 -9
  272. imap_processing/tests/spice/test_time.py +14 -0
  273. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  274. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  275. imap_processing/tests/swapi/test_swapi_l1.py +13 -11
  276. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  277. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  278. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  279. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  280. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  281. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  282. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  283. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  284. imap_processing/tests/swe/test_swe_l1a.py +20 -2
  285. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  286. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  287. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  288. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  289. imap_processing/tests/swe/test_swe_l2.py +153 -91
  290. imap_processing/tests/test_cli.py +171 -88
  291. imap_processing/tests/test_utils.py +140 -17
  292. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  293. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  294. 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
  295. imap_processing/tests/ultra/data/mock_data.py +369 -0
  296. imap_processing/tests/ultra/unit/conftest.py +115 -89
  297. imap_processing/tests/ultra/unit/test_badtimes.py +4 -4
  298. imap_processing/tests/ultra/unit/test_cullingmask.py +8 -6
  299. imap_processing/tests/ultra/unit/test_de.py +14 -13
  300. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  301. imap_processing/tests/ultra/unit/test_decom_apid_881.py +54 -11
  302. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  303. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  304. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  305. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +77 -0
  306. imap_processing/tests/ultra/unit/test_ultra_l1a.py +98 -305
  307. imap_processing/tests/ultra/unit/test_ultra_l1b.py +60 -14
  308. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  309. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +26 -27
  310. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +239 -70
  311. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  312. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +114 -83
  313. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  314. imap_processing/ultra/constants.py +1 -1
  315. imap_processing/ultra/l0/decom_tools.py +27 -39
  316. imap_processing/ultra/l0/decom_ultra.py +168 -204
  317. imap_processing/ultra/l0/ultra_utils.py +152 -136
  318. imap_processing/ultra/l1a/ultra_l1a.py +55 -271
  319. imap_processing/ultra/l1b/badtimes.py +1 -4
  320. imap_processing/ultra/l1b/cullingmask.py +2 -6
  321. imap_processing/ultra/l1b/de.py +116 -57
  322. imap_processing/ultra/l1b/extendedspin.py +20 -18
  323. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  324. imap_processing/ultra/l1b/ultra_l1b.py +36 -16
  325. imap_processing/ultra/l1b/ultra_l1b_culling.py +66 -30
  326. imap_processing/ultra/l1b/ultra_l1b_extended.py +297 -94
  327. imap_processing/ultra/l1c/histogram.py +2 -6
  328. imap_processing/ultra/l1c/spacecraft_pset.py +84 -0
  329. imap_processing/ultra/l1c/ultra_l1c.py +8 -9
  330. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +206 -108
  331. imap_processing/ultra/l2/ultra_l2.py +299 -0
  332. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  333. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  334. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  335. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  336. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  337. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  338. imap_processing/ultra/packet_definitions/README.md +38 -0
  339. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  340. imap_processing/ultra/utils/ultra_l1_utils.py +31 -12
  341. imap_processing/utils.py +69 -29
  342. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +10 -6
  343. imap_processing-0.13.0.dist-info/RECORD +578 -0
  344. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  345. imap_processing/hi/l1a/housekeeping.py +0 -27
  346. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  347. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  348. imap_processing/swe/l1b/swe_l1b_science.py +0 -652
  349. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  350. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  351. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  352. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  353. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  354. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  355. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  356. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  357. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  358. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  359. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  360. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  361. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  362. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  363. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  364. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  365. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  366. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  367. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  368. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  369. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  370. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  371. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  372. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  373. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  374. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  375. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  376. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  377. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  378. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  379. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  380. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  381. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  382. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  383. imap_processing/tests/swe/test_swe_l1b_science.py +0 -84
  384. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  385. imap_processing/ultra/l1c/pset.py +0 -40
  386. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  387. imap_processing-0.11.0.dist-info/RECORD +0 -488
  388. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  389. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  390. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  391. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  392. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  393. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  394. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  395. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  396. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  397. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  398. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  399. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  400. /imap_processing/{mag/l1b → tests/spacecraft}/__init__.py +0 -0
  401. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  402. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  403. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  404. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  405. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  406. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  407. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  408. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  409. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  410. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  411. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  412. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  413. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  414. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  415. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -1,652 +0,0 @@
1
- """Contains code to perform SWE L1b science processing."""
2
-
3
- import logging
4
-
5
- import numpy as np
6
- import numpy.typing as npt
7
- import pandas as pd
8
- import xarray as xr
9
-
10
- from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
- from imap_processing.swe.utils.swe_utils import (
12
- ESA_VOLTAGE_ROW_INDEX_DICT,
13
- read_lookup_table,
14
- )
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- def get_esa_dataframe(esa_table_number: int) -> pd.DataFrame:
20
- """
21
- Read lookup table from file.
22
-
23
- Parameters
24
- ----------
25
- esa_table_number : int
26
- ESA table index number.
27
-
28
- Returns
29
- -------
30
- esa_steps : pandas.DataFrame
31
- ESA table_number and its associated values.
32
- """
33
- if esa_table_number not in [0, 1]:
34
- raise ValueError(f"Unknown ESA table number {esa_table_number}")
35
-
36
- # Get the lookup table DataFrame
37
- lookup_table = read_lookup_table()
38
-
39
- esa_steps = lookup_table.loc[lookup_table["table_index"] == esa_table_number]
40
- return esa_steps
41
-
42
-
43
- def deadtime_correction(counts: np.ndarray, acq_duration: int) -> npt.NDArray:
44
- """
45
- Calculate deadtime correction.
46
-
47
- Deadtime correction is a technique used in various fields, including
48
- nuclear physics, radiation detection, and particle counting, to compensate
49
- for the effects of the time period during which a detector is not able to
50
- record new events or measurements after detecting a previous event.
51
- This "deadtime" is essentially the time during which the detector is
52
- recovering from the previous detection and is unable to detect new events.
53
-
54
- In particle detectors, there is a finite time required for the detector to
55
- reset or recover after detecting a particle. During this deadtime, any
56
- subsequent particles that may have arrived go undetected. As a result,
57
- the recorded count rate appears to be lower than the actual count rate.
58
-
59
- Deadtime correction involves mathematically adjusting the measured count
60
- rates to compensate for this deadtime effect. This correction is crucial
61
- when dealing with high-intensity sources or particle fluxes, as the deadtime
62
- can significantly affect the accuracy of the measurements.
63
-
64
- Deadtime correction is important to ensure accurate measurements and data
65
- analysis in fields where event detection rates are high and where every
66
- detected event is critical for understanding physical processes.
67
-
68
- Parameters
69
- ----------
70
- counts : numpy.ndarray
71
- Counts data before deadtime corrections.
72
- acq_duration : int
73
- This is ACQ_DURATION from science packet. acq_duration is in microseconds.
74
-
75
- Returns
76
- -------
77
- corrected_count : numpy.ndarray
78
- Corrected counts.
79
- """
80
- # deadtime is 360 ns
81
- deadtime = 360e-9
82
- correct = 1.0 - (deadtime * (counts / (acq_duration * 1e-6)))
83
- correct = np.maximum(0.1, correct)
84
- corrected_count = np.divide(counts, correct)
85
- return corrected_count.astype(np.float64)
86
-
87
-
88
- def convert_counts_to_rate(data: np.ndarray, acq_duration: np.ndarray) -> npt.NDArray:
89
- """
90
- Convert counts to rate using sampling time.
91
-
92
- acq_duration is ACQ_DURATION from science packet.
93
-
94
- Parameters
95
- ----------
96
- data : numpy.ndarray
97
- Counts data.
98
- acq_duration : numpy.ndarray
99
- Acquisition duration. acq_duration is in microseconds.
100
-
101
- Returns
102
- -------
103
- numpy.ndarray
104
- Count rates array in seconds.
105
- """
106
- # convert microseconds to seconds
107
- acq_duration_sec = acq_duration * 1e-6
108
- count_rate = data / acq_duration_sec
109
- return count_rate.astype(np.float64)
110
-
111
-
112
- def read_in_flight_cal_data() -> pd.DataFrame:
113
- """
114
- Read in-flight calibration data.
115
-
116
- In-flight calibration data file will contain rows where each line
117
- has 8 numbers, with the first being a time stamp in MET, and the next
118
- 7 being the factors for the 7 detectors.
119
-
120
- This file will be updated weekly with new calibration data. In other
121
- words, one line of data will be added each week to the existing file.
122
- File will be in CSV format. Processing won't be kicked off until there
123
- is in-flight calibration data that covers science data.
124
-
125
- TODO: decide filename convention given this information. This function
126
- is a placeholder for reading in the calibration data until we decide on
127
- how to read calibration data through dependencies list.
128
-
129
- Returns
130
- -------
131
- in_flight_cal_df : pandas.DataFrame
132
- DataFrame with in-flight calibration data.
133
- """
134
- # TODO: Read in in-flight calibration file.
135
-
136
- # Define the column headers
137
- columns = ["met_time", "cem1", "cem2", "cem3", "cem4", "cem5", "cem6", "cem7"]
138
-
139
- # Create an empty DataFrame with the specified columns
140
- empty_df = pd.DataFrame(columns=columns)
141
- return empty_df
142
-
143
-
144
- def calculate_calibration_factor(
145
- acquisition_times: np.ndarray, cal_times: np.ndarray, cal_data: np.ndarray
146
- ) -> npt.NDArray:
147
- """
148
- Calculate calibration factor using linear interpolation.
149
-
150
- Steps to calculate calibration factor:
151
- 1. Convert input time to match time format in the calibration data file.
152
- Both times should be in S/C MET time.
153
- 2. Find the nearest in time calibration data point.
154
- 3. Linear interpolate between those two nearest time and get factor for
155
- input time.
156
-
157
- Parameters
158
- ----------
159
- acquisition_times : numpy.ndarray
160
- Data points to interpolate. Shape is (24, 30).
161
- cal_times : numpy.ndarray
162
- X-coordinates data points. Calibration times. Shape is (n,).
163
- cal_data : numpy.ndarray
164
- Y-coordinates data points. Calibration data of corresponding cal_times.
165
- Shape is (n, 7).
166
-
167
- Returns
168
- -------
169
- calibration_factor : numpy.ndarray
170
- Calibration factor for each CEM detector. Shape is (24, 30, 7)
171
- where last 7 dimension contains calibration factor for each CEM detector.
172
- """
173
- # Raise error if there is no pre or post time in cal_times. SWE does not
174
- # want to extrapolate calibration data.
175
- if (
176
- acquisition_times.min() < cal_times.min()
177
- or acquisition_times.max() > cal_times.max()
178
- ):
179
- error_msg = (
180
- f"Acquisition min/max times: {acquisition_times.min()} to "
181
- f"{acquisition_times.max()}. "
182
- f"Calibration min/max times: {cal_times.min()} to {cal_times.max()}. "
183
- "Acquisition times should be within calibration time range."
184
- )
185
- raise ValueError(error_msg)
186
-
187
- # This line of code finds the indices of acquisition_times in cal_times where
188
- # acquisition_times should be inserted to maintain order. As a result, it finds
189
- # its nearest pre and post time from cal_times.
190
- input_time_indices = np.searchsorted(cal_times, acquisition_times)
191
-
192
- # Assign to a variable for better readability
193
- x = acquisition_times
194
- xp = cal_times
195
- fp = cal_data
196
-
197
- # Given this situation which will be the case for SWE data
198
- # where data will fall in between two calibration times and
199
- # not be exactly equal to any calibration time,
200
- # >>> a = [1, 2, 3]
201
- # >>> np.searchsorted(a, [2.5])
202
- # array([2])
203
- # we need to use (j - 1) to get pre time indices. (j-1) is
204
- # pre time indices and j is post time indices.
205
- j = input_time_indices
206
- w = (x - xp[j - 1]) / (xp[j] - xp[j - 1])
207
- return fp[j - 1] + w[..., None] * (fp[j] - fp[j - 1])
208
-
209
-
210
- def apply_in_flight_calibration(
211
- corrected_counts: np.ndarray, acquisition_time: np.ndarray
212
- ) -> npt.NDArray:
213
- """
214
- Apply in flight calibration to full cycle data.
215
-
216
- These factors are used to account for changes in gain with time.
217
-
218
- They are derived from the weekly electron calibration data.
219
-
220
- Parameters
221
- ----------
222
- corrected_counts : numpy.ndarray
223
- Corrected count of full cycle data. Data shape is (24, 30, 7).
224
- acquisition_time : numpy.ndarray
225
- Acquisition time of full cycle data. Data shape is (24, 30).
226
-
227
- Returns
228
- -------
229
- corrected_counts : numpy.ndarray
230
- Corrected count of full cycle data after applying in-flight calibration.
231
- Array shape is (24, 30, 7).
232
- """
233
- # Read in in-flight calibration data
234
- in_flight_cal_df = read_in_flight_cal_data()
235
- # calculate calibration factor.
236
- # return shape of calculate_calibration_factor is (24, 30, 7) where
237
- # last 7 dimension contains calibration factor for each CEM detector.
238
- cal_factor = calculate_calibration_factor(
239
- acquisition_time,
240
- in_flight_cal_df["met_time"].values,
241
- in_flight_cal_df.iloc[:, 1:].values,
242
- )
243
- # Apply to full cycle data
244
- return corrected_counts.astype(np.float64) * cal_factor
245
-
246
-
247
- def populate_full_cycle_data(
248
- l1a_data: xr.Dataset, packet_index: int, esa_table_num: int
249
- ) -> npt.NDArray:
250
- """
251
- Populate full cycle data array using esa lookup table and l1a_data.
252
-
253
- Parameters
254
- ----------
255
- l1a_data : xarray.Dataset
256
- L1a data with full cycle data only.
257
- packet_index : int
258
- Index of current packet in the whole packet list.
259
- esa_table_num : int
260
- ESA lookup table number.
261
-
262
- Returns
263
- -------
264
- full_cycle_ds : xarray.Dataset
265
- Full cycle data and its acquisition times.
266
- """
267
- esa_lookup_table = get_esa_dataframe(esa_table_num)
268
-
269
- # If esa lookup table number is 0, then populate using esa lookup table data
270
- # with information that esa step ramps up in even column and ramps down
271
- # in odd column every six steps.
272
- if esa_table_num == 0:
273
- energy_steps = 24
274
- angle = 30
275
- cem_detectors = 7
276
- # create new full cycle data array
277
- full_cycle_data = np.zeros((energy_steps, angle, cem_detectors))
278
- # SWE needs to store acquisition time of each count data point
279
- # to use in level 2 processing to calculate
280
- # spin phase. This is done below by using information from
281
- # science packet.
282
- acquisition_times = np.zeros((energy_steps, angle))
283
-
284
- # Store acquisition duration for later calculation in this function
285
- acq_duration_arr = np.zeros((energy_steps, angle))
286
-
287
- # Initialize esa_step_number and column_index.
288
- # esa_step_number goes from 0 to 719 range where
289
- # 720 came from 24 x 30. full_cycle_data array has (24, 30)
290
- # dimension.
291
- esa_step_number = 0
292
- # column_index goes from 0 to 29 range where
293
- # 30 came from 30 column in full_cycle_data array
294
- column_index = -1
295
-
296
- # Go through four quarter cycle data packets
297
- for index in range(4):
298
- decompressed_counts = l1a_data["science_data"].data[packet_index + index]
299
- # Do deadtime correction
300
- acq_duration = l1a_data["acq_duration"].data[packet_index + index]
301
- settle_duration = l1a_data["settle_duration"].data[packet_index + index]
302
- corrected_counts = deadtime_correction(decompressed_counts, acq_duration)
303
-
304
- # Each quarter cycle data should have same acquisition start time coarse
305
- # and fine value. We will use that as base time to calculate each
306
- # acquisition time for each count data.
307
- # base_quarter_cycle_acq_time = acq_start_coarse +
308
- # acq_start_fine / 1000000
309
- base_quarter_cycle_acq_time = (
310
- l1a_data["acq_start_coarse"].data[packet_index + index]
311
- + l1a_data["acq_start_fine"].data[packet_index + index] / 1000000
312
- )
313
-
314
- # Go through each quarter cycle's 180 ESA measurements
315
- # and put counts rate in full cycle data array
316
- for step in range(180):
317
- # Get esa voltage value from esa lookup table and
318
- # use that to get row index in full data array
319
- esa_voltage_value = esa_lookup_table.loc[esa_step_number]["esa_v"]
320
- esa_voltage_row_index = ESA_VOLTAGE_ROW_INDEX_DICT[esa_voltage_value]
321
-
322
- # every six steps, increment column index
323
- if esa_step_number % 6 == 0:
324
- column_index += 1
325
- # Put counts rate in full cycle data array
326
- full_cycle_data[esa_voltage_row_index][column_index] = corrected_counts[
327
- step
328
- ]
329
- # Acquisition time (in seconds) of each count data point will be
330
- # using this formula:
331
- # each_count_acq_time = base_quarter_cycle_acq_time +
332
- # (step * ( acq_duration + settle_duration) / 1000000 )
333
- # where step goes from 0 to 179, acq_start_coarse is in seconds and
334
- # acq_start_fine is in microseconds and acq_duration is in microseconds.
335
- acquisition_times[esa_voltage_row_index][column_index] = (
336
- base_quarter_cycle_acq_time
337
- + (step * (acq_duration + settle_duration) / 1000000)
338
- )
339
- # Store acquisition duration for later calculation
340
- acq_duration_arr[esa_voltage_row_index][column_index] = acq_duration
341
- esa_step_number += 1
342
-
343
- # reset column index for next quarter cycle
344
- column_index = -1
345
- # TODO: Apply in flight calibration to full cycle data
346
-
347
- # NOTE: We may get more lookup table with different setup when we get real
348
- # data. But for now, we are advice to continue with current setup and can
349
- # add/change it when we get real data.
350
-
351
- # Apply calibration based on in-flight calibration.
352
- calibrated_counts = apply_in_flight_calibration(full_cycle_data, acquisition_times)
353
-
354
- # Convert counts to rate
355
- counts_rate = convert_counts_to_rate(calibrated_counts, acq_duration)
356
-
357
- # Store count data and acquisition times of full cycle data in xr.Dataset
358
- full_cycle_ds = xr.Dataset(
359
- {
360
- "full_cycle_data": (["esa_step", "spin_sector", "cem_id"], counts_rate),
361
- "acquisition_time": (["esa_step", "spin_sector"], acquisition_times),
362
- }
363
- )
364
-
365
- return full_cycle_ds
366
-
367
-
368
- def find_cycle_starts(cycles: np.ndarray) -> npt.NDArray:
369
- """
370
- Find index of where new cycle started.
371
-
372
- Brandon Stone helped developed this algorithm.
373
-
374
- Parameters
375
- ----------
376
- cycles : numpy.ndarray
377
- Array that contains quarter cycle information.
378
-
379
- Returns
380
- -------
381
- first_quarter_indices : numpy.ndarray
382
- Array of indices of start cycle.
383
- """
384
- if cycles.size < 4:
385
- return np.array([], np.int64)
386
-
387
- # calculate difference between consecutive cycles
388
- diff = cycles[1:] - cycles[:-1]
389
-
390
- # This uses sliding window to find index where cycle starts.
391
- # This is what this below code line is doing:
392
- # [1 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0] # Is cycle zero?
393
- # [1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1] # Next diff is one?
394
- # [1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0] # Next diff is one?
395
- # [0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0] # Next diff is one?
396
- #
397
- # [0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0] # And all?
398
- ione = diff == 1
399
- valid = (cycles == 0)[:-3] & ione[:-2] & ione[1:-1] & ione[2:]
400
- first_quarter_indices = np.where(valid)[0]
401
- return first_quarter_indices
402
-
403
-
404
- def get_indices_of_full_cycles(quarter_cycle: np.ndarray) -> npt.NDArray:
405
- """
406
- Get indices of full cycles.
407
-
408
- Parameters
409
- ----------
410
- quarter_cycle : numpy.ndarray
411
- Array that contains quarter cycles information.
412
-
413
- Returns
414
- -------
415
- full_cycles_indices : numpy.ndarray
416
- 1D array with indices of full cycle data.
417
- """
418
- indices_of_start = find_cycle_starts(quarter_cycle)
419
- # indices_of_start[..., None] creates array of shape(n, 1).
420
- # Eg. [[3], [8]]
421
- # np.arange(4)[None, ...] creates array of shape(1, 4)
422
- # Eg. [[0, 1, 2, 3]]
423
- # then we add both of them together to get an array of shape(n, 4)
424
- # Eg. [[3, 4, 5, 6], [8, 9, 10, 11]]
425
- full_cycles_indices = indices_of_start[..., None] + np.arange(4)[None, ...]
426
- return full_cycles_indices.reshape(-1)
427
-
428
-
429
- def filter_full_cycle_data(
430
- full_cycle_data_indices: np.ndarray, l1a_data: xr.Dataset
431
- ) -> xr.Dataset:
432
- """
433
- Filter metadata and science of packets that makes full cycles.
434
-
435
- Parameters
436
- ----------
437
- full_cycle_data_indices : numpy.ndarray
438
- Array with indices of full cycles.
439
- l1a_data : xarray.Dataset
440
- L1A dataset.
441
-
442
- Returns
443
- -------
444
- l1a_data : xarray.Dataset
445
- L1A dataset with filtered metadata.
446
- """
447
- for key, value in l1a_data.items():
448
- l1a_data[key] = value.data[full_cycle_data_indices]
449
- return l1a_data
450
-
451
-
452
- def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
453
- """
454
- SWE l1b science processing.
455
-
456
- Parameters
457
- ----------
458
- l1a_data : xarray.Dataset
459
- Input data.
460
- data_version : str
461
- Version of the data product being created.
462
-
463
- Returns
464
- -------
465
- dataset : xarray.Dataset
466
- Processed l1b data.
467
- """
468
- total_packets = len(l1a_data["science_data"].data)
469
-
470
- # Array to store list of table populated with data
471
- # of full cycles
472
- full_cycle_science_data = []
473
- full_cycle_acq_times = []
474
- packet_index = 0
475
- l1a_data_copy = l1a_data.copy(deep=True)
476
-
477
- full_cycle_data_indices = get_indices_of_full_cycles(l1a_data["quarter_cycle"].data)
478
- logger.debug(
479
- f"Quarter cycle data before filtering: {l1a_data_copy['quarter_cycle'].data}"
480
- )
481
-
482
- # Delete Raw Science Data from l1b and onwards
483
- del l1a_data_copy["raw_science_data"]
484
-
485
- if full_cycle_data_indices.size == 0:
486
- # Log that no data is found for science data
487
- return None
488
-
489
- if len(full_cycle_data_indices) != total_packets:
490
- # Filter metadata and science data of packets that makes full cycles
491
- full_cycle_l1a_data = l1a_data_copy.isel({"epoch": full_cycle_data_indices})
492
-
493
- # Update total packets
494
- total_packets = len(full_cycle_data_indices)
495
- logger.debug(
496
- "Quarters cycle after filtering: "
497
- f"{full_cycle_l1a_data['quarter_cycle'].data}"
498
- )
499
- if len(full_cycle_data_indices) != len(
500
- full_cycle_l1a_data["quarter_cycle"].data
501
- ):
502
- raise ValueError(
503
- "Error: full cycle data indices and filtered quarter cycle data size "
504
- "mismatch"
505
- )
506
-
507
- # Go through each cycle and populate full cycle data
508
- for packet_index in range(0, total_packets, 4):
509
- # get ESA lookup table information
510
- esa_table_num = l1a_data["esa_table_num"].data[packet_index]
511
-
512
- # If ESA lookup table number is in-flight calibration
513
- # data, then skip current cycle per SWE teams specification.
514
- # SWE team only wants in-flight calibration data to be processed
515
- # upto l1a. In-flight calibration data looks same as science data
516
- # but it only measures one energy steps during the whole duration.
517
- if esa_table_num == 1:
518
- continue
519
-
520
- full_cycle_ds = populate_full_cycle_data(
521
- full_cycle_l1a_data, packet_index, esa_table_num
522
- )
523
-
524
- # save full data array to file
525
- full_cycle_science_data.append(full_cycle_ds["full_cycle_data"].data)
526
- full_cycle_acq_times.append(full_cycle_ds["acquisition_time"].data)
527
-
528
- # ------------------------------------------------------------------
529
- # Save data to dataset.
530
- # ------------------------------------------------------------------
531
- # Load CDF attrs
532
- cdf_attrs = ImapCdfAttributes()
533
- cdf_attrs.add_instrument_global_attrs("swe")
534
- cdf_attrs.add_instrument_variable_attrs("swe", "l1b")
535
- cdf_attrs.add_global_attribute("Data_version", data_version)
536
-
537
- # Get epoch time of full cycle data and then reshape it to
538
- # (n, 4) where n = total number of full cycles and 4 = four
539
- # quarter cycle data metadata. For epoch's data, we take the first element
540
- # of each quarter cycle data metadata.
541
- epoch_time = xr.DataArray(
542
- l1a_data["epoch"].data[full_cycle_data_indices].reshape(-1, 4)[:, 0],
543
- name="epoch",
544
- dims=["epoch"],
545
- attrs=cdf_attrs.get_variable_attributes("epoch"),
546
- )
547
-
548
- esa_step = xr.DataArray(
549
- np.arange(24),
550
- name="esa_step",
551
- dims=["esa_step"],
552
- attrs=cdf_attrs.get_variable_attributes("esa_step"),
553
- )
554
-
555
- # NOTE: LABL_PTR_1 should be CDF_CHAR.
556
- esa_step_label = xr.DataArray(
557
- esa_step.values.astype(str),
558
- name="esa_step_label",
559
- dims=["esa_step"],
560
- attrs=cdf_attrs.get_variable_attributes("esa_step_label"),
561
- )
562
-
563
- spin_sector = xr.DataArray(
564
- np.arange(30),
565
- name="spin_sector",
566
- dims=["spin_sector"],
567
- attrs=cdf_attrs.get_variable_attributes("spin_sector"),
568
- )
569
-
570
- # NOTE: LABL_PTR_2 should be CDF_CHAR.
571
- spin_sector_label = xr.DataArray(
572
- spin_sector.values.astype(str),
573
- name="spin_sector_label",
574
- dims=["spin_sector"],
575
- attrs=cdf_attrs.get_variable_attributes("spin_sector_label"),
576
- )
577
-
578
- cycle = xr.DataArray(
579
- np.arange(4),
580
- name="cycle",
581
- dims=["cycle"],
582
- attrs=cdf_attrs.get_variable_attributes("cycle"),
583
- )
584
-
585
- cem_id = xr.DataArray(
586
- np.arange(7, dtype=np.float64),
587
- name="cem_id",
588
- dims=["cem_id"],
589
- attrs=cdf_attrs.get_variable_attributes("cem_id"),
590
- )
591
-
592
- # NOTE: LABL_PTR_3 should be CDF_CHAR.
593
- cem_id_label = xr.DataArray(
594
- cem_id.values.astype(str),
595
- name="cem_id_label",
596
- dims=["cem_id"],
597
- attrs=cdf_attrs.get_variable_attributes("cem_id_label"),
598
- )
599
-
600
- # Add science data and it's associated metadata into dataset.
601
- # SCIENCE_DATA has array of this shape:
602
- # (n, 24, 30, 7)
603
- # n = total number of full cycles
604
- # 24 rows --> 24 esa voltage measurements
605
- # 30 columns --> 30 spin angle measurements
606
- # 7 elements --> 7 CEMs counts
607
- #
608
- # The metadata array will need to have this shape:
609
- # (n, 4)
610
- # n = total number of full cycles
611
- # 4 rows --> metadata for each full cycle. Each element of 4 maps to
612
- # metadata of one quarter cycle.
613
-
614
- # Create the dataset
615
- dataset = xr.Dataset(
616
- coords={
617
- "epoch": epoch_time,
618
- "esa_step": esa_step,
619
- "spin_sector": spin_sector,
620
- "cem_id": cem_id,
621
- "cycle": cycle,
622
- "esa_step_label": esa_step_label,
623
- "spin_sector_label": spin_sector_label,
624
- "cem_id_label": cem_id_label,
625
- },
626
- attrs=cdf_attrs.get_global_attributes("imap_swe_l1b_sci"),
627
- )
628
-
629
- dataset["science_data"] = xr.DataArray(
630
- full_cycle_science_data,
631
- dims=["epoch", "esa_step", "spin_sector", "cem_id"],
632
- attrs=cdf_attrs.get_variable_attributes("science_data"),
633
- )
634
- dataset["acquisition_time"] = xr.DataArray(
635
- full_cycle_acq_times,
636
- dims=["epoch", "esa_step", "spin_sector"],
637
- attrs=cdf_attrs.get_variable_attributes("acquisition_time"),
638
- )
639
-
640
- # create xarray dataset for each metadata field
641
- for key, value in full_cycle_l1a_data.items():
642
- if key == "science_data":
643
- continue
644
- metadata_field = key.lower()
645
- dataset[metadata_field] = xr.DataArray(
646
- value.data.reshape(-1, 4),
647
- dims=["epoch", "cycle"],
648
- attrs=cdf_attrs.get_variable_attributes(metadata_field),
649
- )
650
-
651
- logger.info("SWE L1b science processing completed")
652
- return dataset