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

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

Potentially problematic release.


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

Files changed (415) hide show
  1. imap_processing/__init__.py +11 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +66 -18
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +24 -40
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +934 -42
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  9. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  10. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  11. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -14
  12. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  13. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  14. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  15. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +25 -9
  16. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  17. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  18. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  19. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  20. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +23 -20
  21. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  22. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  23. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  24. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  25. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  26. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  27. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  28. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  29. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  30. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +64 -52
  31. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  32. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +180 -19
  33. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  34. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +80 -17
  35. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +32 -57
  36. imap_processing/cdf/utils.py +52 -38
  37. imap_processing/cli.py +477 -233
  38. imap_processing/codice/codice_l1a.py +466 -131
  39. imap_processing/codice/codice_l1b.py +51 -152
  40. imap_processing/codice/constants.py +1360 -569
  41. imap_processing/codice/decompress.py +2 -6
  42. imap_processing/ena_maps/ena_maps.py +1103 -146
  43. imap_processing/ena_maps/utils/coordinates.py +19 -0
  44. imap_processing/ena_maps/utils/map_utils.py +14 -17
  45. imap_processing/ena_maps/utils/spatial_utils.py +55 -52
  46. imap_processing/glows/l1a/glows_l1a.py +28 -99
  47. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  48. imap_processing/glows/l1b/glows_l1b.py +1 -4
  49. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  50. imap_processing/glows/l2/glows_l2.py +2 -5
  51. imap_processing/hi/l1a/hi_l1a.py +54 -29
  52. imap_processing/hi/l1a/histogram.py +0 -1
  53. imap_processing/hi/l1a/science_direct_event.py +6 -8
  54. imap_processing/hi/l1b/hi_l1b.py +111 -82
  55. imap_processing/hi/l1c/hi_l1c.py +416 -32
  56. imap_processing/hi/utils.py +58 -12
  57. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  58. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  59. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  60. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  61. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  62. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  63. imap_processing/hit/hit_utils.py +235 -5
  64. imap_processing/hit/l0/constants.py +20 -11
  65. imap_processing/hit/l0/decom_hit.py +21 -5
  66. imap_processing/hit/l1a/hit_l1a.py +71 -75
  67. imap_processing/hit/l1b/constants.py +321 -0
  68. imap_processing/hit/l1b/hit_l1b.py +377 -67
  69. imap_processing/hit/l2/constants.py +318 -0
  70. imap_processing/hit/l2/hit_l2.py +723 -0
  71. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  72. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  73. imap_processing/ialirt/l0/parse_mag.py +374 -0
  74. imap_processing/ialirt/l0/process_swapi.py +69 -0
  75. imap_processing/ialirt/l0/process_swe.py +548 -0
  76. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -208
  77. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  78. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  79. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  80. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  81. imap_processing/ialirt/utils/grouping.py +114 -0
  82. imap_processing/ialirt/utils/time.py +29 -0
  83. imap_processing/idex/atomic_masses.csv +22 -0
  84. imap_processing/idex/decode.py +2 -2
  85. imap_processing/idex/idex_constants.py +33 -0
  86. imap_processing/idex/idex_l0.py +22 -8
  87. imap_processing/idex/idex_l1a.py +81 -51
  88. imap_processing/idex/idex_l1b.py +13 -39
  89. imap_processing/idex/idex_l2a.py +823 -0
  90. imap_processing/idex/idex_l2b.py +120 -0
  91. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +11 -11
  92. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  93. imap_processing/lo/l0/lo_science.py +7 -2
  94. imap_processing/lo/l1a/lo_l1a.py +1 -5
  95. imap_processing/lo/l1b/lo_l1b.py +702 -29
  96. imap_processing/lo/l1b/tof_conversions.py +11 -0
  97. imap_processing/lo/l1c/lo_l1c.py +1 -4
  98. imap_processing/mag/constants.py +51 -0
  99. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  100. imap_processing/mag/l0/decom_mag.py +10 -3
  101. imap_processing/mag/l1a/mag_l1a.py +23 -19
  102. imap_processing/mag/l1a/mag_l1a_data.py +35 -10
  103. imap_processing/mag/l1b/mag_l1b.py +259 -50
  104. imap_processing/mag/l1c/interpolation_methods.py +388 -0
  105. imap_processing/mag/l1c/mag_l1c.py +621 -17
  106. imap_processing/mag/l2/mag_l2.py +140 -0
  107. imap_processing/mag/l2/mag_l2_data.py +288 -0
  108. imap_processing/quality_flags.py +1 -0
  109. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  110. imap_processing/spacecraft/quaternions.py +121 -0
  111. imap_processing/spice/geometry.py +19 -22
  112. imap_processing/spice/kernels.py +0 -276
  113. imap_processing/spice/pointing_frame.py +257 -0
  114. imap_processing/spice/repoint.py +149 -0
  115. imap_processing/spice/spin.py +38 -33
  116. imap_processing/spice/time.py +24 -0
  117. imap_processing/swapi/l1/swapi_l1.py +20 -12
  118. imap_processing/swapi/l2/swapi_l2.py +116 -5
  119. imap_processing/swapi/swapi_utils.py +32 -0
  120. imap_processing/swe/l1a/swe_l1a.py +44 -12
  121. imap_processing/swe/l1a/swe_science.py +13 -13
  122. imap_processing/swe/l1b/swe_l1b.py +898 -23
  123. imap_processing/swe/l2/swe_l2.py +75 -136
  124. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  125. imap_processing/swe/utils/swe_constants.py +64 -0
  126. imap_processing/swe/utils/swe_utils.py +85 -28
  127. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  128. imap_processing/tests/ccsds/test_excel_to_xtce.py +24 -21
  129. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  130. imap_processing/tests/cdf/test_utils.py +14 -16
  131. imap_processing/tests/codice/conftest.py +44 -33
  132. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  133. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  134. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  135. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  136. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  137. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  138. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  139. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  140. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  141. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  142. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  143. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  144. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  145. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  146. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  147. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  148. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  149. imap_processing/tests/codice/test_codice_l1a.py +126 -53
  150. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  151. imap_processing/tests/codice/test_decompress.py +4 -4
  152. imap_processing/tests/conftest.py +239 -27
  153. imap_processing/tests/ena_maps/conftest.py +51 -0
  154. imap_processing/tests/ena_maps/test_ena_maps.py +1068 -110
  155. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  156. imap_processing/tests/ena_maps/test_spatial_utils.py +17 -21
  157. imap_processing/tests/glows/conftest.py +10 -14
  158. imap_processing/tests/glows/test_glows_decom.py +4 -4
  159. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  160. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  161. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  162. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  163. imap_processing/tests/glows/test_glows_l2.py +2 -8
  164. imap_processing/tests/hi/conftest.py +1 -1
  165. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  166. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  167. imap_processing/tests/hi/test_hi_l1b.py +22 -27
  168. imap_processing/tests/hi/test_hi_l1c.py +249 -18
  169. imap_processing/tests/hi/test_l1a.py +35 -7
  170. imap_processing/tests/hi/test_science_direct_event.py +3 -3
  171. imap_processing/tests/hi/test_utils.py +24 -2
  172. imap_processing/tests/hit/helpers/l1_validation.py +74 -73
  173. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  174. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  175. imap_processing/tests/hit/test_decom_hit.py +5 -1
  176. imap_processing/tests/hit/test_hit_l1a.py +32 -36
  177. imap_processing/tests/hit/test_hit_l1b.py +300 -81
  178. imap_processing/tests/hit/test_hit_l2.py +716 -0
  179. imap_processing/tests/hit/test_hit_utils.py +184 -7
  180. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  181. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  182. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  183. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  184. imap_processing/tests/ialirt/data/l0/461971383-404.bin +0 -0
  185. imap_processing/tests/ialirt/data/l0/461971384-405.bin +0 -0
  186. imap_processing/tests/ialirt/data/l0/461971385-406.bin +0 -0
  187. imap_processing/tests/ialirt/data/l0/461971386-407.bin +0 -0
  188. imap_processing/tests/ialirt/data/l0/461971387-408.bin +0 -0
  189. imap_processing/tests/ialirt/data/l0/461971388-409.bin +0 -0
  190. imap_processing/tests/ialirt/data/l0/461971389-410.bin +0 -0
  191. imap_processing/tests/ialirt/data/l0/461971390-411.bin +0 -0
  192. imap_processing/tests/ialirt/data/l0/461971391-412.bin +0 -0
  193. imap_processing/tests/ialirt/data/l0/sample_decoded_i-alirt_data.csv +383 -0
  194. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  195. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  196. imap_processing/tests/ialirt/unit/test_parse_mag.py +223 -0
  197. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  198. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  199. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  200. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  201. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  202. imap_processing/tests/ialirt/unit/test_process_swe.py +319 -6
  203. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  204. imap_processing/tests/idex/conftest.py +127 -6
  205. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  206. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  207. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  208. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  209. imap_processing/tests/idex/test_idex_l0.py +33 -11
  210. imap_processing/tests/idex/test_idex_l1a.py +92 -21
  211. imap_processing/tests/idex/test_idex_l1b.py +106 -27
  212. imap_processing/tests/idex/test_idex_l2a.py +399 -0
  213. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  214. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  215. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  216. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  217. imap_processing/tests/lo/test_lo_l1b.py +515 -6
  218. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  219. imap_processing/tests/lo/test_lo_science.py +7 -7
  220. imap_processing/tests/lo/test_star_sensor.py +1 -1
  221. imap_processing/tests/mag/conftest.py +120 -2
  222. imap_processing/tests/mag/test_mag_decom.py +5 -4
  223. imap_processing/tests/mag/test_mag_l1a.py +51 -7
  224. imap_processing/tests/mag/test_mag_l1b.py +40 -59
  225. imap_processing/tests/mag/test_mag_l1c.py +354 -19
  226. imap_processing/tests/mag/test_mag_l2.py +130 -0
  227. imap_processing/tests/mag/test_mag_validation.py +247 -26
  228. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  229. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  230. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  231. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  232. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  233. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  234. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  235. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  236. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  237. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  238. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  239. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  240. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  241. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  242. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  243. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  244. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  245. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  246. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  247. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  248. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  249. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  250. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  251. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  252. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  253. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  254. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  255. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  256. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  257. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  258. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  259. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  260. imap_processing/tests/mag/validation/calibration/imap_mag_l1b-calibration_20240229_v001.cdf +0 -0
  261. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  262. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  263. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  264. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  265. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  266. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  267. imap_processing/tests/spice/test_geometry.py +9 -12
  268. imap_processing/tests/spice/test_kernels.py +1 -200
  269. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  270. imap_processing/tests/spice/test_repoint.py +121 -0
  271. imap_processing/tests/spice/test_spin.py +50 -9
  272. imap_processing/tests/spice/test_time.py +14 -0
  273. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  274. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  275. imap_processing/tests/swapi/test_swapi_l1.py +13 -11
  276. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  277. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  278. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  279. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  280. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  281. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  282. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  283. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  284. imap_processing/tests/swe/test_swe_l1a.py +20 -2
  285. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  286. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  287. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  288. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  289. imap_processing/tests/swe/test_swe_l2.py +153 -91
  290. imap_processing/tests/test_cli.py +171 -88
  291. imap_processing/tests/test_utils.py +140 -17
  292. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  293. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  294. imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3243 -3243
  295. imap_processing/tests/ultra/data/mock_data.py +369 -0
  296. imap_processing/tests/ultra/unit/conftest.py +115 -89
  297. imap_processing/tests/ultra/unit/test_badtimes.py +4 -4
  298. imap_processing/tests/ultra/unit/test_cullingmask.py +8 -6
  299. imap_processing/tests/ultra/unit/test_de.py +14 -13
  300. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  301. imap_processing/tests/ultra/unit/test_decom_apid_881.py +54 -11
  302. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  303. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  304. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  305. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +77 -0
  306. imap_processing/tests/ultra/unit/test_ultra_l1a.py +98 -305
  307. imap_processing/tests/ultra/unit/test_ultra_l1b.py +60 -14
  308. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  309. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +26 -27
  310. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +239 -70
  311. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  312. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +114 -83
  313. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  314. imap_processing/ultra/constants.py +1 -1
  315. imap_processing/ultra/l0/decom_tools.py +27 -39
  316. imap_processing/ultra/l0/decom_ultra.py +168 -204
  317. imap_processing/ultra/l0/ultra_utils.py +152 -136
  318. imap_processing/ultra/l1a/ultra_l1a.py +55 -271
  319. imap_processing/ultra/l1b/badtimes.py +1 -4
  320. imap_processing/ultra/l1b/cullingmask.py +2 -6
  321. imap_processing/ultra/l1b/de.py +116 -57
  322. imap_processing/ultra/l1b/extendedspin.py +20 -18
  323. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  324. imap_processing/ultra/l1b/ultra_l1b.py +36 -16
  325. imap_processing/ultra/l1b/ultra_l1b_culling.py +66 -30
  326. imap_processing/ultra/l1b/ultra_l1b_extended.py +297 -94
  327. imap_processing/ultra/l1c/histogram.py +2 -6
  328. imap_processing/ultra/l1c/spacecraft_pset.py +84 -0
  329. imap_processing/ultra/l1c/ultra_l1c.py +8 -9
  330. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +206 -108
  331. imap_processing/ultra/l2/ultra_l2.py +299 -0
  332. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  333. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  334. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  335. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  336. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  337. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  338. imap_processing/ultra/packet_definitions/README.md +38 -0
  339. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  340. imap_processing/ultra/utils/ultra_l1_utils.py +31 -12
  341. imap_processing/utils.py +69 -29
  342. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +10 -6
  343. imap_processing-0.13.0.dist-info/RECORD +578 -0
  344. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  345. imap_processing/hi/l1a/housekeeping.py +0 -27
  346. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  347. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  348. imap_processing/swe/l1b/swe_l1b_science.py +0 -652
  349. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  350. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  351. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  352. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  353. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  354. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  355. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  356. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  357. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  358. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  359. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  360. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  361. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  362. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  363. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  364. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  365. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  366. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  367. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  368. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  369. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  370. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  371. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  372. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  373. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  374. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  375. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  376. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  377. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  378. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  379. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  380. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  381. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  382. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  383. imap_processing/tests/swe/test_swe_l1b_science.py +0 -84
  384. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  385. imap_processing/ultra/l1c/pset.py +0 -40
  386. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  387. imap_processing-0.11.0.dist-info/RECORD +0 -488
  388. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  389. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  390. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  391. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  392. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  393. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  394. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  395. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  396. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  397. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  398. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  399. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  400. /imap_processing/{mag/l1b → tests/spacecraft}/__init__.py +0 -0
  401. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  402. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  403. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  404. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  405. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  406. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  407. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  408. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  409. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  410. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  411. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  412. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  413. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  414. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  415. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -1,17 +1,24 @@
