imap-processing 0.12.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 (272) hide show
  1. imap_processing/__init__.py +1 -0
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +1 -2
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -12
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +569 -0
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +5 -5
  9. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +20 -1
  10. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  11. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  12. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -0
  13. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  14. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +16 -0
  15. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +178 -5
  16. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -19
  18. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +8 -48
  19. imap_processing/cdf/utils.py +41 -33
  20. imap_processing/cli.py +463 -234
  21. imap_processing/codice/codice_l1a.py +260 -47
  22. imap_processing/codice/codice_l1b.py +51 -152
  23. imap_processing/codice/constants.py +38 -1
  24. imap_processing/ena_maps/ena_maps.py +658 -65
  25. imap_processing/ena_maps/utils/coordinates.py +1 -1
  26. imap_processing/ena_maps/utils/spatial_utils.py +10 -5
  27. imap_processing/glows/l1a/glows_l1a.py +28 -99
  28. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  29. imap_processing/glows/l1b/glows_l1b.py +1 -4
  30. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  31. imap_processing/glows/l2/glows_l2.py +2 -5
  32. imap_processing/hi/l1a/hi_l1a.py +31 -12
  33. imap_processing/hi/l1b/hi_l1b.py +80 -43
  34. imap_processing/hi/l1c/hi_l1c.py +12 -16
  35. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  36. imap_processing/hit/hit_utils.py +93 -35
  37. imap_processing/hit/l0/decom_hit.py +3 -1
  38. imap_processing/hit/l1a/hit_l1a.py +30 -25
  39. imap_processing/hit/l1b/constants.py +6 -2
  40. imap_processing/hit/l1b/hit_l1b.py +279 -318
  41. imap_processing/hit/l2/constants.py +37 -0
  42. imap_processing/hit/l2/hit_l2.py +373 -264
  43. imap_processing/ialirt/l0/parse_mag.py +138 -10
  44. imap_processing/ialirt/l0/process_swapi.py +69 -0
  45. imap_processing/ialirt/l0/process_swe.py +318 -22
  46. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -212
  47. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  48. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  49. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  50. imap_processing/ialirt/utils/grouping.py +1 -1
  51. imap_processing/idex/idex_constants.py +9 -1
  52. imap_processing/idex/idex_l0.py +22 -8
  53. imap_processing/idex/idex_l1a.py +75 -44
  54. imap_processing/idex/idex_l1b.py +9 -8
  55. imap_processing/idex/idex_l2a.py +79 -45
  56. imap_processing/idex/idex_l2b.py +120 -0
  57. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -39
  58. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  59. imap_processing/lo/l0/lo_science.py +1 -2
  60. imap_processing/lo/l1a/lo_l1a.py +1 -4
  61. imap_processing/lo/l1b/lo_l1b.py +527 -6
  62. imap_processing/lo/l1b/tof_conversions.py +11 -0
  63. imap_processing/lo/l1c/lo_l1c.py +1 -4
  64. imap_processing/mag/constants.py +43 -0
  65. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  66. imap_processing/mag/l1a/mag_l1a.py +2 -9
  67. imap_processing/mag/l1a/mag_l1a_data.py +10 -10
  68. imap_processing/mag/l1b/mag_l1b.py +84 -17
  69. imap_processing/mag/l1c/interpolation_methods.py +180 -3
  70. imap_processing/mag/l1c/mag_l1c.py +236 -70
  71. imap_processing/mag/l2/mag_l2.py +140 -0
  72. imap_processing/mag/l2/mag_l2_data.py +288 -0
  73. imap_processing/spacecraft/quaternions.py +1 -3
  74. imap_processing/spice/geometry.py +3 -3
  75. imap_processing/spice/kernels.py +0 -276
  76. imap_processing/spice/pointing_frame.py +257 -0
  77. imap_processing/spice/repoint.py +48 -19
  78. imap_processing/spice/spin.py +38 -33
  79. imap_processing/spice/time.py +24 -0
  80. imap_processing/swapi/l1/swapi_l1.py +16 -12
  81. imap_processing/swapi/l2/swapi_l2.py +116 -4
  82. imap_processing/swapi/swapi_utils.py +32 -0
  83. imap_processing/swe/l1a/swe_l1a.py +2 -9
  84. imap_processing/swe/l1a/swe_science.py +8 -11
  85. imap_processing/swe/l1b/swe_l1b.py +898 -23
  86. imap_processing/swe/l2/swe_l2.py +21 -77
  87. imap_processing/swe/utils/swe_constants.py +1 -0
  88. imap_processing/tests/ccsds/test_excel_to_xtce.py +1 -1
  89. imap_processing/tests/cdf/test_utils.py +14 -16
  90. imap_processing/tests/codice/conftest.py +44 -33
  91. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  92. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  93. imap_processing/tests/codice/test_codice_l1a.py +20 -11
  94. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  95. imap_processing/tests/conftest.py +78 -22
  96. imap_processing/tests/ena_maps/test_ena_maps.py +462 -33
  97. imap_processing/tests/ena_maps/test_spatial_utils.py +1 -1
  98. imap_processing/tests/glows/conftest.py +10 -14
  99. imap_processing/tests/glows/test_glows_decom.py +4 -4
  100. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  101. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  102. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  103. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  104. imap_processing/tests/glows/test_glows_l2.py +2 -8
  105. imap_processing/tests/hi/conftest.py +1 -1
  106. imap_processing/tests/hi/test_hi_l1b.py +10 -12
  107. imap_processing/tests/hi/test_hi_l1c.py +27 -24
  108. imap_processing/tests/hi/test_l1a.py +7 -9
  109. imap_processing/tests/hi/test_science_direct_event.py +2 -2
  110. imap_processing/tests/hit/helpers/l1_validation.py +44 -43
  111. imap_processing/tests/hit/test_decom_hit.py +1 -1
  112. imap_processing/tests/hit/test_hit_l1a.py +9 -9
  113. imap_processing/tests/hit/test_hit_l1b.py +172 -217
  114. imap_processing/tests/hit/test_hit_l2.py +380 -118
  115. imap_processing/tests/hit/test_hit_utils.py +122 -55
  116. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  117. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  118. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  119. imap_processing/tests/ialirt/unit/test_grouping.py +2 -2
  120. imap_processing/tests/ialirt/unit/test_parse_mag.py +71 -16
  121. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  122. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  123. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  124. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  125. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  126. imap_processing/tests/ialirt/unit/test_process_swe.py +115 -7
  127. imap_processing/tests/idex/conftest.py +72 -7
  128. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  129. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  130. imap_processing/tests/idex/test_idex_l0.py +33 -11
  131. imap_processing/tests/idex/test_idex_l1a.py +50 -23
  132. imap_processing/tests/idex/test_idex_l1b.py +104 -25
  133. imap_processing/tests/idex/test_idex_l2a.py +48 -32
  134. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  135. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  136. imap_processing/tests/lo/test_lo_l1b.py +371 -6
  137. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  138. imap_processing/tests/lo/test_lo_science.py +6 -7
  139. imap_processing/tests/lo/test_star_sensor.py +1 -1
  140. imap_processing/tests/mag/conftest.py +58 -9
  141. imap_processing/tests/mag/test_mag_decom.py +4 -3
  142. imap_processing/tests/mag/test_mag_l1a.py +13 -7
  143. imap_processing/tests/mag/test_mag_l1b.py +9 -9
  144. imap_processing/tests/mag/test_mag_l1c.py +151 -47
  145. imap_processing/tests/mag/test_mag_l2.py +130 -0
  146. imap_processing/tests/mag/test_mag_validation.py +144 -7
  147. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  148. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  149. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  150. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  151. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  152. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  153. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  154. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  155. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  156. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  157. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  158. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  159. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  160. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  161. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  162. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  163. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  164. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  165. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  166. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  167. imap_processing/tests/spacecraft/test_quaternions.py +1 -1
  168. imap_processing/tests/spice/test_data/fake_repoint_data.csv +4 -4
  169. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  170. imap_processing/tests/spice/test_geometry.py +3 -3
  171. imap_processing/tests/spice/test_kernels.py +1 -200
  172. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  173. imap_processing/tests/spice/test_repoint.py +20 -10
  174. imap_processing/tests/spice/test_spin.py +50 -9
  175. imap_processing/tests/spice/test_time.py +14 -0
  176. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  177. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  178. imap_processing/tests/swapi/test_swapi_l1.py +7 -9
  179. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  180. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  181. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  182. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  183. imap_processing/tests/swe/test_swe_l1a.py +6 -6
  184. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  185. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  186. imap_processing/tests/swe/test_swe_l2.py +82 -102
  187. imap_processing/tests/test_cli.py +171 -88
  188. imap_processing/tests/test_utils.py +2 -1
  189. imap_processing/tests/ultra/data/mock_data.py +49 -21
  190. imap_processing/tests/ultra/unit/conftest.py +53 -70
  191. imap_processing/tests/ultra/unit/test_badtimes.py +2 -4
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -6
  193. imap_processing/tests/ultra/unit/test_de.py +3 -10
  194. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  195. imap_processing/tests/ultra/unit/test_decom_apid_881.py +15 -16
  196. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  197. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  198. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  199. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +3 -4
  200. imap_processing/tests/ultra/unit/test_ultra_l1a.py +84 -307
  201. imap_processing/tests/ultra/unit/test_ultra_l1b.py +30 -12
  202. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  203. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +4 -1
  204. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +163 -29
  205. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  206. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +32 -43
  207. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  208. imap_processing/ultra/constants.py +1 -1
  209. imap_processing/ultra/l0/decom_tools.py +21 -34
  210. imap_processing/ultra/l0/decom_ultra.py +168 -204
  211. imap_processing/ultra/l0/ultra_utils.py +152 -136
  212. imap_processing/ultra/l1a/ultra_l1a.py +55 -243
  213. imap_processing/ultra/l1b/badtimes.py +1 -4
  214. imap_processing/ultra/l1b/cullingmask.py +2 -6
  215. imap_processing/ultra/l1b/de.py +62 -47
  216. imap_processing/ultra/l1b/extendedspin.py +8 -4
  217. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  218. imap_processing/ultra/l1b/ultra_l1b.py +3 -8
  219. imap_processing/ultra/l1b/ultra_l1b_culling.py +4 -4
  220. imap_processing/ultra/l1b/ultra_l1b_extended.py +236 -78
  221. imap_processing/ultra/l1c/histogram.py +2 -6
  222. imap_processing/ultra/l1c/spacecraft_pset.py +2 -4
  223. imap_processing/ultra/l1c/ultra_l1c.py +1 -5
  224. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +107 -60
  225. imap_processing/ultra/l2/ultra_l2.py +299 -0
  226. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  227. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  228. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  229. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  230. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  231. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  232. imap_processing/ultra/packet_definitions/README.md +38 -0
  233. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  234. imap_processing/ultra/utils/ultra_l1_utils.py +13 -12
  235. imap_processing/utils.py +1 -1
  236. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +3 -2
  237. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/RECORD +264 -225
  238. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  239. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +0 -6
  240. imap_processing/mag/l1b/__init__.py +0 -0
  241. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  242. imap_processing/swe/l1b/swe_l1b_science.py +0 -699
  243. imap_processing/tests/swe/test_swe_l1b_science.py +0 -103
  244. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  245. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  246. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  247. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  248. /imap_processing/tests/ialirt/{test_data → data}/l0/461971383-404.bin +0 -0
  249. /imap_processing/tests/ialirt/{test_data → data}/l0/461971384-405.bin +0 -0
  250. /imap_processing/tests/ialirt/{test_data → data}/l0/461971385-406.bin +0 -0
  251. /imap_processing/tests/ialirt/{test_data → data}/l0/461971386-407.bin +0 -0
  252. /imap_processing/tests/ialirt/{test_data → data}/l0/461971387-408.bin +0 -0
  253. /imap_processing/tests/ialirt/{test_data → data}/l0/461971388-409.bin +0 -0
  254. /imap_processing/tests/ialirt/{test_data → data}/l0/461971389-410.bin +0 -0
  255. /imap_processing/tests/ialirt/{test_data → data}/l0/461971390-411.bin +0 -0
  256. /imap_processing/tests/ialirt/{test_data → data}/l0/461971391-412.bin +0 -0
  257. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  258. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  259. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  260. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  261. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  262. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  263. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  264. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  265. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  266. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  267. /imap_processing/tests/ialirt/{test_data → data}/l0/sample_decoded_i-alirt_data.csv +0 -0
  268. /imap_processing/tests/mag/validation/{imap_calibration_mag_20240229_v01.cdf → calibration/imap_mag_l1b-calibration_20240229_v001.cdf} +0 -0
  269. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  270. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  271. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  272. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -9,7 +9,7 @@ class CoordNames(Enum):
