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
@@ -13,22 +13,27 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
13
13
  determine_species,
14
14
  get_coincidence_positions,
15
15
  get_ctof,
16
- get_de_az_el,
17
16
  get_de_energy_kev,
18
17
  get_de_velocity,
19
18
  get_energy_pulse_height,
20
19
  get_energy_ssd,
20
+ get_eventtimes,
21
21
  get_front_x_position,
22
22
  get_front_y_position,
23
+ get_fwhm,
23
24
  get_path_length,
24
25
  get_ph_tof_and_back_positions,
26
+ get_phi_theta,
25
27
  get_ssd_back_position_and_tof_offset,
26
28
  get_ssd_tof,
27
29
  )
28
30
  from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
29
31
 
32
+ FILLVAL_UINT8 = 255
33
+ FILLVAL_FLOAT32 = -1.0e31
30
34
 
31
- def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dataset:
35
+
36
+ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
32
37
  """
33
38
  Create dataset with defined datatypes for Direct Event Data.
34
39
 
@@ -38,8 +43,6 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
38
43
  L1a dataset containing direct event data.
39
44
  name : str
40
45
  Name of the l1a dataset.
41
- data_version : str
42
- Version of the data.
43
46
 
44
47
  Returns
45
48
  -------
@@ -49,55 +52,106 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
49
52
  de_dict = {}
50
53
  sensor = parse_filename_like(name)["sensor"][0:2]
51
54
 
52
- # Drop events with invalid start type.
53
- de_dataset = de_dataset.where(
54
- de_dataset["START_TYPE"] != np.iinfo(np.int64).min, drop=True
55
+ # Define epoch and spin.
56
+ de_dict["epoch"] = de_dataset["epoch"].data
57
+ de_dict["spin"] = de_dataset["spin"].data
58
+
59
+ # Add already populated fields.
60
+ keys = [
61
+ "coincidence_type",
62
+ "start_type",
63
+ "event_type",
64
+ "de_event_met",
65
+ "phase_angle",
66
+ "spin",
67
+ ]
68
+ dataset_keys = [
69
+ "coin_type",
70
+ "start_type",
71
+ "stop_type",
72
+ "shcoarse",
73
+ "phase_angle",
74
+ "spin",
75
+ ]
76
+
77
+ de_dict.update(
78
+ {key: de_dataset[dataset_key] for key, dataset_key in zip(keys, dataset_keys)}
55
79
  )
56
80
 
57
- # Instantiate arrays
58
- yf = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
59
- xb = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
60
- yb = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
61
- xc = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
62
- d = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float64)
63
- r = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
64
- tof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
65
- etof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
66
- ctof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
67
- magnitude_v = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
68
- energy = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
69
- species_bin = np.full(len(de_dataset["epoch"]), "UNKNOWN", dtype="U10")
70
- t2 = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
71
-
72
- # Define epoch.
73
- de_dict["epoch"] = de_dataset["epoch"].data
81
+ valid_mask = de_dataset["start_type"].data != FILLVAL_UINT8
82
+ ph_mask = np.isin(
83
+ de_dataset["stop_type"].data, [StopType.Top.value, StopType.Bottom.value]
84
+ )
85
+ ssd_mask = np.isin(de_dataset["stop_type"].data, [StopType.SSD.value])
86
+
87
+ valid_indices = np.nonzero(valid_mask)[0]
88
+ ph_indices = np.nonzero(valid_mask & ph_mask)[0]
89
+ ssd_indices = np.nonzero(valid_mask & ssd_mask)[0]
74
90
 
75
- xf = get_front_x_position(
76
- de_dataset["START_TYPE"].data,
77
- de_dataset["START_POS_TDC"].data,
91
+ # Instantiate arrays
92
+ xf = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
93
+ yf = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
94
+ xb = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
95
+ yb = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
96
+ xc = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
97
+ d = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64)
98
+ r = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
99
+ phi = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
100
+ theta = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
101
+ tof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
102
+ etof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
103
+ ctof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
104
+ magnitude_v = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
105
+ energy = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
106
+ species_bin = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
107
+ t2 = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
108
+ event_times = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64)
109
+ spin_starts = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64)
110
+ spin_period_sec = np.full(
111
+ len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64
112
+ )
113
+ start_type = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
114
+
115
+ xf[valid_indices] = get_front_x_position(
116
+ de_dataset["start_type"].data[valid_indices],
117
+ de_dataset["start_pos_tdc"].data[valid_indices],
118
+ f"ultra{sensor}",
119
+ )
120
+ start_type[valid_indices] = de_dataset["start_type"].data[valid_indices]
121
+
122
+ (
123
+ event_times[valid_indices],
124
+ spin_starts[valid_indices],
125
+ spin_period_sec[valid_indices],
126
+ ) = get_eventtimes(
127
+ de_dataset["spin"].data[valid_indices],
128
+ de_dataset["phase_angle"].data[valid_indices],
78
129
  )
79
130
 
80
131
  # Pulse height
81
- ph_indices = np.nonzero(
82
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
83
- )[0]
84
132
  tof[ph_indices], t2[ph_indices], xb[ph_indices], yb[ph_indices] = (
85
133
  get_ph_tof_and_back_positions(de_dataset, xf, f"ultra{sensor}")
86
134
  )
87
135
  d[ph_indices], yf[ph_indices] = get_front_y_position(
88
- de_dataset["START_TYPE"].data[ph_indices], yb[ph_indices]
136
+ de_dataset["start_type"].data[ph_indices], yb[ph_indices]
89
137
  )
90
138
  energy[ph_indices] = get_energy_pulse_height(
91
- de_dataset["STOP_TYPE"].data[ph_indices],
92
- de_dataset["ENERGY_PH"].data[ph_indices],
139
+ de_dataset["stop_type"].data[ph_indices],
140
+ de_dataset["energy_ph"].data[ph_indices],
93
141
  xb[ph_indices],
94
142
  yb[ph_indices],
143
+ f"ultra{sensor}",
95
144
  )
96
145
  r[ph_indices] = get_path_length(
97
146
  (xf[ph_indices], yf[ph_indices]),
98
147
  (xb[ph_indices], yb[ph_indices]),
99
148
  d[ph_indices],
100
149
  )
150
+ phi[ph_indices], theta[ph_indices] = get_phi_theta(
151
+ (xf[ph_indices], yf[ph_indices]),
152
+ (xb[ph_indices], yb[ph_indices]),
153
+ d[ph_indices],
154
+ )
101
155
  species_bin[ph_indices] = determine_species(tof[ph_indices], r[ph_indices], "PH")
102
156
  etof[ph_indices], xc[ph_indices] = get_coincidence_positions(
103
157
  de_dataset.isel(epoch=ph_indices), t2[ph_indices], f"ultra{sensor}"
@@ -107,14 +161,15 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
107
161
  )
108
162
 
109
163
  # SSD
110
- ssd_indices = np.nonzero(np.isin(de_dataset["STOP_TYPE"], StopType.SSD.value))[0]
111
- tof[ssd_indices] = get_ssd_tof(de_dataset, xf)
112
- yb[ssd_indices], _, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
164
+ tof[ssd_indices] = get_ssd_tof(de_dataset, xf, f"ultra{sensor}")
165
+ yb[ssd_indices], _, ssd_number = get_ssd_back_position_and_tof_offset(
166
+ de_dataset, f"ultra{sensor}"
167
+ )
113
168
  xc[ssd_indices] = np.zeros(len(ssd_indices))
114
169
  xb[ssd_indices] = np.zeros(len(ssd_indices))
115
170
  etof[ssd_indices] = np.zeros(len(ssd_indices))
116
171
  d[ssd_indices], yf[ssd_indices] = get_front_y_position(
117
- de_dataset["START_TYPE"].data[ssd_indices], yb[ssd_indices]
172
+ de_dataset["start_type"].data[ssd_indices], yb[ssd_indices]
118
173
  )
119
174
  energy[ssd_indices] = get_energy_ssd(de_dataset, ssd_number)
120
175
  r[ssd_indices] = get_path_length(
@@ -122,6 +177,11 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
122
177
  (xb[ssd_indices], yb[ssd_indices]),
123
178
  d[ssd_indices],
124
179
  )
180
+ phi[ssd_indices], theta[ssd_indices] = get_phi_theta(
181
+ (xf[ssd_indices], yf[ssd_indices]),
182
+ (xb[ssd_indices], yb[ssd_indices]),
183
+ d[ssd_indices],
184
+ )
125
185
  species_bin[ssd_indices] = determine_species(
126
186
  tof[ssd_indices], r[ssd_indices], "SSD"
127
187
  )
@@ -131,6 +191,9 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
131
191
 
132
192
  # Combine ph_yb and ssd_yb along with their indices
133
193
  de_dict["x_front"] = xf.astype(np.float32)
194
+ de_dict["event_times"] = event_times
195
+ de_dict["spin_starts"] = spin_starts
196
+ de_dict["spin_period"] = spin_period_sec
134
197
  de_dict["y_front"] = yf
135
198
  de_dict["x_back"] = xb
136
199
  de_dict["y_back"] = yb
@@ -141,37 +204,27 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
141
204
  de_dict["velocity_magnitude"] = magnitude_v
142
205
  de_dict["front_back_distance"] = d
143
206
  de_dict["path_length"] = r
207
+ de_dict["phi"] = phi
208
+ de_dict["theta"] = theta
144
209
 
145
- keys = [
146
- "coincidence_type",
147
- "start_type",
148
- "event_type",
149
- "de_event_met",
150
- "event_times",
151
- ]
152
- dataset_keys = ["COIN_TYPE", "START_TYPE", "STOP_TYPE", "SHCOARSE", "EVENTTIMES"]
153
-
154
- de_dict.update(
155
- {key: de_dataset[dataset_key] for key, dataset_key in zip(keys, dataset_keys)}
156
- )
157
-
158
- v = get_de_velocity(
210
+ v, vhat, r = get_de_velocity(
159
211
  (de_dict["x_front"], de_dict["y_front"]),
160
212
  (de_dict["x_back"], de_dict["y_back"]),
161
213
  de_dict["front_back_distance"],
162
214
  de_dict["tof_start_stop"],
163
215
  )
164
216
  de_dict["direct_event_velocity"] = v.astype(np.float32)
217
+ de_dict["direct_event_unit_velocity"] = vhat.astype(np.float32)
218
+ de_dict["direct_event_unit_position"] = r.astype(np.float32)
165
219
 
166
220
  de_dict["tof_energy"] = get_de_energy_kev(v, species_bin)
167
- de_dict["azimuth"], de_dict["elevation"] = get_de_az_el(v)
168
221
  de_dict["energy"] = energy
169
222
  de_dict["species"] = species_bin
170
223
 
171
224
  # Annotated Events.
172
225
  ultra_frame = getattr(SpiceFrame, f"IMAP_ULTRA_{sensor}")
173
226
  sc_velocity, sc_dps_velocity, helio_velocity = get_annotated_particle_velocity(
174
- de_dataset.data_vars["EVENTTIMES"].values,
227
+ event_times,
175
228
  de_dict["direct_event_velocity"],
176
229
  ultra_frame,
177
230
  SpiceFrame.IMAP_DPS,
@@ -182,11 +235,17 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
182
235
  de_dict["velocity_dps_sc"] = sc_dps_velocity
183
236
  de_dict["velocity_dps_helio"] = helio_velocity
184
237
 
185
- # TODO: TBD.
186
- de_dict["event_efficiency"] = np.full(
187
- len(de_dataset["epoch"]), np.nan, dtype=np.float32
238
+ de_dict["energy_spacecraft"] = get_de_energy_kev(sc_dps_velocity, species_bin)
239
+ de_dict["energy_heliosphere"] = get_de_energy_kev(helio_velocity, species_bin)
240
+
241
+ de_dict["phi_fwhm"], de_dict["theta_fwhm"] = get_fwhm(
242
+ start_type,
243
+ f"ultra{sensor}",
244
+ de_dict["tof_energy"],
245
+ de_dict["phi"],
246
+ de_dict["theta"],
188
247
  )
189
248
 
190
- dataset = create_dataset(de_dict, name, "l1b", data_version)
249
+ dataset = create_dataset(de_dict, name, "l1b")
191
250
 
192
251
  return dataset
@@ -1,58 +1,60 @@
1
1
  """Calculate Extended Spin."""
2
2
 
3
+ import numpy as np
3
4
  import xarray as xr
4
5
 
5
6
  from imap_processing.ultra.l1b.ultra_l1b_culling import (
6
7
  flag_attitude,
7
8
  flag_spin,
8
9
  get_energy_histogram,
9
- get_spin,
10
10
  )
11
11
  from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
12
12
 
13
13
 
14
14
  def calculate_extendedspin(
15
- hk_dataset: xr.Dataset,
16
- rates_dataset: xr.Dataset,
17
- de_dataset: xr.Dataset,
15
+ dict_datasets: dict[str, xr.Dataset],
18
16
  name: str,
19
- data_version: str,
17
+ instrument_id: int,
20
18
  ) -> xr.Dataset:
21
19
  """