1
1
  """IMAP-Lo L1B Data Processing."""
2
2
 
3
- from collections import namedtuple
4
3
  from dataclasses import Field
5
4
  from pathlib import Path
5
+ from typing import Any, Union
6
6
 
7
7
  import numpy as np
8
8
  import xarray as xr
9
9
 
10
10
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
- from imap_processing.spice.time import met_to_ttj2000ns
11
+ from imap_processing.lo.l1b.tof_conversions import (
12
+ TOF0_CONV,
13
+ TOF1_CONV,
14
+ TOF2_CONV,
15
+ TOF3_CONV,
16
+ )
17
+ from imap_processing.spice.geometry import SpiceFrame, instrument_pointing
18
+ from imap_processing.spice.time import met_to_ttj2000ns, ttj2000ns_to_et
12
19
 
13
20
 
14
- def lo_l1b(dependencies: dict, data_version: str) -> list[Path]:
21
+ def lo_l1b(dependencies: dict) -> list[Path]:
15
22
  """
16
23
  Will process IMAP-Lo L1A data into L1B CDF data products.
17
24
 
@@ -19,8 +26,6 @@ def lo_l1b(dependencies: dict, data_version: str) -> list[Path]:
19
26
  ----------
20
27
  dependencies : dict
21
28
  Dictionary of datasets needed for L1B data product creation in xarray Datasets.
22
- data_version : str
23
- Version of the data product being created.
24
29
 
25
30
  Returns
26
31
  -------
@@ -28,35 +33,703 @@ def lo_l1b(dependencies: dict, data_version: str) -> list[Path]:
28
33
  Location of created CDF files.
29
34
  """