9
9
  GENERIC_PIXEL = "pixel"
10
10
 
11
11
  TIME = "epoch"
12
- ENERGY = "energy"
12
+ ENERGY_ULTRA = "energy_bin_geometric_mean"
13
13
  HEALPIX_INDEX = "healpix_index"
14
14
 
15
15
  # The names of the az/el angular coordinates may differ between L1C and L2 data
@@ -79,17 +79,22 @@ def build_solid_angle_map(
79
79
  if spacing <= 0:
80
80
  raise ValueError("Spacing must be positive valued, non-zero.")
81
81
 
82
- 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):
83
86
  raise ValueError("Spacing must divide evenly into pi radians.")
84
87
 
85
- latitudes = np.arange(-np.pi / 2, np.pi / 2 + spacing, step=spacing)
86
- sine_latitudes = np.sin(latitudes)
87
- 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)
88
93
  solid_angle_by_latitude = np.abs(spacing * delta_sine_latitudes)
89
94
 
90
95
  # Order ensures agreement with build_az_el_grid's order of tiling az/el grid.
91
96
  solid_angle_grid = np.repeat(
92
- 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
93
98
  )
94
99
 
95
100
  return solid_angle_grid
@@ -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,
@@ -16,7 +16,7 @@ from imap_processing.utils import packet_file_to_datasets
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
18
 