22
20
  Create dataset with defined datatypes for Extended Spin Data.
23
21
 
24
22
  Parameters
25
23
  ----------
26
- hk_dataset : xarray.Dataset
27
- Dataset containing l1a hk data.
28
- rates_dataset : xarray.Dataset
29
- Dataset containing l1a rates data.
30
- de_dataset : xarray.Dataset
31
- Dataset containing l1b de data.
24
+ dict_datasets : dict
25
+ Dictionary containing all the datasets.
32
26
  name : str
33
27
  Name of the dataset.
34
- data_version : str
35
- Version of the data.
28
+ instrument_id : int
29
+ Instrument ID.
36
30
 
37
31
  Returns
38
32
  -------
39
33
  extendedspin_dataset : xarray.Dataset
40
34
  Dataset containing the data.
41
35
  """
36
+ aux_dataset = dict_datasets[f"imap_ultra_l1a_{instrument_id}sensor-aux"]
37
+ de_dataset = dict_datasets[f"imap_ultra_l1b_{instrument_id}sensor-de"]
38
+
42
39
  extendedspin_dict = {}
43
40
  rates_qf, spin, energy_midpoints, n_sigma_per_energy = flag_spin(
44
- de_dataset["event_times"].values,
41
+ de_dataset["spin"].values,
45
42
  de_dataset["energy"].values,
46
43
  )
47
- spin_number = get_spin(de_dataset["event_times"].values)
48
44
  count_rates, _, counts, _ = get_energy_histogram(
49
- spin_number, de_dataset["energy"].values
45
+ de_dataset["spin"].values, de_dataset["energy"].values
50
46
  )
51
47
  attitude_qf, spin_rates, spin_period, spin_starttime = flag_attitude(
52
- de_dataset["event_times"].values
48
+ de_dataset["spin"].values, aux_dataset
53
49
  )
50
+ # Get the first epoch for each spin.
51
+ mask = xr.DataArray(np.isin(de_dataset["spin"], spin), dims="epoch")
52
+ filtered_dataset = de_dataset.where(mask, drop=True)
53
+ _, first_indices = np.unique(filtered_dataset["spin"].values, return_index=True)
54
+ first_epochs = filtered_dataset["epoch"].values[first_indices]
54
55
 
55
56
  # These will be the coordinates.
57
+ extendedspin_dict["epoch"] = first_epochs
56
58
  extendedspin_dict["spin_number"] = spin
57
59
  extendedspin_dict["energy_bin_geometric_mean"] = energy_midpoints
58
60
 
@@ -64,6 +66,6 @@ def calculate_extendedspin(
64
66
  extendedspin_dict["quality_attitude"] = attitude_qf
65
67
  extendedspin_dict["quality_ena_rates"] = rates_qf
66
68
 
67
- extendedspin_dataset = create_dataset(extendedspin_dict, name, "l1b", data_version)
69
+ extendedspin_dataset = create_dataset(extendedspin_dict, name, "l1b")
68
70
 
69
71
  return extendedspin_dataset
@@ -23,7 +23,21 @@ _BACK_POS_DF_ULTRA90 = pd.read_csv(
23
23
  BASE_PATH / "ultra90_back-pos-luts.csv", index_col="Index_offset"
24
24
  )
25
25
  _ENERGY_NORM_DF = pd.read_csv(BASE_PATH / "EgyNorm.mem.csv")
26
- _IMAGE_PARAMS_DF = pd.read_csv(BASE_PATH / "FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv")
26
+ _IMAGE_PARAMS_DF = {
27
+ "ultra45": pd.read_csv(BASE_PATH / "FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv"),
28
+ "ultra90": pd.read_csv(BASE_PATH / "FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv"),
29
+ }
30
+
31
+ _FWHM_TABLES = {
32
+ ("left", "ultra45"): pd.read_csv(BASE_PATH / "Angular_Profiles_FM45_LeftSlit.csv"),
33
+ ("right", "ultra45"): pd.read_csv(
34
+ BASE_PATH / "Angular_Profiles_FM45_RightSlit.csv"
35
+ ),
36
+ ("left", "ultra90"): pd.read_csv(BASE_PATH / "Angular_Profiles_FM90_LeftSlit.csv"),
37
+ ("right", "ultra90"): pd.read_csv(
38
+ BASE_PATH / "Angular_Profiles_FM90_RightSlit.csv"
39
+ ),
40
+ }
27
41
 
28
42
 
29
43
  def get_y_adjust(dy_lut: np.ndarray) -> npt.NDArray:
@@ -32,7 +46,7 @@ def get_y_adjust(dy_lut: np.ndarray) -> npt.NDArray:
32
46
 
33
47
  Instead of using trigonometry, this function utilizes a 256-element lookup table
34
48
  to find the Y adjustment. For more details, refer to pages 37-38 of the
35
- IMAP-Ultra Flight Software Specification document (7523-9009_Rev_-.pdf).
49
+ IMAP-Ultra Flight Software Specification document.
36
50
 
37
51
  Parameters
38
52
  ----------
@@ -56,7 +70,7 @@ def get_norm(dn: xr.DataArray, key: str, file_label: str) -> npt.NDArray:
56
70
  using lookup tables.
57
71
 
58
72
  Further description is available on pages 31-32 of the IMAP-Ultra Flight Software
59
- Specification document (7523-9009_Rev_-.pdf). This will work for both Tp{key}Norm,
73
+ Specification document. This will work for both Tp{key}Norm,
60
74
  Bt{key}Norm. This is for getStopNorm and getCoinNorm.
61
75
 
62
76
  Parameters
@@ -92,7 +106,7 @@ def get_back_position(back_index: np.ndarray, key: str, file_label: str) -> npt.
92
106
  instead of linear equations is necessary. The computation will use different
93
107
  tables to accommodate variations between the top and bottom anodes.
94
108
  Further description is available on page 32 of the
95
- IMAP-Ultra Flight Software Specification document (7523-9009_Rev_-.pdf).
109
+ IMAP-Ultra Flight Software Specification document.
96
110
 
97
111
  Parameters
98
112
  ----------
@@ -122,8 +136,8 @@ def get_energy_norm(ssd: np.ndarray, composite_energy: np.ndarray) -> npt.NDArra
122
136
  Normalize composite energy per SSD using a lookup table.
123
137
 
124
138
  Further description is available on page 41 of the
125
- IMAP-Ultra Flight Software Specification document
126
- (7523-9009_Rev_-.pdf). Note : There are 8 SSDs containing
139
+ IMAP-Ultra Flight Software Specification document.
140
+ Note : There are 8 SSDs containing
127
141
  4096 composite energies each.
128
142
 
129
143
  Parameters
@@ -143,23 +157,72 @@ def get_energy_norm(ssd: np.ndarray, composite_energy: np.ndarray) -> npt.NDArra
143
157
  return _ENERGY_NORM_DF["NormEnergy"].iloc[row_number]
144
158
 
145
159
 
146
- def get_image_params(image: str) -> np.float64:
160
+ def get_image_params(image: str, sensor: str) -> np.float64:
147
161
  """
