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
@@ -0,0 +1,19 @@
1
+ """Define utils and classes related to coordinates of the ENA maps."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class CoordNames(Enum):
7
+ """Enumeration of the names of the coordinates in the L1C and L2 ENA datasets."""
8
+
9
+ GENERIC_PIXEL = "pixel"
10
+
11
+ TIME = "epoch"
12
+ ENERGY_ULTRA = "energy_bin_geometric_mean"
13
+ HEALPIX_INDEX = "healpix_index"
14
+
15
+ # The names of the az/el angular coordinates may differ between L1C and L2 data
16
+ AZIMUTH_L1C = "longitude"
17
+ ELEVATION_L1C = "latitude"
18
+ AZIMUTH_L2 = "longitude"
19
+ ELEVATION_L2 = "latitude"
@@ -12,20 +12,22 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
  def bin_single_array_at_indices(
14
14
  value_array: NDArray,
15
- projection_grid_shape: tuple[int, int],
15
+ projection_grid_shape: tuple[int, ...],
16
16
  projection_indices: NDArray,
17
17
  input_indices: NDArray | None = None,
18
18
  ) -> NDArray:
19
19
  """
20
20
  Bin an array of values at the given indices.
21
21
 
22
+ NOTE: The output array's spatial axis is always the final (-1) axis.
23
+
22
24
  Parameters
23
25
  ----------
24
26
  value_array : NDArray
25
- Array of values to bin. The 0th axis must be the one and only spatial axis.
27
+ Array of values to bin. The final axis be the one and only spatial axis.
26
28
  If other axes are present, they will be binned independently
27
- along the 0th (spatial) axis.
28
- projection_grid_shape : tuple[int]
29
+ along the spatial axis.
30
+ projection_grid_shape : tuple[int, ...]
29
31
  The shape of the grid onto which values are projected
30
32
  (rows, columns) if the grid is rectangular,
31
33
  or just (number of bins,) if the grid is 1D.