30
35
  # create the attribute manager for this data level
31
- attr_mgr = ImapCdfAttributes()
32
- attr_mgr.add_instrument_global_attrs(instrument="lo")
33
- attr_mgr.add_instrument_variable_attrs(instrument="lo", level="l1b")
34
- attr_mgr.add_global_attribute("Data_version", data_version)
36
+ attr_mgr_l1b = ImapCdfAttributes()
37
+ attr_mgr_l1b.add_instrument_global_attrs(instrument="lo")
38
+ attr_mgr_l1b.add_instrument_variable_attrs(instrument="lo", level="l1b")
39
+ # create the attribute manager to access L1A fillval attributes
40
+ attr_mgr_l1a = ImapCdfAttributes()
41
+ attr_mgr_l1a.add_instrument_variable_attrs(instrument="lo", level="l1a")
35
42
 
36
43
  # if the dependencies are used to create Annotated Direct Events
37
-
38
44
  if "imap_lo_l1a_de" in dependencies and "imap_lo_l1a_spin" in dependencies:
39
45
  logical_source = "imap_lo_l1b_de"
40
- # TODO: TEMPORARY. Need to update to use the L1B data class once that exists
41
- # and I have sample data.
42
- data_field_tup = namedtuple("data_field_tup", ["name"])
43
- data_fields = [
44
- data_field_tup("ESA_STEP"),
45
- data_field_tup("MODE"),
46
- data_field_tup("TOF0"),
47
- data_field_tup("TOF1"),
48
- data_field_tup("TOF2"),
49
- data_field_tup("TOF3"),
50
- data_field_tup("COINCIDENCE_TYPE"),
51
- data_field_tup("POS"),
52
- data_field_tup("COINCIDENCE"),
53
- data_field_tup("BADTIME"),
54
- data_field_tup("DIRECTION"),
55
- ]
46
+ # get the dependency dataset for l1b direct events
47
+ l1a_de = dependencies["imap_lo_l1a_de"]
48
+ spin_data = dependencies["imap_lo_l1a_spin"]
56
49
 