148
162
  Lookup table for image parameters.
149
163
 
150
164
  Further description is available starting on
151
165
  page 30 of the IMAP-Ultra Flight Software
152
- Specification document (7523-9009_Rev_-.pdf).
166
+ Specification document.
153
167
 
154
168
  Parameters
155
169
  ----------
156
170
  image : str
157
171
  The column name to lookup in the CSV file, e.g., 'XFTLTOFF' or 'XFTRTOFF'.
172
+ sensor : str
173
+ Sensor name: "ultra45" or "ultra90".
158
174
 
159
175
  Returns
160
176
  -------
161
177
  value : np.float64
162
178
  Image parameter value from the CSV file.
163
179
  """
164
- value: np.float64 = _IMAGE_PARAMS_DF[image].values[0]
180
+ lookup_table = _IMAGE_PARAMS_DF[sensor]
181
+ value: np.float64 = lookup_table[image].values[0]
165
182
  return value
183
+
184
+
185
+ def get_angular_profiles(start_type: str, sensor: str) -> pd.DataFrame:
186
+ """
187
+ Lookup table for FWHM for theta and phi.
188
+
189
+ Further description is available starting on
190
+ page 18 of the Algorithm Document.
191
+
192
+ Parameters
193
+ ----------
194
+ start_type : str
195
+ Start Type: Left, Right.
196
+ sensor : str
197
+ Sensor name: "ultra45" or "ultra90".
198
+
199
+ Returns
200
+ -------
201
+ lookup_table : DataFrame
202
+ Angular profile lookup table for a given start_type and sensor.
203
+ """
204
+ lookup_table = _FWHM_TABLES[(start_type.lower(), sensor)]
205
+
206
+ return lookup_table
207
+
208
+
209
+ def get_energy_efficiencies() -> pd.DataFrame:
210
+ """
211
+ Lookup table for efficiencies for theta and phi.
212
+
213
+ Further description is available starting on
214
+ page 18 of the Algorithm Document.
215
+
216
+ Returns
217
+ -------
218
+ lookup_table : DataFrame
219
+ Efficiencies lookup table for a given sensor.
220
+ """
221
+ # TODO: Move this out of tests directory once we have the aux api
222
+ # TODO: ultra90 efficiencies
223
+ path = imap_module_directory / "tests" / "ultra" / "data" / "l1"
224
+ lookup_table = pd.read_csv(
225
+ path / "Ultra_efficiencies_45_combined_logistic_interpolation.csv"
226
+ )
227
+
228
+ return lookup_table
@@ -8,7 +8,7 @@ from imap_processing.ultra.l1b.de import calculate_de
8
8
  from imap_processing.ultra.l1b.extendedspin import calculate_extendedspin
9
9
 
10
10
 
11
- def ultra_l1b(data_dict: dict, data_version: str) -> list[xr.Dataset]:
11
+ def ultra_l1b(data_dict: dict) -> list[xr.Dataset]:
12
12
  """