@@ -36,7 +38,7 @@ def bin_single_array_at_indices(
36
38
  Ordered indices for input grid, corresponding to indices in projection grid.
37
39
  1 dimensional. May be non-unique, depending on the projection method.
38
40
  If None (default), an arange of the same length as the
39
- 0th axis of value_array is used.
41
+ final axis of value_array is used.
40
42
 
41
43
  Returns
42
44
  -------
@@ -52,7 +54,7 @@ def bin_single_array_at_indices(
52
54
  If the input value_array has dimensionality less than 1.
53
55
  """
54
56
  if input_indices is None:
55
- input_indices = np.arange(value_array.shape[0])
57
+ input_indices = np.arange(value_array.shape[-1])
56
58
 
57
59
  # Both sets of indices must be 1D with the same number of elements
58
60
  if input_indices.ndim != 1 or projection_indices.ndim != 1:
@@ -80,23 +82,18 @@ def bin_single_array_at_indices(
80
82
  binned_values = np.apply_along_axis(
81
83
  lambda x: np.bincount(
82
84
  projection_indices,
83
- weights=x[input_indices, ...],
85
+ weights=x[..., input_indices],
84
86
  minlength=num_projection_indices,
85
87
  ),
86
- axis=0,
88
+ axis=-1,
87
89
  arr=value_array,
88
90
  )
89
- else:
90
- raise NotImplementedError(
91
- "Only 1+ Dimensional arrays are supported for binning. "
92
- f"Received array with shape {value_array.shape}."
93
- )
94
91
  return binned_values
95
92
 
96
93
 
97
94
  def bin_values_at_indices(
98
95
  input_values_to_bin: dict[str, NDArray],
99
- projection_grid_shape: tuple[int, int],
96
+ projection_grid_shape: tuple[int, ...],
100
97
  projection_indices: NDArray,
101
98
  input_indices: NDArray | None = None,
102
99
  ) -> dict[str, NDArray]:
@@ -107,10 +104,10 @@ def bin_values_at_indices(
107
104
  ----------
108
105
  input_values_to_bin : dict[str, NDArray]
109
106
  Dict matching variable names to arrays of values to bin.
110
- The 0th axis of each array must be the one and only spatial axis,
107
+ The final (-1) axis of each array must be the one and only spatial axis,
111
108
  which the indices correspond to and on which the values will be binned.
112
- The other axes will be binned independently along this 0th axis.
113
- projection_grid_shape : tuple[int, int]
109
+ The other axes will be binned independently along this final spatial axis.
110
+ projection_grid_shape : tuple[int, ...]
114
111
  The shape of the grid onto which values are projected (rows, columns).
115
112
  This size of the resulting grid (rows * columns) will be the size of the
116
113
  projected values contained in the output dictionary.
@@ -15,8 +15,7 @@ def build_spatial_bins(
15
15
  """
16
16
  Build spatial bin boundaries for azimuth and elevation.
17
17
 
18
- Input angles in degrees for consistency with map inputs,
19
- output angles in radians for internal use.
18
+ Input/output angles in degrees.
20
19
 
21
20
  Parameters
22
21
  ----------
@@ -28,13 +27,13 @@ def build_spatial_bins(
28
27
  Returns
29
28
  -------
30
29
  az_bin_edges : np.ndarray
31
- Array of azimuth bin boundary values in radians.
30
+ Array of azimuth bin boundary values in degrees.
32
31
  el_bin_edges : np.ndarray
33
- Array of elevation bin boundary values in radians.
32
+ Array of elevation bin boundary values in degrees.
34
33
  az_bin_midpoints : np.ndarray
35
- Array of azimuth bin midpoint values in radians.
34
+ Array of azimuth bin midpoint values in degrees.
36
35
  el_bin_midpoints : np.ndarray
37
- Array of elevation bin midpoint values in radians.
36
+ Array of elevation bin midpoint values in degrees.
38
37
  """
39
38
  # Azimuth bins from 0 to 360 degrees.
40
39
  az_bin_edges = np.arange(0, 360 + az_spacing_deg, az_spacing_deg)
@@ -44,12 +43,11 @@ def build_spatial_bins(
44
43
  el_bin_edges = np.arange(-90, 90 + el_spacing_deg, el_spacing_deg)
45
44
  el_bin_midpoints = el_bin_edges[:-1] + el_spacing_deg / 2 # Midpoints between edges
46
45
 
47
- # Convert all angles to radians and return them
48
46
  return (
49
- np.deg2rad(az_bin_edges),
50
- np.deg2rad(el_bin_edges),
51
- np.deg2rad(az_bin_midpoints),
52
- np.deg2rad(el_bin_midpoints),
47
+ az_bin_edges,
48
+ el_bin_edges,
49
+ az_bin_midpoints,
50
+ el_bin_midpoints,
53
51
  )
54
52
 
55
53
 
@@ -59,6 +57,10 @@ def build_solid_angle_map(
59
57
  """
60
58
  Build a solid angle map in steradians for a given spacing in degrees.
61
59
 
60
+ NOTE: This function works in radians internally and returns steradians, while other
61
+ functions in this module work in degrees. Expressing solid angles in steradians
62
+ is the preferred unit for ENA Maps.
63
+
62
64
  Parameters
63
65
  ----------
64
66
  spacing_deg : float
@@ -77,17 +79,22 @@ def build_solid_angle_map(
77
79
  if spacing <= 0:
78
80
  raise ValueError("Spacing must be positive valued, non-zero.")
79
81
 
80
- if not np.isclose((np.pi / spacing) % 1, 0):
82
+ proposed_number_of_lat_bins = 180 / spacing_deg
83
+ number_of_lat_bins = round(180 / spacing_deg)
84
+ number_of_lon_bins = 2 * number_of_lat_bins
85
+ if not np.isclose(proposed_number_of_lat_bins, number_of_lat_bins):
81
86
  raise ValueError("Spacing must divide evenly into pi radians.")
82
87
 
83
- latitudes = np.arange(-np.pi / 2, np.pi / 2 + spacing, step=spacing)
84
- sine_latitudes = np.sin(latitudes)
85
- delta_sine_latitudes = np.diff(sine_latitudes)
88
+ latitude_edges = np.linspace(
89
+ -np.pi / 2, np.pi / 2, num=number_of_lat_bins + 1, endpoint=True
90
+ )
91
+ sine_latitude_edges = np.sin(latitude_edges)
92
+ delta_sine_latitudes = np.diff(sine_latitude_edges)
86
93
  solid_angle_by_latitude = np.abs(spacing * delta_sine_latitudes)
87
94
 
88
95
  # Order ensures agreement with build_az_el_grid's order of tiling az/el grid.
89
96
  solid_angle_grid = np.repeat(
90
- solid_angle_by_latitude[np.newaxis, :], (2 * np.pi) / spacing, axis=0
97
+ solid_angle_by_latitude[np.newaxis, :], number_of_lon_bins, axis=0
91
98
  )
92
99
 
93
100
  return solid_angle_grid
@@ -96,23 +103,26 @@ def build_solid_angle_map(
96
103
  @typing.no_type_check
97
104
  def rewrap_even_spaced_az_el_grid(
98
105
  raveled_values: NDArray,
99
- shape: tuple[int] | None = None,
106
+ grid_shape: tuple[int] | None = None,
100
107
  order: typing.Literal["C"] | typing.Literal["F"] = "C",
101
108
  ) -> NDArray:
102
109
  """
103
110
  Take an unwrapped (raveled) 1D array and reshapes it into a 2D az/el grid.
104
111
 
112
+ In the input, unwrapped grid, the spatial axis is the final (-1) axis.
113
+ In the output, the spatial axes are the -2 (azimuth) and -1 (elevation) axes.
114
+
105
115
  Assumes the following must be true of the original grid:
106
116
  1. Grid was evenly spaced in angular space,
107
117
  2. Grid had the same spacing in both azimuth and elevation.
108
- 3. Azimuth is axis 0 (and extends a total of 360 degrees).
109
- 4. Elevation is axis 1 (and extends a total of 180 degrees),
118
+ 3. Azimuth is the first spatial axis (and extends a total of 360 degrees).
119
+ 4. Elevation is the second spatial axis (and extends a total of 180 degrees).
110
120
 
111
121
  Parameters
112
122
  ----------
113
123
  raveled_values : NDArray
114
124
  1D array of values to be reshaped into a 2D grid.
115
- shape : tuple[int], optional
125
+ grid_shape : tuple[int], optional
116
126
  The shape of the original grid, if known, by default None.
117
127
  If None, the shape will be inferred from the size of the input array.
118
128
  order : {'C', 'F'}, optional
@@ -121,35 +131,27 @@ def rewrap_even_spaced_az_el_grid(
121
131
  Returns
122
132
  -------
123
133
  NDArray
124
- The reshaped 2D grid of values.
125
-
126
- Raises
127
- ------
128
- ValueError
129
- If the input is not a 1D array or 2D array with an 'extra' non-spatial axis.
134
+ The reshaped 2D grid of values with (azimuth, elevation) as the final 2 axes.
130
135
  """
131
- if raveled_values.ndim > 2:
132
- raise ValueError(
133
- "Input must be a 1D array or 2D array with only one spatial axis as axis 0."
134
- )
135
-
136
136
  # We can infer the shape if its evenly spaced and 2D
137
- if not shape:
138
- spacing_deg = 1 / np.sqrt(raveled_values.shape[0] / (360 * 180))
139
- shape = (int(360 // spacing_deg), int(180 // spacing_deg))
137
+ if not grid_shape:
138
+ spacing_deg = 1 / np.sqrt(raveled_values.shape[-1] / (360 * 180))
139
+ grid_shape = (int(360 // spacing_deg), int(180 // spacing_deg))
140
140
 
141
- if raveled_values.ndim == 2:
142
- shape = (shape[0], shape[1], raveled_values.shape[1])
143
- return raveled_values.reshape(shape, order=order)
141
+ if raveled_values.ndim == 1:
142
+ array_shape = grid_shape
143
+ else:
144
+ array_shape = (*raveled_values.shape[:-1], *grid_shape)
145
+ return raveled_values.reshape(array_shape, order=order)
144
146
 
145
147
 
146
148
  class AzElSkyGrid:
147
149
  """
148
150
  Representation of a 2D grid of azimuth and elevation angles covering the sky.
149
151
 
150
- All angles are stored internally in radians.
151
- Azimuth is within the range [0, 2*pi) radians,
152
- elevation is within the range [-pi/2, pi/2) radians.
152
+ All angles are stored internally in degrees.
153
+ Azimuth is within the range [0, 360) degrees,
154
+ elevation is within the range [-90, 90) degrees.
153
155
 
154
156
  Parameters
155
157
  ----------
@@ -157,13 +159,13 @@ class AzElSkyGrid:
157
159
  Spacing of the grid in degrees, by default 0.5.
158
160
  reversed_elevation : bool, optional
159
161
  Whether the elevation grid should be reversed, by default False.
160
- If False, the elevation grid will be from -pi/2 to pi/2 radians (-90 to 90 deg).
161
- If True, the elevation grid will be from pi/2 to -pi/2 radians (90 to -90 deg).
162
+ If False, the elevation grid will be from -90 to 90 deg.
163
+ If True, the elevation grid will be from 90 to -90 deg.
162
164
 
163
165
  Raises
164
166
  ------
165
167
  ValueError
166
- If the spacing is not positive or does not divide evenly into pi radians.
168
+ If the spacing is not positive or does not divide evenly into 180 degrees.
167
169
  """
168
170
 
169
171
  def __init__(
@@ -174,25 +176,26 @@ class AzElSkyGrid:
174
176
  # Store grid properties
175
177
  self.reversed_elevation = reversed_elevation
176
178
 
177
- # Internally, work in radians, regardless of desired output units
178
- self.spacing = np.deg2rad(spacing_deg)
179
+ # Internally, work in degrees
180
+ self.spacing_deg = spacing_deg
179
181
 
180
- # Ensure valid grid spacing (positive, divides evenly into pi radians)
181
- if self.spacing <= 0:
182
+ # Ensure valid grid spacing (positive, divides evenly into 180 degrees)
183
+ if self.spacing_deg <= 0:
182
184
  raise ValueError("Spacing must be positive valued, non-zero.")
183
185
 
184
- if not np.isclose((np.pi / self.spacing) % 1, 0):
185
- raise ValueError("Spacing must divide evenly into pi radians.")
186
+ if not np.isclose((180 / self.spacing_deg) % 1, 0):
187
+ raise ValueError("Spacing must divide evenly into 180 degrees.")
186
188
 
187
189
  # build_spacial_bins creates the bin edges and centers for azimuth and elevation
188
190
  # E.g. for spacing=1, az_bin_edges = [0, 1, 2, ..., 359, 360] deg.
189
- # However returned values are in radians.
190
191
  (
191
192
  self.az_bin_edges,
192
193
  self.el_bin_edges,
193
194
  self.az_bin_midpoints,
194
195
  self.el_bin_midpoints,
195
- ) = build_spatial_bins(az_spacing_deg=spacing_deg, el_spacing_deg=spacing_deg)
196
+ ) = build_spatial_bins(
197
+ az_spacing_deg=self.spacing_deg, el_spacing_deg=self.spacing_deg
198
+ )
196
199
 
197
200
  # If desired, reverse the elevation range so that the grid is in the order
198
201
  # defined by the Ultra prototype code (`build_dps_grid.m`).
@@ -221,6 +224,6 @@ class AzElSkyGrid:
221
224
  A string representation of the AzElSkyGrid.
222
225
  """
223
226
  return (
224
- f"AzElSkyGrid with a spacing of {self.spacing:.4e} radians. "
227
+ f"AzElSkyGrid with a spacing of {self.spacing_deg:.4e} degrees. "
225
228
  f"{self.grid_shape} Grid."
226
229
  )
@@ -1,32 +1,23 @@
1
1
  """Methods for GLOWS Level 1A processing and CDF writing."""
2
2
 
3
- from collections import defaultdict
4
3
  from pathlib import Path
5
- from typing import Optional
6
4
 
7
5
  import numpy as np
8
6
  import xarray as xr
9
7
 
10
8
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
9
  from imap_processing.glows.l0.decom_glows import decom_packets
12
- from imap_processing.glows.l0.glows_l0_data import DirectEventL0, HistogramL0
10
+ from imap_processing.glows.l0.glows_l0_data import DirectEventL0
13
11
  from imap_processing.glows.l1a.glows_l1a_data import DirectEventL1A, HistogramL1A
14
- from imap_processing.glows.l1b.glows_l1b_data import HistogramL1B
15
12
  from imap_processing.spice.time import (
16
- met_to_datetime64,
17
13
  met_to_ttj2000ns,
18
14
  )
19
15
 
20
16
 
21
- def create_glows_attr_obj(data_version: str) -> ImapCdfAttributes:
17
+ def create_glows_attr_obj() -> ImapCdfAttributes:
22
18
  """
23
19
  Load in 1la CDF attributes for GLOWS instrument.
24
20
 
25
- Parameters
26
- ----------
27
- data_version : str
28
- Data version for CDF filename, in the format "vXXX".
29
-
30
21
  Returns
31
22
  -------
32
23
  glows_attrs : ImapCdfAttributes
@@ -37,23 +28,23 @@ def create_glows_attr_obj(data_version: str) -> ImapCdfAttributes:
37
28
  # Load in files
38
29
  glows_attrs.add_instrument_global_attrs("glows")
39
30
  glows_attrs.add_instrument_variable_attrs("glows", "l1a")
40
- glows_attrs.add_global_attribute("Data_version", data_version)
41
31
  return glows_attrs
42
32
 
43
33
 
44
- def glows_l1a(packet_filepath: Path, data_version: str) -> list[xr.Dataset]:
34
+ def glows_l1a(packet_filepath: Path) -> list[xr.Dataset]:
45
35
  """
46
36
  Will process packets into GLOWS L1A CDF files.
47
37
 
48
38
  Outputs Datasets for histogram and direct event GLOWS L1A. This list can be passed
49
39
  into write_cdf to output CDF files.
50
40
 
41
+ We expect one input L0 file to be processed into one L1A file, with one
42
+ observational day's worth of data.
43
+
51
44
  Parameters
52
45
  ----------
53
46
  packet_filepath : pathlib.Path
54
47
  Path to packet file for processing.
55
- data_version : str
56
- Data version for CDF filename, in the format "vXXX".
57
48
 
58
49
  Returns
59
50
  -------
@@ -61,77 +52,30 @@ def glows_l1a(packet_filepath: Path, data_version: str) -> list[xr.Dataset]:
61
52
  List of the L1A datasets.
62
53
  """
63
54
  # Create ImapCdfAttributes object for cdf attributes management
64
- glows_attrs = create_glows_attr_obj(data_version)
65
-
66
- # TODO: Data version inside file as well?
55
+ glows_attrs = create_glows_attr_obj()
67
56
 
68
57
  # Decompose packet file into histogram, and direct event data.
69
58
  hist_l0, de_l0 = decom_packets(packet_filepath)
70
59
 
71
- # Create dictionaries to group data by day
72
- de_by_day = process_de_l0(de_l0)
73
- hists_by_day = defaultdict(list)
74
- # Assume the observational day starts with the first packet, then find any new
75
- # observation days.
76
- # TODO: replace determine_observational_day with spin table API
77
- obs_days = [hist_l0[0].SEC]
78
- obs_days += determine_observational_day(hist_l0)
79
-
60
+ l1a_de = process_de_l0(de_l0)
61
+ l1a_hists = []
80
62
  for hist in hist_l0:
81
- hist_l1a = HistogramL1A(hist)
82
- # Determine the day the histogram belongs to. This finds the observation
83
- # day in obs_day that is nearest the histogram timestamp without going over.
84
- hist_day = next(
85
- (day for day in reversed(obs_days) if day <= hist.SEC), obs_days[-1]
86
- )
87
- hists_by_day[hist_day].append(hist_l1a)
63
+ l1a_hists.append(HistogramL1A(hist))
88
64
 
89
65
  # Generate CDF files for each day
90
66
  output_datasets = []
91
- for obs_day, hist_l1a_list in hists_by_day.items():
92
- dataset = generate_histogram_dataset(hist_l1a_list, glows_attrs, obs_day)
93
- output_datasets.append(dataset)
67
+ dataset = generate_histogram_dataset(l1a_hists, glows_attrs)
68
+ output_datasets.append(dataset)
94
69
 
95
- for de_l1a_list in de_by_day.values():
96
- dataset = generate_de_dataset(de_l1a_list, glows_attrs)
97
- output_datasets.append(dataset)
70
+ dataset = generate_de_dataset(l1a_de, glows_attrs)
71
+ output_datasets.append(dataset)
98
72
 
99
73
  return output_datasets
100
74
 
101
75
 
102
- def determine_observational_day(hist_l0: list[HistogramL0]) -> list:
103
- """
104
- Find the timestamps for each observational day.
105
-
106
- This function temporarily uses the is_night flag to determine the start of a new
107
- observational day, but should eventually use the spin table APIs.
108
-
109
- Parameters
110
- ----------
111
- hist_l0 : list[HistogramL0]
112
- List of HistogramL0 objects.
113
-
114
- Returns
115
- -------
116
- list
117
- List of start times for each observational day.
118
- """
119
- prev_is_night = -1
120
- obs_day_change = []
121
- for hist in hist_l0:
122
- flags = HistogramL1B.deserialize_flags(hist.FLAGS)
123
- is_night: int = int(flags[6])
124
- if prev_is_night and not is_night:
125
- obs_day_change.append(hist.SEC)
126
-
127
- prev_is_night = is_night
128
-
129
- return obs_day_change
130
-
131
-
132
76
  def process_de_l0(
133
77
  de_l0: list[DirectEventL0],
134
- ) -> dict[np.datetime64, list[DirectEventL1A]]:
78
+ ) -> list[DirectEventL1A]:
135
79
  """
136
80
  Will process Direct Event packets into GLOWS L1A CDF files.
137
81
 
@@ -145,25 +89,22 @@ def process_de_l0(
145
89
 
146
90
  Returns
147
91
  -------
148
- de_by_day : dict[np.datetime64, list[DirectEventL1A]]
92
+ de_by_day : list[DirectEventL1A]
149
93
  Dictionary with keys of days and values of lists of DirectEventL1A objects.
150
94
  Each day has one CDF file associated with it.
151
95
  """
152
- de_by_day = dict()
96
+ de_list: list[DirectEventL1A] = []
153
97
 
154
98
  for de in de_l0:
155
- de_day = (met_to_datetime64(de.MET)).astype("datetime64[D]")
156
- if de_day not in de_by_day:
157
- de_by_day[de_day] = [DirectEventL1A(de)]
158
99
  # Putting not first data int o last direct event list.
159
- elif de.SEQ != 0:
100
+ if de.SEQ != 0:
160
101
  # If the direct event is part of a sequence and is not the first,
161
- # append it to the last direct event in the list
162
- de_by_day[de_day][-1].append(de)
102
+ # add it to the last direct event in the list
103
+ de_list[-1].merge_de_packets(de)
163
104
  else:
164
- de_by_day[de_day].append(DirectEventL1A(de))
105
+ de_list.append(DirectEventL1A(de))
165
106
 
166
- return de_by_day
107
+ return de_list
167
108
 
168
109
 
169
110
  def generate_de_dataset(
@@ -263,8 +204,8 @@ def generate_de_dataset(
263
204
  support_data["number_of_de_packets"].append(int(de.l0.LEN))
264
205
  # support_data["missing_packet_sequences"].append(str(de.missing_seq))
265
206
 
266
- for key in data_every_second.keys():
267
- data_every_second[key].append(de.status_data.__getattribute__(key))
207
+ for key, val in data_every_second.items():
208
+ val.append(de.status_data.__getattribute__(key))
268
209
 
269
210
  # Convert arrays and dictionaries into xarray 'DataArray' objects
270
211
  epoch_time = xr.DataArray(
@@ -284,7 +225,6 @@ def generate_de_dataset(
284
225
  ),
285
226
  )
286
227
 
287
- # TODO come up with a better name
288
228
  within_the_second = xr.DataArray(
289
229
  np.arange(direct_events.shape[1]),
290
230
  name="within_the_second",
@@ -304,7 +244,6 @@ def generate_de_dataset(
304
244
  attrs=glows_cdf_attributes.get_variable_attributes("direct_events"),
305
245
  )
306
246
 
307
- # TODO: This is the weird global attribute.
308
247
  # Create an xarray dataset object, and add DataArray objects into it
309
248
  output = xr.Dataset(
310
249
  coords={"epoch": time_data},
@@ -313,9 +252,6 @@ def generate_de_dataset(
313
252
 
314
253
  output["direct_events"] = de
315
254
 
316
- # TODO: Do we want missing_sequences as support data or as global attrs?
317
- # Currently: support data, with a string
318
-
319
255
  for key, value in support_data.items():
320
256
  output[key] = xr.DataArray(
321
257
  value,
@@ -340,7 +276,6 @@ def generate_de_dataset(
340
276
  def generate_histogram_dataset(
341
277
  hist_l1a_list: list[HistogramL1A],
342
278
  glows_cdf_attributes: ImapCdfAttributes,
343
- obs_day: Optional[int] = None,
344
279
  ) -> xr.Dataset:
345
280
  """
346
281
  Generate a dataset for GLOWS L1A histogram data CDF files.
@@ -351,9 +286,6 @@ def generate_histogram_dataset(
351
286
  List of HistogramL1A objects for a given day.
352
287
  glows_cdf_attributes : ImapCdfAttributes
353
288
  Object containing l1a CDF attributes for instrument glows.
354
- obs_day : int, optional
355
- Observational day counter. If supplied, it will be included in the
356
- output file name.
357
289
 
358
290
  Returns
359
291
  -------
@@ -407,12 +339,12 @@ def generate_histogram_dataset(
407
339
  )
408
340
 
409
341
  # Add support_data keys to the support_data dictionary
410
- for key in support_data.keys():
342
+ for key, support_val in support_data.items():
411
343
  if key not in ["flags_set_onboard", "is_generated_on_ground"]:
412
- support_data[key].append(hist.__getattribute__(key))
344
+ support_val.append(hist.__getattribute__(key))
413
345
  # For the time varying data, convert to seconds and then append
414
- for key in time_metadata.keys():
415
- time_metadata[key].append(hist.__getattribute__(key).to_seconds())
346
+ for key, time_metadata_val in time_metadata.items():
347
+ time_metadata_val.append(hist.__getattribute__(key).to_seconds())
416
348
  time_data[index] = epoch_time
417
349
 
418
350
  epoch_time = xr.DataArray(
@@ -450,9 +382,6 @@ def generate_histogram_dataset(
450
382
  )
451
383
 
452
384
  attrs = glows_cdf_attributes.get_global_attributes("imap_glows_l1a_hist")
453
- if obs_day:
454
- # this needs to be 5 digits, so truncate it from the temporary obs day
455
- attrs["Repointing"] = int(str(obs_day)[-5:])
456
385
 
457
386
  output = xr.Dataset(
458
387
  coords={"epoch": epoch_time, "bins": bins, "bins_label": bin_label},
@@ -326,7 +326,7 @@ class DirectEventL1A:
326
326
 
327
327
  Methods
328
328
  -------
329
- append
329
+ merge_de_packets
330
330
  Add another Level0 instance.
331
331
  """
332
332
 
@@ -346,7 +346,7 @@ class DirectEventL1A:
346
346
  if level0.LEN == 1:
347
347
  self._process_de_data()
348
348
 
349
- def append(self, second_l0: DirectEventL0) -> None:
349
+ def merge_de_packets(self, second_l0: DirectEventL0) -> None:
350
350
  """
351
351
  Merge an additional direct event packet to this DirectEventL1A class.
352
352
 
@@ -10,7 +10,7 @@ from imap_processing.glows import FLAG_LENGTH
10
10
  from imap_processing.glows.l1b.glows_l1b_data import DirectEventL1B, HistogramL1B
11
11
 
12
12
 
13
- def glows_l1b(input_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
13
+ def glows_l1b(input_dataset: xr.Dataset) -> xr.Dataset:
14
14
  """
15
15
  Will process the GLOWS L1B data and format the output datasets.
16
16
 
@@ -18,8 +18,6 @@ def glows_l1b(input_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
18
18
  ----------
19
19
  input_dataset : xr.Dataset
20
20
  Dataset of input values.
21
- data_version : str
22
- Data version.
23
21
 
24
22
  Returns
25
23
  -------
@@ -29,7 +27,6 @@ def glows_l1b(input_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
29
27
  cdf_attrs = ImapCdfAttributes()
30
28
  cdf_attrs.add_instrument_global_attrs("glows")
31
29
  cdf_attrs.add_instrument_variable_attrs("glows", "l1b")
32
- cdf_attrs.add_global_attribute("Data_version", data_version)
33
30
 
34
31
  data_epoch = xr.DataArray(
35
32
  input_dataset["epoch"],
@@ -1,4 +1,3 @@
1
- # ruff: noqa: PLR0913
2
1
  """Module for GLOWS L1B data products."""
3
2
 
4
3
  import dataclasses
@@ -73,8 +72,7 @@ class AncillaryParameters:
73
72
 
74
73
  except KeyError as e:
75
74
  raise KeyError(
76
- "GLOWS L1B Ancillary input_table does not conform to "
77
- "expected format."
75
+ "GLOWS L1B Ancillary input_table does not conform to expected format."
78
76
  ) from e
79
77
 
80
78
  def decode(self, param_key: str, encoded_value: np.double) -> np.double:
@@ -12,7 +12,7 @@ from imap_processing.glows.l1b.glows_l1b_data import HistogramL1B
12
12
  from imap_processing.glows.l2.glows_l2_data import DailyLightcurve, HistogramL2
13
13
 
14
14
 
15
- def glows_l2(input_dataset: xr.Dataset, data_version: str) -> list[xr.Dataset]:
15
+ def glows_l2(input_dataset: xr.Dataset) -> list[xr.Dataset]:
16
16
  """
17
17
  Will process GLoWS L2 data from L1 data.
18
18
 
@@ -20,8 +20,6 @@ def glows_l2(input_dataset: xr.Dataset, data_version: str) -> list[xr.Dataset]:
20
20
  ----------
21
21
  input_dataset : xarray.Dataset
22
22
  Input L1B dataset.
23
- data_version : str
24
- Version for output.
25
23
 
26
24
  Returns
27
25
  -------
@@ -31,7 +29,6 @@ def glows_l2(input_dataset: xr.Dataset, data_version: str) -> list[xr.Dataset]:
31
29
  cdf_attrs = ImapCdfAttributes()
32
30
  cdf_attrs.add_instrument_global_attrs("glows")
33
31
  cdf_attrs.add_instrument_variable_attrs("glows", "l2")
34
- cdf_attrs.add_global_attribute("Data_version", data_version)
35
32
 
36
33
  split_data = split_data_by_observational_day(input_dataset)
37
34
  l2_output = []
@@ -270,7 +267,7 @@ def create_l2_dataset(
270
267
 
271
268
  elif key != "daily_lightcurve":
272
269
  val = value
273
- if type(value) != np.ndarray:
270
+ if type(value) is not np.ndarray:
274
271
  val = np.array([value])
275
272
  output[key] = xr.DataArray(
276
273
  val,