57
- dataset: list[Path] = create_datasets(attr_mgr, logical_source, data_fields) # type: ignore[arg-type]
58
- # TODO Remove once data_fields is removed from create_datasets
59
- return dataset
50
+ # Initialize the L1B DE dataset
51
+ l1b_de = initialize_l1b_de(l1a_de, attr_mgr_l1b, logical_source)
52
+ # Get the start and end times for each spin epoch
53
+ acq_start, acq_end = convert_start_end_acq_times(spin_data)
54
+ # Get the average spin durations for each epoch
55
+ avg_spin_durations = get_avg_spin_durations(acq_start, acq_end)
56
+ # get spin angle (0 - 360 degrees) for each DE
57
+ spin_angle = get_spin_angle(l1a_de)
58
+ # calculate and set the spin bin based on the spin angle
59
+ # spin bins are 0 - 60 bins
60
+ l1b_de = set_spin_bin(l1b_de, spin_angle)
61
+ # set the spin cycle for each direct event
62
+ l1b_de = set_spin_cycle(l1a_de, l1b_de)
63
+ # get spin start times for each event
64
+ spin_start_time = get_spin_start_times(l1a_de, l1b_de, spin_data, acq_end)
65
+ # get the absolute met for each event
66
+ l1b_de = set_event_met(l1a_de, l1b_de, spin_start_time, avg_spin_durations)
67
+ # set the epoch for each event
68
+ l1b_de = set_each_event_epoch(l1b_de)
69
+ # calculate the TOF1 for golden triples
70
+ # store in the l1a dataset to use in l1b calculations
71
+ l1a_de = calculate_tof1_for_golden_triples(l1a_de)
72
+ # set the coincidence type string for each direct event
73
+ l1b_de = set_coincidence_type(l1a_de, l1b_de, attr_mgr_l1a)
74
+ # convert the TOFs to engineering units
75
+ l1b_de = convert_tofs_to_eu(l1a_de, l1b_de, attr_mgr_l1a, attr_mgr_l1b)
76
+ # set the species for each direct event
77
+ l1b_de = identify_species(l1b_de)
78
+ # set the badtimes
79
+ l1b_de = set_bad_times(l1b_de)
80
+ # set the pointing direction for each direct event
81
+ l1b_de = set_pointing_direction(l1b_de)
82
+ # calculate and set the pointing bin based on the spin phase
83
+ # pointing bin is 3600 x 40 bins
84
+ l1b_de = set_pointing_bin(l1b_de)
85
+
86
+ return [l1b_de]
87
+
88
+
89
+ def initialize_l1b_de(
90
+ l1a_de: xr.Dataset, attr_mgr_l1b: ImapCdfAttributes, logical_source: str
91
+ ) -> xr.Dataset:
92
+ """
93
+ Initialize the L1B DE dataset.
94
+
95
+ Create an empty L1B DE dataset and copy over fields from the L1A DE that will
96
+ not change during L1B processing.
97
+
98
+ Parameters
99
+ ----------
100
+ l1a_de : xarray.Dataset
101
+ The L1A DE dataset.
102
+ attr_mgr_l1b : ImapCdfAttributes
103
+ Attribute manager used to get the global attributes for the L1B DE dataset.
104
+ logical_source : str
105
+ The logical source of the direct event product.
106
+
107
+ Returns
108
+ -------
109
+ l1b_de : xarray.Dataset
110
+ The initialized L1B DE dataset.
111
+ """
112
+ l1b_de = xr.Dataset(
113
+ attrs=attr_mgr_l1b.get_global_attributes(logical_source),
114
+ )
115
+
116
+ # Copy over fields from L1A DE that will not change in L1B processing
117
+ l1b_de["pos"] = xr.DataArray(
118
+ l1a_de["pos"].values,
119
+ dims=["epoch"],
120
+ # TODO: Add pos to YAML file
121
+ # attrs=attr_mgr.get_variable_attributes("pos"),
122
+ )
123
+ l1b_de["mode"] = xr.DataArray(
124
+ l1a_de["mode"].values,
125
+ dims=["epoch"],
126
+ # TODO: Add mode to YAML file
127
+ # attrs=attr_mgr.get_variable_attributes("mode"),
128
+ )
129
+ l1b_de["absent"] = xr.DataArray(
130
+ l1a_de["coincidence_type"].values,
131
+ dims=["epoch"],
132
+ # TODO: Add absent to YAML file
133
+ # attrs=attr_mgr.get_variable_attributes("absent"),
134
+ )
135
+ l1b_de["esa_step"] = xr.DataArray(
136
+ l1a_de["esa_step"].values,
137
+ dims=["epoch"],
138
+ # TODO: Add esa_step to YAML file
139
+ # attrs=attr_mgr.get_variable_attributes("esa_step"),
140
+ )
141
+
142
+ return l1b_de
143
+
144
+
145
+ def convert_start_end_acq_times(
146
+ spin_data: xr.Dataset,
147
+ ) -> tuple[xr.DataArray, xr.DataArray]:
148
+ """
149
+ Convert the start and end times from the spin data.
150
+
151
+ The L1A spin data start and end acquisition times are stored in seconds and
152
+ subseconds (microseconds). This function converts them to a single time in seconds.
153
+
154
+ Parameters
155
+ ----------
156
+ spin_data : xarray.Dataset
157
+ The L1A Spin dataset containing the start and end acquisition times.
158
+
159
+ Returns
160
+ -------
161
+ tuple[xr.DataArray, xr.DataArray]
162
+ A tuple containing the start and end acquisition times as xarray DataArrays.
163
+ """
164
+ # Convert subseconds from microseconds to seconds
165
+ acq_start = spin_data["acq_start_sec"] + spin_data["acq_start_subsec"] * 1e-6
166
+ acq_end = spin_data["acq_end_sec"] + spin_data["acq_end_subsec"] * 1e-6
167
+ return (acq_start, acq_end)
168
+
169
+
170
+ def get_avg_spin_durations(
171
+ acq_start: xr.DataArray, acq_end: xr.DataArray
172
+ ) -> xr.DataArray:
173
+ """
174
+ Get the average spin duration for each spin epoch.
175
+
176
+ Parameters
177
+ ----------
178
+ acq_start : xarray.DataArray
179
+ The start acquisition times for each spin epoch.
180
+ acq_end : xarray.DataArray
181
+ The end acquisition times for each spin epoch.
182
+
183
+ Returns
184
+ -------
185
+ avg_spin_durations : xarray.DataArray
186
+ The average spin duration for each spin epoch.
187
+ """
188
+ # Get the avg spin duration for each spin epoch
189
+ # There are 28 spins per epoch (1 aggregated science cycle)
190
+ avg_spin_durations = (acq_end - acq_start) / 28
191
+ return avg_spin_durations
192
+
193
+
194
+ def get_spin_angle(l1a_de: xr.Dataset) -> Union[np.ndarray[np.float64], Any]:
195
+ """
196
+ Get the spin angle (0 - 360 degrees) for each DE.
197
+
198
+ Parameters
199
+ ----------
200
+ l1a_de : xarray.Dataset
201
+ The L1A DE dataset.
202
+
203
+ Returns
204
+ -------
205
+ spin_angle : np.ndarray
206
+ The spin angle for each DE.
207
+ """
208
+ de_times = l1a_de["de_time"].values
209
+ # DE Time is 12 bit DN. The max possible value is 4096
210
+ spin_angle = np.array(de_times / 4096 * 360, dtype=np.float64)
211
+ return spin_angle
212
+
213
+
214
+ def set_spin_bin(l1b_de: xr.Dataset, spin_angle: np.ndarray) -> xr.Dataset:
215
+ """
216
+ Set the spin bin (0 - 60 bins) for each Direct Event where each bin is 6 degrees.
217
+
218
+ Parameters
219
+ ----------
220
+ l1b_de : xarray.Dataset
221
+ The L1B Direct Event dataset.
222
+ spin_angle : np.ndarray
223
+ The spin angle (0-360 degrees) for each Direct Event.
224
+
225
+ Returns
226
+ -------
227
+ l1b_de : xarray.Dataset
228
+ The L1B DE dataset with the spin bin added.
229
+ """
230
+ # Get the spin bin for each DE
231
+ # Spin bins are 0 - 60 where each bin is 6 degrees
232
+ spin_bin = (spin_angle // 6).astype(int)
233
+ l1b_de["spin_bin"] = xr.DataArray(
234
+ spin_bin,
235
+ dims=["epoch"],
236
+ # TODO: Add spin angle to YAML file
237
+ # attrs=attr_mgr.get_variable_attributes("spin_bin"),
238
+ )
239
+ return l1b_de
240
+
241
+
242
+ def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
243
+ """
244
+ Set the spin cycle for each direct event.
245
+
246
+ spin_cycle = spin_start + 7 + (esa_step - 1) * 2
247
+
248
+ where spin_start is the spin number for the first spin
249
+ in an Aggregated Science Cycle (ASC) and esa_step is the esa_step for a direct event
250
+
251
+ The 28 spins in a spin epoch spans one ASC.
252
+
253
+ Parameters
254
+ ----------
255
+ l1a_de : xarray.Dataset
256
+ The L1A DE dataset.
257
+ l1b_de : xarray.Dataset
258
+ The L1B DE dataset.
259
+
260
+ Returns
261
+ -------
262
+ l1b_de : xarray.Dataset
263
+ The L1B DE dataset with the spin cycle added for each direct event.
264
+ """
265
+ counts = l1a_de["de_count"].values
266
+ # split the esa_steps into ASC groups
267
+ de_asc_groups = np.split(l1a_de["esa_step"].values, np.cumsum(counts)[:-1])
268
+ spin_cycle = []
269
+ for i, esa_asc_group in enumerate(de_asc_groups):
270
+ # TODO: Spin Number does not reset for each pointing. Need to figure out
271
+ # how to retain this information across days
272
+ # increment the spin_start by 28 after each aggregated science cycle
273
+ spin_start = i * 28
274
+ # calculate the spin cycle for each DE in the ASC group
275
+ # TODO: Add equation number in algorithm document when new version is
276
+ # available. Add to docstring as well
277
+ spin_cycle.extend(spin_start + 7 + (esa_asc_group - 1) * 2)
278
+
279
+ l1b_de["spin_cycle"] = xr.DataArray(
280
+ spin_cycle,
281
+ dims=["epoch"],
282
+ # TODO: Add spin cycle to YAML file
283
+ # attrs=attr_mgr.get_variable_attributes("spin_cycle"),
284
+ )
285
+
286
+ return l1b_de
287
+
288
+
289
+ def get_spin_start_times(
290
+ l1a_de: xr.Dataset, l1b_de: xr.Dataset, spin_data: xr.Dataset, acq_end: xr.DataArray
291
+ ) -> xr.DataArray:
292
+ """
293
+ Get the start time for the spin that each direct event is in.
294
+
295
+ The resulting array of spin start times will be equal to the length of the direct
296
+ events. If two direct events occurred in the same spin, then there will be repeating
297
+ spin start times.
298
+
299
+ Parameters
300
+ ----------
301
+ l1a_de : xr.Dataset
302
+ The L1A DE dataset.
303
+ l1b_de : xr.Dataset
304
+ The L1B DE dataset.
305
+ spin_data : xr.Dataset
306
+ The L1A Spin dataset.
307
+ acq_end : xr.DataArray
308
+ The end acquisition times for each spin ASC.
309
+
310
+ Returns
311
+ -------
312
+ spin_start_time : xr.DataArray
313
+ The start time for the spin that each direct event is in.
314
+ """
315
+ met = l1a_de["met"].values
316
+ # Find the closest stop_acq for each shcoarse
317
+ closest_stop_acq_indices = np.abs(met[:, None] - acq_end.values).argmin(axis=1)
318
+ # There are 28 spins per epoch (1 aggregated science cycle)
319
+ # Set the spin_cycle_num to the spin number relative to the
320
+ # start of the ASC
321
+ spin_cycle_num = l1b_de["spin_cycle"] % 28
322
+ # Get the seconds portion of the start time for each spin
323
+ start_sec_spins = spin_data["start_sec_spin"].values[
324
+ closest_stop_acq_indices, spin_cycle_num
325
+ ]
326
+ # Get the subseconds portion of the spin start time and convert from
327
+ # microseconds to seconds
328
+ start_subsec_spins = (
329
+ spin_data["start_subsec_spin"].values[closest_stop_acq_indices, spin_cycle_num]
330
+ * 1e-6
331
+ )
332
+
333
+ # Combine the seconds and subseconds to get the start time for each spin
334
+ spin_start_time = start_sec_spins + start_subsec_spins
335
+ return xr.DataArray(spin_start_time)
336
+
337
+
338
+ def set_event_met(
339
+ l1a_de: xr.Dataset,
340
+ l1b_de: xr.Dataset,
341
+ spin_start_time: xr.DataArray,
342
+ avg_spin_durations: xr.DataArray,
343
+ ) -> xr.Dataset:
344
+ """
345
+ Get the event MET for each direct event.
346
+
347
+ Each direct event is converted from a data number to engineering unit in seconds.
348
+ de_eu_time de_dn_time / 4096 * avg_spin_duration
349
+ where de_time is the direct event time Data Number (DN) and avg_spin_duration
350
+ is the average spin duration for the ASC that the event was measured in.
351
+
352
+ The direct event time is the time of direct event relative to the start of the spin.
353
+ The event MET is the sum of the start time of the spin and the
354
+ direct event EU time.
355
+
356
+ Parameters
357
+ ----------
358
+ l1a_de : xr.Dataset
359
+ The L1A DE dataset.
360
+ l1b_de : xr.Dataset
361
+ The L1B DE dataset.
362
+ spin_start_time : np.ndarray
363
+ The start time for the spin that each direct event is in.
364
+ avg_spin_durations : xr.DataArray
365
+ The average spin duration for each epoch.
366
+
367
+ Returns
368
+ -------
369
+ l1b_de : xr.Dataset
370
+ The L1B DE dataset with the event MET.
371
+ """
372
+ counts = l1a_de["de_count"].values
373
+ de_time_asc_groups = np.split(l1a_de["de_time"].values, np.cumsum(counts)[:-1])
374
+ de_times_eu = []
375
+ for i, de_time_asc in enumerate(de_time_asc_groups):
376
+ # DE Time is 12 bit DN. The max possible value is 4095
377
+ # divide by 4096 to get fraction of a spin duration
378
+ de_times_eu.extend(de_time_asc / 4096 * avg_spin_durations[i].values)
379
+
380
+ l1b_de["event_met"] = xr.DataArray(
381
+ spin_start_time + de_times_eu,
382
+ dims=["epoch"],
383
+ # attrs=attr_mgr.get_variable_attributes("epoch")
384
+ )
385
+ return l1b_de
386
+
387
+
388
+ def set_each_event_epoch(l1b_de: xr.Dataset) -> xr.Dataset:
389
+ """
390
+ Set the epoch for each direct event.
391
+
392
+ Parameters
393
+ ----------
394
+ l1b_de : xr.Dataset
395
+ The L1B DE dataset.
396
+
397
+ Returns
398
+ -------
399
+ l1b_de : xr.Dataset
400
+ The L1B DE dataset with the epoch set for each event.
401
+ """
402
+ l1b_de["epoch"] = xr.DataArray(
403
+ met_to_ttj2000ns(l1b_de["event_met"].values),
404
+ dims=["epoch"],
405
+ # attrs=attr_mgr.get_variable_attributes("epoch")
406
+ )
407
+ return l1b_de
408
+
409
+
410
+ def calculate_tof1_for_golden_triples(l1a_de: xr.Dataset) -> xr.Dataset:
411
+ """
412
+ Calculate the TOF1 for golden triples.
413
+
414
+ TOF1 is not transmitted for golden triples, but is recovered on the
415
+ ground using the TOF0, TOF2, TOF3, and CKSUM values. The equation is:
416
+ TOF1 = (TOF0 + TOF3 - TOF2 - CKSUM - left_cksm_bound) << 1
417
+
418
+ where left_cksm_bound is the left checksum boundary value. This is a
419
+ constant value that is not transmitted in the telemetry.
420
+
421
+ Parameters
422
+ ----------
423
+ l1a_de : xr.Dataset
424
+ The L1A DE dataset.
425
+
426
+ Returns
427
+ -------
428
+ l1a_de : xr.Dataset
429
+ The L1A DE dataset with the TOF1 calculated for golden triples.
430
+ """
431
+ for idx, coin_type in enumerate(l1a_de["coincidence_type"].values):
432
+ if coin_type == 0 and l1a_de["mode"][idx] == 0:
433
+ # Calculate TOF1
434
+ # TOF1 equation requires values to be right bit shifted. These values were
435
+ # originally right bit shifted when packed in the telemetry packet, but were
436
+ # left bit shifted for the L1A product. Need to right bit shift them again
437
+ # to apply the TOF1 equation
438
+ tof0 = l1a_de["tof0"][idx] >> 1
439
+ tof2 = l1a_de["tof2"][idx] >> 1
440
+ tof3 = l1a_de["tof3"][idx] >> 1
441
+ cksm = l1a_de["cksm"][idx] >> 1
442
+ # TODO: will get left checksum boundary from LUT table when available
443
+ left_cksm_bound = -21
444
+ # Calculate TOF1, then left bit shift it to store it with the rest of the
445
+ # left shifted L1A dataset data.
446
+ l1a_de["tof1"][idx] = (tof0 + tof3 - tof2 - cksm - left_cksm_bound) << 1
447
+ return l1a_de
448
+
449
+
450
+ def set_coincidence_type(
451
+ l1a_de: xr.Dataset,
452
+ l1b_de: xr.Dataset,
453
+ attr_mgr_l1a: ImapCdfAttributes,
454
+ ) -> xr.Dataset:
455
+ """
456
+ Set the coincidence type for each direct event.
457
+
458
+ The coincidence type is a string that indicates the type of coincidence
459
+ for each direct event. The string is a combination of the following depending
460
+ on whether the TOF or CKSM value is present (1) or absent (0) and the value
461
+ of the mode for each direct event:
462
+ "<TOF0><TOF1><TOF2><TOF3><CKSM><Mode>"
463
+
464
+ Parameters
465
+ ----------
466
+ l1a_de : xarray.Dataset
467
+ The L1A DE dataset.
468
+ l1b_de : xarray.Dataset
469
+ The L1B DE dataset.
470
+ attr_mgr_l1a : ImapCdfAttributes
471
+ Attribute manager used to get the fill values for the L1A DE dataset.
472
+
473
+ Returns
474
+ -------
475
+ l1b_de : xarray.Dataset
476
+ The L1B DE dataset with the coincidence type added.
477
+ """
478
+ tof0_fill = attr_mgr_l1a.get_variable_attributes("tof0")["FILLVAL"]
479
+ tof0_mask = (l1a_de["tof0"].values != tof0_fill).astype(int)
480
+ tof1_fill = attr_mgr_l1a.get_variable_attributes("tof1")["FILLVAL"]
481
+ tof1_mask = (l1a_de["tof1"].values != tof1_fill).astype(int)
482
+ tof2_fill = attr_mgr_l1a.get_variable_attributes("tof2")["FILLVAL"]
483
+ tof2_mask = (l1a_de["tof2"].values != tof2_fill).astype(int)
484
+ tof3_fill = attr_mgr_l1a.get_variable_attributes("tof3")["FILLVAL"]
485
+ tof3_mask = (l1a_de["tof3"].values != tof3_fill).astype(int)
486
+ cksm_fill = attr_mgr_l1a.get_variable_attributes("cksm")["FILLVAL"]
487
+ cksm_mask = (l1a_de["cksm"].values != cksm_fill).astype(int)
488
+
489
+ coincidence_type = [
490
+ f"{tof0_mask[i]}{tof1_mask[i]}{tof2_mask[i]}{tof3_mask[i]}{cksm_mask[i]}{l1a_de['mode'].values[i]}"
491
+ for i in range(len(l1a_de["direct_events"]))
492
+ ]
493
+
494
+ l1b_de["coincidence_type"] = xr.DataArray(
495
+ coincidence_type,
496
+ dims=["epoch"],
497
+ # TODO: Add coincidence_type to YAML file
498
+ # attrs=attr_mgr.get_variable_attributes("spin_cycle"),
499
+ )
500
+
501
+ return l1b_de
502
+
503
+
504
+ def convert_tofs_to_eu(
505
+ l1a_de: xr.Dataset,
506
+ l1b_de: xr.Dataset,
507
+ attr_mgr_l1a: ImapCdfAttributes,
508
+ attr_mgr_l1b: ImapCdfAttributes,
509
+ ) -> xr.Dataset:
510
+ """
511
+ Convert the TOFs to engineering units.
512
+
513
+ The TOFs are converted from data numbers (DN) to engineering units (EU) using the
514
+ following equation:
515
+ TOF_EU = C0 + C1 * TOF_DN
516
+
517
+ where C0 and C1 are the conversion coefficients for each TOF.
518
+
519
+ This equation is applied to all four TOFs (TOF0, TOF1, TOF2, TOF3).
520
+
521
+ Parameters
522
+ ----------
523
+ l1a_de : xarray.Dataset
524
+ The L1A DE dataset.
525
+ l1b_de : xarray.Dataset
526
+ The L1B DE dataset.
527
+ attr_mgr_l1a : ImapCdfAttributes
528
+ Attribute manager used to get the fill values for the L1A DE dataset.
529
+ attr_mgr_l1b : ImapCdfAttributes
530
+ Attribute manager used to get the fill values for the L1B DE dataset.
531
+
532
+ Returns
533
+ -------
534
+ l1b_de : xarray.Dataset
535
+ The L1B DE dataset with the TOFs converted to engineering units.
536
+ """
537
+ tof_fields = ["tof0", "tof1", "tof2", "tof3"]
538
+ tof_conversions = [TOF0_CONV, TOF1_CONV, TOF2_CONV, TOF3_CONV]
539
+
540
+ # Loop through the TOF fields and convert them to engineering units
541
+ for tof, conv in zip(tof_fields, tof_conversions):
542
+ # Get the fill value for the L1A and L1B TOF
543
+ fillval_1a = attr_mgr_l1a.get_variable_attributes(tof)["FILLVAL"]
544
+ fillval_1b = attr_mgr_l1b.get_variable_attributes(tof)["FILLVAL"]
545
+ # Create a mask for the TOF
546
+ mask = l1a_de[tof] != fillval_1a
547
+ # Convert the DN TOF to EU and add the EU TOF to the dataset.
548
+ # If the TOF is not present, set it to the fill value for the L1B TOF data.
549
+ tof_eu = np.where(
550
+ mask,
551
+ conv.C0 + conv.C1 * l1a_de[tof],
552
+ fillval_1b,
553
+ )
554
+ l1b_de[tof] = xr.DataArray(
555
+ tof_eu,
556
+ dims=["epoch"],
557
+ attrs=attr_mgr_l1b.get_variable_attributes(tof),
558
+ )
559
+
560
+ return l1b_de
561
+
562
+
563
+ def identify_species(l1b_de: xr.Dataset) -> xr.Dataset:
564
+ """
565
+ Identify the species for each direct event.
566
+
567
+ The species are determined using the U_PAC 7-13kV range table with the TOF2 value.
568
+ Each event is set to "H" for Hydrogen, "O" for Oxygen, or "U" for Unknown.
569
+
570
+ See the species identification section in the Lo algorithm document for more
571
+ information on the ranges used to identify the species.
572
+
573
+ Parameters
574
+ ----------
575
+ l1b_de : xarray.Dataset
576
+ The L1B DE dataset.
577
+
578
+ Returns
579
+ -------
580
+ l1b_de : xarray.Dataset
581
+ The L1B DE dataset with the species identified.
582
+ """
583
+ # Define upper and lower ranges for Hydrogen and Oxygen
584
+ # Table defined in 9.3.4.4 of the Lo algorithm document
585
+ # UNH-IMAP-Lo-27850-6002-Data-Product-Algorithms-v9_&_IMAP-LoMappingAlgorithm
586
+ # The ranges are used for U_PAC voltages 7-12kV. Lo does not expect to use
587
+ # voltages outside of that range.
588
+ range_hydrogen = (13, 40)
589
+ range_oxygen = (75, 200)
590
+
591
+ # Initialize the species array with U for Unknown
592
+ species = np.full(len(l1b_de["epoch"]), "U")
593
+
594
+ tof2 = l1b_de["tof2"]
595
+ # Check for range Hydrogen using the TOF2 value
596
+ mask_h = (tof2 >= range_hydrogen[0]) & (tof2 <= range_hydrogen[1])
597
+ species[mask_h] = "H"
598
+
599
+ # Check for range Oxygen using the TOF2 value
600
+ mask_oxygen = (tof2 >= range_oxygen[0]) & (tof2 <= range_oxygen[1])
601
+ species[mask_oxygen] = "O"
602
+
603
+ # Add species to the dataset
604
+ l1b_de["species"] = xr.DataArray(
605
+ species,
606
+ dims=["epoch"],
607
+ # TODO: Add to yaml
608
+ # attrs=attr_mgr.get_variable_attributes("species"),
609
+ )
610
+
611
+ return l1b_de
612
+
613
+
614
+ def set_bad_times(l1b_de: xr.Dataset) -> xr.Dataset:
615
+ """
616
+ Set the bad times for each direct event.
617
+
618
+ Parameters
619
+ ----------
620
+ l1b_de : xarray.Dataset
621
+ The L1B DE dataset.
622
+
623
+ Returns
624
+ -------
625
+ l1b_de : xarray.Dataset
626
+ The L1B DE dataset with the bad times added.
627
+ """
628
+ # Initialize all times as not bad for now
629
+ # TODO: Update to set badtimes based on criteria that
630
+ # will be defined in the algorithm document
631
+ # 1 = badtime, 0 = not badtime
632
+ l1b_de["badtimes"] = xr.DataArray(
633
+ np.zeros(len(l1b_de["epoch"]), dtype=int),
634
+ dims=["epoch"],
635
+ # TODO: Add to yaml
636
+ # attrs=attr_mgr.get_variable_attributes("bad_times"),
637
+ )
638
+
639
+ return l1b_de
640
+
641
+
642
+ def set_pointing_direction(l1b_de: xr.Dataset) -> xr.Dataset:
643
+ """
644
+ Set the pointing direction for each direct event.
645
+
646
+ The pointing direction is determined using the SPICE instrument pointing
647
+ function. The pointing direction are two 1D vectors in units of degrees
648
+ for longitude and latitude sharing the same epoch dimension.
649
+
650
+ Parameters
651
+ ----------
652
+ l1b_de : xarray.Dataset
653
+ The L1B DE dataset.
654
+
655
+ Returns
656
+ -------
657
+ l1b_de : xarray.Dataset
658
+ The L1B DE dataset with the pointing direction added.
659
+ """
660
+ # Get the pointing bin for each DE
661
+ et = ttj2000ns_to_et(l1b_de["epoch"])
662
+
663
+ direction = instrument_pointing(et, SpiceFrame.IMAP_LO_BASE, SpiceFrame.IMAP_DPS)
664
+ # TODO: Need to ask Lo what to do if a latitude is outside of the
665
+ # +/-2 degree range. Is that possible?
666
+ l1b_de["direction_lon"] = xr.DataArray(
667
+ direction[:, 0],
668
+ dims=["epoch"],
669
+ # TODO: Add direction_lon to YAML file
670
+ # attrs=attr_mgr.get_variable_attributes("direction_lon"),
671
+ )
672
+
673
+ l1b_de["direction_lat"] = xr.DataArray(
674
+ direction[:, 1],
675
+ dims=["epoch"],
676
+ # TODO: Add direction_lat to YAML file
677
+ # attrs=attr_mgr.get_variable_attributes("direction_lat"),
678
+ )
679
+
680
+ return l1b_de
681
+
682
+
683
+ def set_pointing_bin(l1b_de: xr.Dataset) -> xr.Dataset:
684
+ """
685
+ Set the pointing bin for each direct event.
686
+
687
+ The pointing bins are defined as 3600 bins for longitude and 40 bins for latitude.
688
+ Each bin is 0.1 degrees. The bins are defined as follows:
689
+ Longitude bins: -180 to 180 degrees
690
+ Latitude bins: -2 to 2 degrees
691
+
692
+ Parameters
693
+ ----------
694
+ l1b_de : xarray.Dataset
695
+ The L1B DE dataset.
696
+
697
+ Returns
698
+ -------
699
+ l1b_de : xarray.Dataset
700
+ The L1B DE dataset with the pointing bins added.
701
+ """
702
+ # First column: latitudes
703
+ lats = l1b_de["direction_lat"]
704
+ # Second column: longitudes
705
+ lons = l1b_de["direction_lon"]
706
+
707
+ # Define bin edges
708
+ # 3600 bins, 0.1° each
709
+ lon_bins = np.linspace(-180, 180, 3601)
710
+ # 40 bins, 0.1° each
711
+ lat_bins = np.linspace(-2, 2, 41)
712
+
713
+ # put the lons and lats into bins
714
+ # shift to 0-based index
715
+ lon_bins = np.digitize(lons, lon_bins) - 1
716
+ lat_bins = np.digitize(lats, lat_bins) - 1
717
+
718
+ l1b_de["pointing_bin_lon"] = xr.DataArray(
719
+ lon_bins,
720
+ dims=["epoch"],
721
+ # TODO: Add pointing_bin_lon to YAML file
722
+ # attrs=attr_mgr.get_variable_attributes("pointing_bin_lon"),
723
+ )
724
+
725
+ l1b_de["pointing_bin_lat"] = xr.DataArray(
726
+ lat_bins,
727
+ dims=["epoch"],
728
+ # TODO: Add point_bin_lat to YAML file
729
+ # attrs=attr_mgr.get_variable_attributes("pointing_bin_lat"),
730
+ )
731
+
732
+ return l1b_de
60
733
 
61
734
 
62
735
  # TODO: This is going to work differently when I sample data.