13
13
  Will process ULTRA L1A data into L1B CDF files at output_filepath.
14
14
 
@@ -16,47 +16,67 @@ def ultra_l1b(data_dict: dict, data_version: str) -> list[xr.Dataset]:
16
16
  ----------
17
17
  data_dict : dict
18
18
  The data itself and its dependent data.
19
- data_version : str
20
- Version of the data product being created.
21
19
 
22
20
  Returns
23
21
  -------
24
22
  output_datasets : list[xarray.Dataset]
25
23
  List of xarray.Dataset.
24
+
25
+ Notes
26
+ -----
27
+ General flow:
28
+ 1. l1a data products are created (upstream to this code)
29
+ 2. l1b de is created here and dropped in s3 kicking off processing again
30
+ 3. l1b extended, culling, badtimes created here
26
31
  """
27
32
  output_datasets = []
28
33
  instrument_id = 45 if any("45" in key for key in data_dict.keys()) else 90
29
34
 
30
- if (
31
- f"imap_ultra_l1a_{instrument_id}sensor-hk" in data_dict
32
- and f"imap_ultra_l1a_{instrument_id}sensor-de" in data_dict
33
- and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
34
- ):
35
+ # L1b de data will be created if L1a de data is available
36
+ if f"imap_ultra_l1a_{instrument_id}sensor-de" in data_dict:
35
37
  de_dataset = calculate_de(
36
38
  data_dict[f"imap_ultra_l1a_{instrument_id}sensor-de"],
37
39
  f"imap_ultra_l1b_{instrument_id}sensor-de",
38
- data_version,
39
40
  )
41
+ output_datasets.append(de_dataset)
42
+ # L1b extended data will be created if L1a hk, rates,
43
+ # aux, params, and l1b de data are available
44
+ elif (
45
+ f"imap_ultra_l1a_{instrument_id}sensor-hk" in data_dict
46
+ and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
47
+ and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
48
+ and f"imap_ultra_l1a_{instrument_id}sensor-aux" in data_dict
49
+ and f"imap_ultra_l1a_{instrument_id}sensor-params" in data_dict
50
+ ):
40
51
  extendedspin_dataset = calculate_extendedspin(
41
- data_dict[f"imap_ultra_l1a_{instrument_id}sensor-hk"],
42
- data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
43
- de_dataset,
52
+ {
53
+ f"imap_ultra_l1a_{instrument_id}sensor-aux": data_dict[
54
+ f"imap_ultra_l1a_{instrument_id}sensor-aux"
55
+ ],
56
+ f"imap_ultra_l1a_{instrument_id}sensor-hk": data_dict[
57
+ f"imap_ultra_l1a_{instrument_id}sensor-hk"
58
+ ],
59
+ f"imap_ultra_l1a_{instrument_id}sensor-rates": data_dict[
60
+ f"imap_ultra_l1a_{instrument_id}sensor-rates"
61
+ ],
62
+ f"imap_ultra_l1b_{instrument_id}sensor-de": data_dict[
63
+ f"imap_ultra_l1b_{instrument_id}sensor-de"
64
+ ],
65
+ },
44
66
  f"imap_ultra_l1b_{instrument_id}sensor-extendedspin",
45
- data_version,
67
+ instrument_id,
46
68
  )
47
69
  cullingmask_dataset = calculate_cullingmask(
48
70
  extendedspin_dataset,
49
71
  f"imap_ultra_l1b_{instrument_id}sensor-cullingmask",
50
- data_version,
51
72
  )
52
73
  badtimes_dataset = calculate_badtimes(
53
74
  extendedspin_dataset,
54
75
  cullingmask_dataset["spin_number"].values,
55
76
  f"imap_ultra_l1b_{instrument_id}sensor-badtimes",
56
- data_version,
57
77
  )
58
78
  output_datasets.extend(
59
- [de_dataset, extendedspin_dataset, cullingmask_dataset, badtimes_dataset]
79
+ [extendedspin_dataset, cullingmask_dataset, badtimes_dataset]
60
80
  )
61
81
  else:
62
82
  raise ValueError("Data dictionary does not contain the expected keys.")