19
- def hi_l1a(packet_file_path: Union[str, Path], data_version: str) -> list[xr.Dataset]:
19
+ def hi_l1a(packet_file_path: Union[str, Path]) -> list[xr.Dataset]:
20
20
  """
21
21
  Will process IMAP raw data to l1a.
22
22
 
@@ -24,20 +24,13 @@ def hi_l1a(packet_file_path: Union[str, Path], data_version: str) -> list[xr.Dat
24
24
  ----------
25
25
  packet_file_path : str
26
26
  Data packet file path.
27
- data_version : str
28
- Version of the data product being created.
29
27
 
30
28
  Returns
31
29
  -------
32
30
  processed_data : list[xarray.Dataset]
33
31
  List of processed xarray dataset.
34
32
  """
35
- packet_def_file = (
36
- imap_module_directory / "hi/packet_definitions/TLM_HI_COMBINED_SCI.xml"
37
- )
38
- datasets_by_apid = packet_file_to_datasets(
39
- packet_file=packet_file_path, xtce_packet_definition=packet_def_file
40
- )
33
+ datasets_by_apid = hi_packet_file_to_datasets(packet_file_path)
41
34
 
42
35
  # Process science to l1a.
43
36
  processed_data = []
@@ -67,9 +60,6 @@ def hi_l1a(packet_file_path: Union[str, Path], data_version: str) -> list[xr.Dat
67
60
  attr_mgr.add_instrument_global_attrs("hi")
68
61
  data.attrs.update(attr_mgr.get_global_attributes(gattr_key))
69
62
 
70
- # TODO: revisit this
71
- data.attrs["Data_version"] = data_version
72
-
73
63
  # set the sensor string in Logical_source
74
64
  sensor_str = apid_enum.sensor
75
65
  data.attrs["Logical_source"] = data.attrs["Logical_source"].format(
@@ -77,3 +67,32 @@ def hi_l1a(packet_file_path: Union[str, Path], data_version: str) -> list[xr.Dat
77
67
  )
78
68
  processed_data.append(data)
79
69
  return processed_data
70
+
71
+
72
+ def hi_packet_file_to_datasets(
73
+ packet_file_path: Union[str, Path], use_derived_value: bool = False
74
+ ) -> dict[int, xr.Dataset]:
75
+ """
76
+ Extract hi datasets from packet file.
77
+
78
+ Parameters
79
+ ----------
80
+ packet_file_path : str
81
+ L0 packet file path.
82
+ use_derived_value : bool
83
+ Whether to use the derived value from the XTCE definition. Default is False.
84
+
85
+ Returns
86
+ -------
87
+ datasets : dict[int, xarray.Dataset]
88
+ Dictionary of xarray datasets keyed by APID.
89
+ """
90
+ packet_def_file = (
91
+ imap_module_directory / "hi/packet_definitions/TLM_HI_COMBINED_SCI.xml"
92
+ )
93
+ datasets_by_apid = packet_file_to_datasets(
94
+ packet_file=packet_file_path,
95
+ xtce_packet_definition=packet_def_file,
96
+ use_derived_value=use_derived_value,
97
+ )
98
+ return datasets_by_apid
@@ -2,6 +2,8 @@
2
2
 
3
3
  import logging
4
4
  from enum import IntEnum
5
+ from pathlib import Path
6
+ from typing import Union
5
7
 
6
8
  import numpy as np
7
9
  import xarray as xr
@@ -26,7 +28,7 @@ from imap_processing.spice.spin import (
26
28
  get_spacecraft_spin_phase,
27
29
  )
28
30
  from imap_processing.spice.time import met_to_sclkticks, sct_to_et
29
- from imap_processing.utils import convert_raw_to_eu
31
+ from imap_processing.utils import packet_file_to_datasets
30
32
 
31
33
 
32
34
  class TriggerId(IntEnum):
@@ -43,61 +45,96 @@ ATTR_MGR.add_instrument_global_attrs("hi")
43
45
  ATTR_MGR.add_instrument_variable_attrs(instrument="hi", level=None)
44
46
 
45
47
 
46
- def hi_l1b(l1a_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
48
+ def hi_l1b(dependency: Union[str, Path, xr.Dataset]) -> list[xr.Dataset]:
47
49
  """
48
50
  High level IMAP-HI L1B processing function.
49
51
 
50
52
  Parameters
51
53
  ----------
52
- l1a_dataset : xarray.Dataset
53
- L1A dataset to process.
54
- data_version : str
55
- Version of the data product being created.
54
+ dependency : str or xarray.Dataset
55
+ Path to L0 file or L1A dataset to process.
56
56
 
57
57
  Returns
58
58
  -------
59
- l1b_dataset : xarray.Dataset
60
- Processed xarray dataset.
59
+ l1b_dataset : list[xarray.Dataset]
60
+ Processed xarray datasets.
61
61
  """
62
- logger.info(
63
- f"Running Hi L1B processing on dataset: {l1a_dataset.attrs['Logical_source']}"
64
- )
65
- logical_source_parts = parse_filename_like(l1a_dataset.attrs["Logical_source"])
66
- # TODO: apid is not currently stored in all L1A data but should be.
67
- # Use apid to determine what L1B processing function to call
68
-
69
62
  # Housekeeping processing
70
- if logical_source_parts["descriptor"].endswith("hk"):
71
- # if packet_enum in (HIAPID.H45_APP_NHK, HIAPID.H90_APP_NHK):
72
- packet_enum = HIAPID(l1a_dataset["pkt_apid"].data[0])
73
- conversion_table_path = str(
74
- imap_module_directory / "hi" / "l1b" / "hi_eng_unit_convert_table.csv"
75
- )
76
- l1b_dataset = convert_raw_to_eu(
77
- l1a_dataset,
78
- conversion_table_path=conversion_table_path,
79
- packet_name=packet_enum.name,
80
- comment="#", # type: ignore[arg-type]
81
- # Todo error, Argument "comment" to "convert_raw_to_eu" has incompatible
82
- # type "str"; expected "dict[Any, Any]"
83
- converters={"mnemonic": str.lower},
84
- )
85
-
86
- l1b_dataset.attrs.update(ATTR_MGR.get_global_attributes("imap_hi_l1b_hk_attrs"))
87
- elif logical_source_parts["descriptor"].endswith("de"):
88
- l1b_dataset = annotate_direct_events(l1a_dataset)
89
- else:
90
- raise NotImplementedError(
91
- f"No Hi L1B processing defined for file type: "
63
+ if isinstance(dependency, (Path, str)):
64
+ logger.info(f"Running Hi L1B processing on file: {dependency}")
65
+ l1b_datasets = housekeeping(dependency)
66
+ elif isinstance(dependency, xr.Dataset):
67
+ l1a_dataset = dependency
68
+ logger.info(
69
+ f"Running Hi L1B processing on dataset: "
92
70
  f"{l1a_dataset.attrs['Logical_source']}"
93
71
  )
94
- # Update global attributes
95
- l1b_dataset.attrs["Logical_source"] = l1b_dataset.attrs["Logical_source"].format(
96
- sensor=logical_source_parts["sensor"]
72
+ logical_source_parts = parse_filename_like(l1a_dataset.attrs["Logical_source"])
73
+ # TODO: apid is not currently stored in all L1A data but should be.
74
+ # Use apid to determine what L1B processing function to call
75
+
76
+ # DE processing
77
+ if logical_source_parts["descriptor"].endswith("de"):
78
+ l1b_datasets = [annotate_direct_events(l1a_dataset)]
79
+ l1b_datasets[0].attrs["Logical_source"] = (
80
+ l1b_datasets[0]
81
+ .attrs["Logical_source"]
82
+ .format(sensor=logical_source_parts["sensor"])
83
+ )
84
+ else:
85
+ raise NotImplementedError(
86
+ f"No Hi L1B processing defined for file type: "
87
+ f"{l1a_dataset.attrs['Logical_source']}"
88
+ )
89
+
90
+ return l1b_datasets
91
+
92
+
93
+ def housekeeping(packet_file_path: Union[str, Path]) -> list[xr.Dataset]:
94
+ """
95
+ Will process IMAP raw data to l1b housekeeping dataset.
96
+
97
+ In order to use `space_packet_parser` and the xtce which contains the
98
+ DN to EU conversion factors, the L0 packet file is used to go straight to
99
+ L1B.
100
+
101
+ Parameters
102
+ ----------
103
+ packet_file_path : str
104
+ Packet file path.
105
+
106
+ Returns
107
+ -------
108
+ processed_data : list[xarray.Dataset]
109
+ Housekeeping datasets with engineering units.
110
+ """
111
+ packet_def_file = (
112
+ imap_module_directory / "hi/packet_definitions/TLM_HI_COMBINED_SCI.xml"
97
113
  )
98
- # TODO: revisit this
99
- l1b_dataset.attrs["Data_version"] = data_version
100
- return l1b_dataset
114
+ # TODO: If raw and derived values can be gotten from one call to
115
+ # packet_file_to_datasets, the L1A and L1B could be generated
116
+ # in a single L1A/B function.
117
+ datasets_by_apid = packet_file_to_datasets(
118
+ packet_file=packet_file_path,
119
+ xtce_packet_definition=packet_def_file,
120
+ use_derived_value=True,
121
+ )
122
+
123
+ # Extract only the HK datasets
124
+ attr_mgr = ImapCdfAttributes()
125
+ attr_mgr.add_instrument_global_attrs("hi")
126
+ datasets = list()
127
+ for apid in [HIAPID.H45_APP_NHK, HIAPID.H90_APP_NHK]:
128
+ if apid in datasets_by_apid:
129
+ datasets.append(datasets_by_apid[apid])
130
+ # Update the dataset global attributes
131
+ datasets[-1].attrs.update(
132
+ ATTR_MGR.get_global_attributes("imap_hi_l1b_hk_attrs")
133
+ )
134
+ datasets[-1].attrs["Logical_source"] = (
135
+ datasets[-1].attrs["Logical_source"].format(sensor=apid.sensor)
136
+ )
137
+ return datasets
101
138
 
102
139
 
103
140
  def annotate_direct_events(l1a_dataset: xr.Dataset) -> xr.Dataset: