imap-processing 0.6.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.
Files changed (398) hide show
  1. imap_processing/__init__.py +34 -0
  2. imap_processing/_version.py +3 -0
  3. imap_processing/ccsds/__init__.py +0 -0
  4. imap_processing/ccsds/ccsds_data.py +55 -0
  5. imap_processing/ccsds/excel_to_xtce.py +477 -0
  6. imap_processing/cdf/__init__.py +0 -0
  7. imap_processing/cdf/cdf_attribute_manager.py +322 -0
  8. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +212 -0
  9. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +1358 -0
  10. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +391 -0
  11. imap_processing/cdf/config/imap_constant_attrs.yaml +33 -0
  12. imap_processing/cdf/config/imap_default_global_cdf_attrs.yaml +17 -0
  13. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +41 -0
  14. imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +499 -0
  15. imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +334 -0
  16. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +51 -0
  17. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +435 -0
  18. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -0
  19. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +493 -0
  20. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +564 -0
  21. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +24 -0
  22. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +426 -0
  23. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +90 -0
  24. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +487 -0
  25. imap_processing/cdf/config/imap_lo_l1b_variable_attrs.yaml +121 -0
  26. imap_processing/cdf/config/imap_lo_l1c_variable_attrs.yaml +179 -0
  27. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +97 -0
  28. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +201 -0
  29. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +33 -0
  30. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +137 -0
  31. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +24 -0
  32. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +234 -0
  33. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +273 -0
  34. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +100 -0
  35. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +52 -0
  36. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +297 -0
  37. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +121 -0
  38. imap_processing/cdf/config/shared/default_global_cdf_attrs_schema.yaml +246 -0
  39. imap_processing/cdf/config/shared/default_variable_cdf_attrs_schema.yaml +466 -0
  40. imap_processing/cdf/imap_cdf_manager.py +64 -0
  41. imap_processing/cdf/utils.py +147 -0
  42. imap_processing/cli.py +863 -0
  43. imap_processing/codice/__init__.py +1 -0
  44. imap_processing/codice/codice_l0.py +54 -0
  45. imap_processing/codice/codice_l1a.py +558 -0
  46. imap_processing/codice/codice_l1b.py +194 -0
  47. imap_processing/codice/constants.py +986 -0
  48. imap_processing/codice/data/esa_sweep_values.csv +257 -0
  49. imap_processing/codice/data/lo_stepping_values.csv +129 -0
  50. imap_processing/codice/decompress.py +142 -0
  51. imap_processing/codice/packet_definitions/P_COD_NHK.xml +618 -0
  52. imap_processing/codice/packet_definitions/codice_packet_definition.xml +5073 -0
  53. imap_processing/codice/utils.py +95 -0
  54. imap_processing/decom.py +40 -0
  55. imap_processing/glows/__init__.py +1 -0
  56. imap_processing/glows/ancillary/l1b_conversion_table_v001.json +42 -0
  57. imap_processing/glows/l0/__init__.py +0 -0
  58. imap_processing/glows/l0/decom_glows.py +91 -0
  59. imap_processing/glows/l0/glows_l0_data.py +194 -0
  60. imap_processing/glows/l1a/glows_l1a.py +424 -0
  61. imap_processing/glows/l1a/glows_l1a_data.py +555 -0
  62. imap_processing/glows/l1b/glows_l1b.py +270 -0
  63. imap_processing/glows/l1b/glows_l1b_data.py +583 -0
  64. imap_processing/glows/packet_definitions/GLX_COMBINED.xml +254 -0
  65. imap_processing/glows/packet_definitions/P_GLX_TMSCDE.xml +97 -0
  66. imap_processing/glows/packet_definitions/P_GLX_TMSCHIST.xml +215 -0
  67. imap_processing/glows/utils/__init__.py +0 -0
  68. imap_processing/glows/utils/constants.py +105 -0
  69. imap_processing/hi/__init__.py +1 -0
  70. imap_processing/hi/l0/__init__.py +0 -0
  71. imap_processing/hi/l0/decom_hi.py +24 -0
  72. imap_processing/hi/l1a/__init__.py +0 -0
  73. imap_processing/hi/l1a/hi_l1a.py +73 -0
  74. imap_processing/hi/l1a/histogram.py +142 -0
  75. imap_processing/hi/l1a/housekeeping.py +27 -0
  76. imap_processing/hi/l1a/science_direct_event.py +341 -0
  77. imap_processing/hi/l1b/__init__.py +0 -0
  78. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +154 -0
  79. imap_processing/hi/l1b/hi_l1b.py +127 -0
  80. imap_processing/hi/l1c/__init__.py +0 -0
  81. imap_processing/hi/l1c/hi_l1c.py +228 -0
  82. imap_processing/hi/packet_definitions/__init__.py +0 -0
  83. imap_processing/hi/packet_definitions/hi_packet_definition.xml +482 -0
  84. imap_processing/hi/utils.py +27 -0
  85. imap_processing/hit/__init__.py +1 -0
  86. imap_processing/hit/l0/__init__.py +0 -0
  87. imap_processing/hit/l0/data_classes/housekeeping.py +240 -0
  88. imap_processing/hit/l0/data_classes/science_packet.py +259 -0
  89. imap_processing/hit/l0/decom_hit.py +467 -0
  90. imap_processing/hit/l0/utils/hit_base.py +57 -0
  91. imap_processing/hit/l1a/__init__.py +0 -0
  92. imap_processing/hit/l1a/hit_l1a.py +254 -0
  93. imap_processing/hit/l1b/hit_l1b.py +179 -0
  94. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1276 -0
  95. imap_processing/ialirt/__init__.py +0 -0
  96. imap_processing/ialirt/l0/__init__.py +0 -0
  97. imap_processing/ialirt/l0/process_hit.py +220 -0
  98. imap_processing/ialirt/packet_definitions/__init__.py +0 -0
  99. imap_processing/ialirt/packet_definitions/ialirt.xml +778 -0
  100. imap_processing/ialirt/packet_definitions/ialirt_hit.xml +186 -0
  101. imap_processing/idex/__init__.py +2 -0
  102. imap_processing/idex/idex_constants.py +27 -0
  103. imap_processing/idex/idex_l0.py +31 -0
  104. imap_processing/idex/idex_l1a.py +631 -0
  105. imap_processing/idex/packet_definitions/idex_packet_definition.xml +3162 -0
  106. imap_processing/lo/__init__.py +1 -0
  107. imap_processing/lo/l0/__init__.py +0 -0
  108. imap_processing/lo/l0/data_classes/science_direct_events.py +215 -0
  109. imap_processing/lo/l0/data_classes/star_sensor.py +98 -0
  110. imap_processing/lo/l0/decompression_tables/12_to_16_bit.csv +4097 -0
  111. imap_processing/lo/l0/decompression_tables/8_to_12_bit.csv +257 -0
  112. imap_processing/lo/l0/decompression_tables/8_to_16_bit.csv +257 -0
  113. imap_processing/lo/l0/decompression_tables/decompression_tables.py +75 -0
  114. imap_processing/lo/l0/lo_apid.py +15 -0
  115. imap_processing/lo/l0/lo_science.py +150 -0
  116. imap_processing/lo/l0/utils/binary_string.py +59 -0
  117. imap_processing/lo/l0/utils/bit_decompression.py +62 -0
  118. imap_processing/lo/l0/utils/lo_base.py +57 -0
  119. imap_processing/lo/l1a/__init__.py +0 -0
  120. imap_processing/lo/l1a/lo_l1a.py +157 -0
  121. imap_processing/lo/l1b/lo_l1b.py +160 -0
  122. imap_processing/lo/l1c/lo_l1c.py +180 -0
  123. imap_processing/lo/packet_definitions/lo_xtce.xml +3541 -0
  124. imap_processing/mag/__init__.py +2 -0
  125. imap_processing/mag/constants.py +108 -0
  126. imap_processing/mag/l0/decom_mag.py +170 -0
  127. imap_processing/mag/l0/mag_l0_data.py +118 -0
  128. imap_processing/mag/l1a/mag_l1a.py +317 -0
  129. imap_processing/mag/l1a/mag_l1a_data.py +1007 -0
  130. imap_processing/mag/l1b/__init__.py +0 -0
  131. imap_processing/mag/l1b/imap_calibration_mag_20240229_v01.cdf +0 -0
  132. imap_processing/mag/l1b/mag_l1b.py +125 -0
  133. imap_processing/mag/l1c/mag_l1c.py +57 -0
  134. imap_processing/mag/packet_definitions/MAG_SCI_COMBINED.xml +235 -0
  135. imap_processing/quality_flags.py +91 -0
  136. imap_processing/spice/__init__.py +1 -0
  137. imap_processing/spice/geometry.py +322 -0
  138. imap_processing/spice/kernels.py +459 -0
  139. imap_processing/spice/time.py +72 -0
  140. imap_processing/swapi/__init__.py +1 -0
  141. imap_processing/swapi/l1/__init__.py +0 -0
  142. imap_processing/swapi/l1/swapi_l1.py +685 -0
  143. imap_processing/swapi/l2/__init__.py +0 -0
  144. imap_processing/swapi/l2/swapi_l2.py +107 -0
  145. imap_processing/swapi/packet_definitions/__init__.py +0 -0
  146. imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +708 -0
  147. imap_processing/swapi/swapi_utils.py +25 -0
  148. imap_processing/swe/__init__.py +1 -0
  149. imap_processing/swe/l1a/__init__.py +0 -0
  150. imap_processing/swe/l1a/swe_l1a.py +48 -0
  151. imap_processing/swe/l1a/swe_science.py +223 -0
  152. imap_processing/swe/l1b/engineering_unit_convert_table.csv +65 -0
  153. imap_processing/swe/l1b/swe_esa_lookup_table.csv +1441 -0
  154. imap_processing/swe/l1b/swe_l1b.py +49 -0
  155. imap_processing/swe/l1b/swe_l1b_science.py +557 -0
  156. imap_processing/swe/packet_definitions/__init__.py +0 -0
  157. imap_processing/swe/packet_definitions/swe_packet_definition.xml +303 -0
  158. imap_processing/swe/utils/__init__.py +0 -0
  159. imap_processing/swe/utils/swe_utils.py +9 -0
  160. imap_processing/tests/__init__.py +0 -0
  161. imap_processing/tests/ccsds/test_data/expected_output.xml +171 -0
  162. imap_processing/tests/ccsds/test_excel_to_xtce.py +285 -0
  163. imap_processing/tests/cdf/__init__.py +0 -0
  164. imap_processing/tests/cdf/imap_default_global_cdf_attrs.yaml +8 -0
  165. imap_processing/tests/cdf/shared/default_global_cdf_attrs_schema.yaml +246 -0
  166. imap_processing/tests/cdf/shared/default_variable_cdf_attrs_schema.yaml +466 -0
  167. imap_processing/tests/cdf/test_cdf_attribute_manager.py +353 -0
  168. imap_processing/tests/cdf/test_data/imap_default_global_test_cdf_attrs.yaml +7 -0
  169. imap_processing/tests/cdf/test_data/imap_instrument1_global_cdf_attrs.yaml +14 -0
  170. imap_processing/tests/cdf/test_data/imap_instrument1_level1_variable_attrs.yaml +23 -0
  171. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +23 -0
  172. imap_processing/tests/cdf/test_data/imap_instrument2_level2_variable_attrs.yaml +30 -0
  173. imap_processing/tests/cdf/test_data/imap_test_global.yaml +26 -0
  174. imap_processing/tests/cdf/test_data/imap_test_variable.yaml +41 -0
  175. imap_processing/tests/cdf/test_imap_cdf_manager.py +62 -0
  176. imap_processing/tests/cdf/test_utils.py +109 -0
  177. imap_processing/tests/codice/__init__.py +0 -0
  178. imap_processing/tests/codice/conftest.py +56 -0
  179. imap_processing/tests/codice/data/eu_unit_lookup_table.csv +101 -0
  180. imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +100 -0
  181. imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +100 -0
  182. imap_processing/tests/codice/data/imap_codice_l0_hi-counters-aggregated_20240429_v001.pkts +0 -0
  183. imap_processing/tests/codice/data/imap_codice_l0_hi-counters-singles_20240429_v001.pkts +0 -0
  184. imap_processing/tests/codice/data/imap_codice_l0_hi-omni_20240429_v001.pkts +0 -0
  185. imap_processing/tests/codice/data/imap_codice_l0_hi-pha_20240429_v001.pkts +0 -0
  186. imap_processing/tests/codice/data/imap_codice_l0_hi-sectored_20240429_v001.pkts +0 -0
  187. imap_processing/tests/codice/data/imap_codice_l0_hskp_20100101_v001.pkts +0 -0
  188. imap_processing/tests/codice/data/imap_codice_l0_lo-counters-aggregated_20240429_v001.pkts +0 -0
  189. imap_processing/tests/codice/data/imap_codice_l0_lo-counters-singles_20240429_v001.pkts +0 -0
  190. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-angular_20240429_v001.pkts +0 -0
  191. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-priority_20240429_v001.pkts +0 -0
  192. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-species_20240429_v001.pkts +0 -0
  193. imap_processing/tests/codice/data/imap_codice_l0_lo-pha_20240429_v001.pkts +0 -0
  194. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-angular_20240429_v001.pkts +0 -0
  195. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-priority_20240429_v001.pkts +0 -0
  196. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-species_20240429_v001.pkts +0 -0
  197. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  198. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  199. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  200. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  201. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  202. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  203. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  204. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  205. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  206. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  207. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  208. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  209. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  210. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  211. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  212. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  213. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  214. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  215. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  216. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  217. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  218. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  219. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  220. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  221. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  222. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  223. imap_processing/tests/codice/test_codice_l0.py +144 -0
  224. imap_processing/tests/codice/test_codice_l1a.py +187 -0
  225. imap_processing/tests/codice/test_codice_l1b.py +60 -0
  226. imap_processing/tests/codice/test_decompress.py +50 -0
  227. imap_processing/tests/conftest.py +372 -0
  228. imap_processing/tests/glows/direct_events_validation_data_l1a.csv +5704 -0
  229. imap_processing/tests/glows/glows_test_packet_20110921_v01.pkts +0 -0
  230. imap_processing/tests/glows/test_glows_decom.py +133 -0
  231. imap_processing/tests/glows/test_glows_l1a_cdf.py +85 -0
  232. imap_processing/tests/glows/test_glows_l1a_data.py +510 -0
  233. imap_processing/tests/glows/test_glows_l1b.py +348 -0
  234. imap_processing/tests/glows/test_glows_l1b_data.py +70 -0
  235. imap_processing/tests/hi/__init__.py +0 -0
  236. imap_processing/tests/hi/conftest.py +133 -0
  237. imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.bin +0 -0
  238. imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.csv +201 -0
  239. imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_CNT.bin +0 -0
  240. imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_DE.bin +0 -0
  241. imap_processing/tests/hi/test_data/l0/README.txt +54 -0
  242. imap_processing/tests/hi/test_decom.py +55 -0
  243. imap_processing/tests/hi/test_hi_l1b.py +31 -0
  244. imap_processing/tests/hi/test_hi_l1c.py +69 -0
  245. imap_processing/tests/hi/test_l1a.py +96 -0
  246. imap_processing/tests/hi/test_l1a_sci_de.py +72 -0
  247. imap_processing/tests/hi/test_utils.py +15 -0
  248. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  249. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  250. imap_processing/tests/hit/__init__.py +0 -0
  251. imap_processing/tests/hit/test_data/imap_hit_l0_hk_20100105_v001.pkts +0 -0
  252. imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
  253. imap_processing/tests/hit/test_hit_decom.py +230 -0
  254. imap_processing/tests/hit/test_hit_l1a.py +224 -0
  255. imap_processing/tests/hit/test_hit_l1b.py +52 -0
  256. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +88 -0
  257. imap_processing/tests/ialirt/__init__.py +0 -0
  258. imap_processing/tests/ialirt/test_data/l0/IALiRT Raw Packet Telemetry.txt +33 -0
  259. imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.ccsds +0 -0
  260. imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.csv +1001 -0
  261. imap_processing/tests/ialirt/unit/__init__.py +0 -0
  262. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +94 -0
  263. imap_processing/tests/ialirt/unit/test_process_hit.py +226 -0
  264. imap_processing/tests/idex/__init__.py +0 -0
  265. imap_processing/tests/idex/conftest.py +22 -0
  266. imap_processing/tests/idex/imap_idex_l0_raw_20230725_v001.pkts +0 -0
  267. imap_processing/tests/idex/impact_14_tof_high_data.txt +8189 -0
  268. imap_processing/tests/idex/test_idex_l0.py +45 -0
  269. imap_processing/tests/idex/test_idex_l1a.py +91 -0
  270. imap_processing/tests/lo/__init__.py +0 -0
  271. imap_processing/tests/lo/test_binary_string.py +21 -0
  272. imap_processing/tests/lo/test_bit_decompression.py +39 -0
  273. imap_processing/tests/lo/test_cdfs/imap_lo_l0_raw_20240627_v001.pkts +0 -0
  274. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  275. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  276. imap_processing/tests/lo/test_cdfs/imap_lo_l1b_de_20100101_v001.cdf +0 -0
  277. imap_processing/tests/lo/test_lo_l1a.py +66 -0
  278. imap_processing/tests/lo/test_lo_l1b.py +74 -0
  279. imap_processing/tests/lo/test_lo_l1c.py +66 -0
  280. imap_processing/tests/lo/test_science_counts.py +41 -0
  281. imap_processing/tests/lo/test_science_direct_events.py +209 -0
  282. imap_processing/tests/lo/test_star_sensor.py +35 -0
  283. imap_processing/tests/mag/imap_mag_l1a_burst-magi_20231025_v001.cdf +0 -0
  284. imap_processing/tests/mag/mag_l0_test_data.pkts +0 -0
  285. imap_processing/tests/mag/mag_l0_test_output.csv +37 -0
  286. imap_processing/tests/mag/mag_l1_test_data.pkts +0 -0
  287. imap_processing/tests/mag/mag_l1a_test_output.csv +97 -0
  288. imap_processing/tests/mag/test_mag_decom.py +117 -0
  289. imap_processing/tests/mag/test_mag_l1a.py +856 -0
  290. imap_processing/tests/mag/test_mag_l1b.py +77 -0
  291. imap_processing/tests/mag/test_mag_l1c.py +40 -0
  292. imap_processing/tests/spice/__init__.py +0 -0
  293. imap_processing/tests/spice/test_data/imap_ena_sim_metakernel.template +4 -0
  294. imap_processing/tests/spice/test_data/imap_science_0001.tf +171 -0
  295. imap_processing/tests/spice/test_data/imap_sclk_0000.tsc +156 -0
  296. imap_processing/tests/spice/test_data/imap_sim_ck_2hr_2secsampling_with_nutation.bc +0 -0
  297. imap_processing/tests/spice/test_data/imap_simple_metakernel.template +3 -0
  298. imap_processing/tests/spice/test_data/imap_spk_demo.bsp +0 -0
  299. imap_processing/tests/spice/test_data/imap_wkcp.tf +1806 -0
  300. imap_processing/tests/spice/test_data/naif0012.tls +150 -0
  301. imap_processing/tests/spice/test_data/sim_1yr_imap_attitude.bc +0 -0
  302. imap_processing/tests/spice/test_data/sim_1yr_imap_pointing_frame.bc +0 -0
  303. imap_processing/tests/spice/test_geometry.py +214 -0
  304. imap_processing/tests/spice/test_kernels.py +272 -0
  305. imap_processing/tests/spice/test_time.py +35 -0
  306. imap_processing/tests/swapi/__init__.py +0 -0
  307. imap_processing/tests/swapi/conftest.py +16 -0
  308. imap_processing/tests/swapi/l0_data/__init__.py +0 -0
  309. imap_processing/tests/swapi/l0_data/imap_swapi_l0_raw_20231012_v001.pkts +0 -0
  310. imap_processing/tests/swapi/l0_validation_data/__init__.py +0 -0
  311. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_AUT_20231012_125245.csv +124 -0
  312. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_HK_20231012_125245.csv +98 -0
  313. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_MG_20231012_125245.csv +9 -0
  314. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_SCI_20231012_125245.csv +72 -0
  315. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_AUT_20231012_125245.csv +124 -0
  316. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_HK_20231012_125245.csv +98 -0
  317. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_MG_20231012_125245.csv +9 -0
  318. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_SCI_20231012_125245.csv +72 -0
  319. imap_processing/tests/swapi/test_swapi_decom.py +135 -0
  320. imap_processing/tests/swapi/test_swapi_l1.py +354 -0
  321. imap_processing/tests/swapi/test_swapi_l2.py +21 -0
  322. imap_processing/tests/swe/__init__.py +0 -0
  323. imap_processing/tests/swe/conftest.py +35 -0
  324. imap_processing/tests/swe/decompressed/20230927173238_4th_quarter_decompressed.csv +181 -0
  325. imap_processing/tests/swe/decompressed/20230927173253_1st_quarter_decompressed.csv +181 -0
  326. imap_processing/tests/swe/decompressed/20230927173308_2nd_quarter_decompressed.csv +181 -0
  327. imap_processing/tests/swe/decompressed/20230927173323_3rd_quarter_decompressed.csv +181 -0
  328. imap_processing/tests/swe/l0_data/2024051010_SWE_SCIENCE_packet.bin +0 -0
  329. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_SCIENCE_20240510_092742.csv +544 -0
  330. imap_processing/tests/swe/l0_validation_data/idle_export_raw.SWE_SCIENCE_20240510_092742.csv +363 -0
  331. imap_processing/tests/swe/test_swe_l1a.py +12 -0
  332. imap_processing/tests/swe/test_swe_l1a_science.py +129 -0
  333. imap_processing/tests/swe/test_swe_l1b.py +61 -0
  334. imap_processing/tests/swe/test_swe_l1b_science.py +65 -0
  335. imap_processing/tests/test_cli.py +229 -0
  336. imap_processing/tests/test_decom.py +66 -0
  337. imap_processing/tests/test_quality_flags.py +71 -0
  338. imap_processing/tests/test_utils.py +107 -0
  339. imap_processing/tests/ultra/__init__.py +0 -0
  340. imap_processing/tests/ultra/test_data/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  341. imap_processing/tests/ultra/test_data/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  342. imap_processing/tests/ultra/test_data/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  343. imap_processing/tests/ultra/test_data/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  344. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
  345. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +105 -0
  346. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
  347. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -0
  348. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +702 -0
  349. imap_processing/tests/ultra/unit/__init__.py +0 -0
  350. imap_processing/tests/ultra/unit/conftest.py +210 -0
  351. imap_processing/tests/ultra/unit/test_decom_apid_880.py +98 -0
  352. imap_processing/tests/ultra/unit/test_decom_apid_881.py +50 -0
  353. imap_processing/tests/ultra/unit/test_decom_apid_883.py +44 -0
  354. imap_processing/tests/ultra/unit/test_decom_apid_896.py +104 -0
  355. imap_processing/tests/ultra/unit/test_lookup_utils.py +68 -0
  356. imap_processing/tests/ultra/unit/test_ultra_l1a.py +338 -0
  357. imap_processing/tests/ultra/unit/test_ultra_l1b.py +122 -0
  358. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +57 -0
  359. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +342 -0
  360. imap_processing/tests/ultra/unit/test_ultra_l1c.py +104 -0
  361. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +35 -0
  362. imap_processing/ultra/__init__.py +1 -0
  363. imap_processing/ultra/constants.py +60 -0
  364. imap_processing/ultra/l0/__init__.py +0 -0
  365. imap_processing/ultra/l0/decom_tools.py +281 -0
  366. imap_processing/ultra/l0/decom_ultra.py +278 -0
  367. imap_processing/ultra/l0/ultra_utils.py +326 -0
  368. imap_processing/ultra/l1a/__init__.py +0 -0
  369. imap_processing/ultra/l1a/ultra_l1a.py +319 -0
  370. imap_processing/ultra/l1b/badtimes.py +26 -0
  371. imap_processing/ultra/l1b/cullingmask.py +26 -0
  372. imap_processing/ultra/l1b/de.py +59 -0
  373. imap_processing/ultra/l1b/extendedspin.py +45 -0
  374. imap_processing/ultra/l1b/lookup_utils.py +165 -0
  375. imap_processing/ultra/l1b/ultra_l1b.py +65 -0
  376. imap_processing/ultra/l1b/ultra_l1b_annotated.py +54 -0
  377. imap_processing/ultra/l1b/ultra_l1b_extended.py +764 -0
  378. imap_processing/ultra/l1c/histogram.py +36 -0
  379. imap_processing/ultra/l1c/pset.py +36 -0
  380. imap_processing/ultra/l1c/ultra_l1c.py +52 -0
  381. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +54 -0
  382. imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +32769 -0
  383. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  384. imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +4097 -0
  385. imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +2050 -0
  386. imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +4097 -0
  387. imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +2050 -0
  388. imap_processing/ultra/lookup_tables/yadjust.csv +257 -0
  389. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +547 -0
  390. imap_processing/ultra/packet_definitions/__init__.py +0 -0
  391. imap_processing/ultra/utils/__init__.py +0 -0
  392. imap_processing/ultra/utils/ultra_l1_utils.py +50 -0
  393. imap_processing/utils.py +413 -0
  394. imap_processing-0.6.0.dist-info/LICENSE +21 -0
  395. imap_processing-0.6.0.dist-info/METADATA +107 -0
  396. imap_processing-0.6.0.dist-info/RECORD +398 -0
  397. imap_processing-0.6.0.dist-info/WHEEL +4 -0
  398. imap_processing-0.6.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,685 @@
1
+ """SWAPI level-1 processing code."""
2
+
3
+ import copy
4
+
5
+ import numpy as np
6
+ import numpy.typing as npt
7
+ import xarray as xr
8
+
9
+ from imap_processing import imap_module_directory
10
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
+ from imap_processing.quality_flags import SWAPIFlags
12
+ from imap_processing.swapi.swapi_utils import SWAPIAPID, SWAPIMODE
13
+ from imap_processing.utils import packet_file_to_datasets
14
+
15
+
16
+ def filter_good_data(full_sweep_sci: xr.Dataset) -> npt.NDArray:
17
+ """
18
+ Filter out bad data sweep indices.
19
+
20
+ Bad data indicator:
21
+
22
+ | 1. SWP_HK.CHKSUM is wrong
23
+ | 2. SWAPI mode (SWP_SCI.MODE) is not HVSCI
24
+ | 3. PLAN_ID for current sweep should all be one value
25
+ | 4. SWEEP_TABLE should all be one value.
26
+
27
+ Parameters
28
+ ----------
29
+ full_sweep_sci : xarray.Dataset
30
+ Science data that only contains full sweep data.
31
+
32
+ Returns
33
+ -------
34
+ good_data_indices : numpy.ndarray
35
+ Good data sweep indices.
36
+ """
37
+ # PLAN_ID for current sweep should all be one value and
38
+ # SWEEP_TABLE should all be one value.
39
+ plan_id = full_sweep_sci["plan_id_science"].data.reshape(-1, 12)
40
+ sweep_table = full_sweep_sci["sweep_table"].data.reshape(-1, 12)
41
+
42
+ mode = full_sweep_sci["mode"].data.reshape(-1, 12)
43
+
44
+ sweep_indices = (sweep_table == sweep_table[:, 0, None]).all(axis=1)
45
+ plan_id_indices = (plan_id == plan_id[:, 0, None]).all(axis=1)
46
+ # TODO: change comparison to SWAPIMODE.HVSCI once we have
47
+ # some HVSCI data
48
+ # MODE should be HVSCI
49
+ mode_indices = (mode == SWAPIMODE.HVENG).all(axis=1)
50
+ bad_data_indices = sweep_indices & plan_id_indices & mode_indices
51
+
52
+ # TODO: add checks for checksum
53
+
54
+ # Get bad data sweep start indices and create
55
+ # sweep indices.
56
+ # Eg.
57
+ # From this: [0 24]
58
+ # To this: [[ 0 1 2 3 4 5 6 7 8 9 10 11]
59
+ # [24 25 26 27 28 29 30 31 32 33 34 35]]
60
+ cycle_start_indices = np.where(bad_data_indices == 0)[0] * 12
61
+ bad_cycle_indices = cycle_start_indices[..., None] + np.arange(12)[
62
+ None, ...
63
+ ].reshape(-1)
64
+
65
+ # Use bad data cycle indices to find all good data indices.
66
+ # Then that will used to filter good sweep data.
67
+ all_indices = np.arange(len(full_sweep_sci["epoch"].data))
68
+ good_data_indices = np.setdiff1d(all_indices, bad_cycle_indices)
69
+
70
+ return good_data_indices
71
+
72
+
73
+ def decompress_count(
74
+ count_data: np.ndarray, compression_flag: np.ndarray
75
+ ) -> npt.NDArray:
76
+ """
77
+ Will decompress counts based on compression indicators.
78
+
79
+ Decompression algorithm:
80
+ There are 3 compression regions:
81
+
82
+ | 1) 0 <= value <=65535
83
+ | 2) 65536 <= value <= 1,048,575
84
+ | 3) 1,048,576 <= value
85
+
86
+ Pseudocode:
87
+
88
+ | if XXX_RNG_ST0 == 0: # Not compressed
89
+ | actual_value = XXX_CNT0
90
+ | elif (XXX_RNG_ST0==1 && XXX_CNT0==0xFFFF): # Overflow
91
+ | actual_value = <some constant that indicates overflow>
92
+ | elif (XXX_RNG_ST0==1 && XXX_CNT0!=0xFFFF):
93
+ | actual_value = XXX_CNT0 * 16
94
+
95
+ Parameters
96
+ ----------
97
+ count_data : numpy.ndarray
98
+ Array with counts.
99
+ compression_flag : numpy.ndarray
100
+ Array with compression indicators.
101
+
102
+ Returns
103
+ -------
104
+ new_count : numpy.ndarray
105
+ Array with decompressed counts.
106
+ """
107
+ # Decompress counts based on compression indicators
108
+ # If 0, value is already decompressed. If 1, value is compressed.
109
+ # If 1 and count is 0xFFFF, value is overflow.
110
+ new_count = copy.deepcopy(count_data).astype(np.int32)
111
+
112
+ # If data is compressed, decompress it
113
+ compressed_indices = compression_flag == 1
114
+ new_count[compressed_indices] *= 16
115
+
116
+ # If the data was compressed and the count was 0xFFFF, mark it as an overflow
117
+ if np.any(count_data < 0):
118
+ raise ValueError(
119
+ "Count data type must be unsigned int and should not contain negative value"
120
+ )
121
+
122
+ # SWAPI suggested using big value to indicate overflow.
123
+ new_count[compressed_indices & (count_data == 0xFFFF)] = np.iinfo(np.int32).max
124
+ return new_count
125
+
126
+
127
+ def find_sweep_starts(packets: xr.Dataset) -> npt.NDArray:
128
+ """
129
+ Find index of where new cycle started.
130
+
131
+ Beginning of a sweep is marked by SWP_SCI.SEQ_NUMBER=0
132
+ (Sequence number of set of steps in energy sweep);
133
+ end of a sweep is marked by SWP_SCI.SEQ_NUMBER=11;
134
+ In this function, we look for index of SEQ_NUMBER 0.
135
+
136
+ Brandon Stone helped developed this algorithm.
137
+
138
+ Parameters
139
+ ----------
140
+ packets : xarray.Dataset
141
+ Dataset that contains SWP_SCI packets.
142
+
143
+ Returns
144
+ -------
145
+ indices_start : numpy.ndarray
146
+ Array of indices of start cycle.
147
+ """
148
+ if packets["shcoarse"].size < 12:
149
+ return np.array([], np.int64)
150
+
151
+ # calculate time difference between consecutive sweep
152
+ diff = packets["shcoarse"].data[1:] - packets["shcoarse"].data[:-1]
153
+ # Time difference between consecutive sweep should be 1 second.
154
+ ione = diff == 1 # 1 second
155
+
156
+ # This uses sliding window to find index where cycle starts.
157
+ # This is what this below code line is doing:
158
+ # [1 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0] # Is cycle zero?
159
+ # [1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1] # Next diff is one?
160
+ # [1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0] # Next diff is one?
161
+ # [0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0] # Next diff is one?
162
+ #
163
+ # [0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0] # And all?
164
+
165
+ valid = (
166
+ (packets["seq_number"] == 0)[:-11]
167
+ & ione[:-10]
168
+ & ione[1:-9]
169
+ & ione[2:-8]
170
+ & ione[3:-7]
171
+ & ione[4:-6]
172
+ & ione[5:-5]
173
+ & ione[6:-4]
174
+ & ione[7:-3]
175
+ & ione[8:-2]
176
+ & ione[9:-1]
177
+ & ione[10:]
178
+ )
179
+ return np.where(valid)[0]
180
+
181
+
182
+ def get_indices_of_full_sweep(packets: xr.Dataset) -> npt.NDArray:
183
+ """
184
+ Get indices of full cycles.
185
+
186
+ Beginning of a sweep is marked by SWP_SCI.SEQ_NUMBER=0
187
+ (Sequence number of set of steps in energy sweep);
188
+ end of a sweep is marked by SWP_SCI.SEQ_NUMBER=11;
189
+ all packets must be present to process a sweep.
190
+
191
+ In this function, we get the indices of SEQ_NUMBER
192
+ 0 and then construct full sweep indices.
193
+
194
+ Parameters
195
+ ----------
196
+ packets : xarray.Dataset
197
+ Dataset that contains SEQ_NUMBER data information.
198
+ Eg. sci_dataset["SEQ_NUMBER"].data.
199
+
200
+ Returns
201
+ -------
202
+ full_cycle_indices : numpy.ndarray
203
+ 1D array with indices of full cycle data.
204
+ """
205
+ indices_of_start = find_sweep_starts(packets)
206
+ # find_sweep_starts[..., None] creates array of shape(n, 1).
207
+ # Eg. [[3], [8]]
208
+ # np.arange(12)[None, ...] creates array of shape(1, 12)
209
+ # Eg. [[0, 1, 2, 3, ....., 11]]
210
+ # then we add both of them together to get an array of shape(n, 4)
211
+ # Eg. [[3, 4, 5, 6,...14], [8, 9, 10, 11, ..., 19]]
212
+ full_cycles_indices = indices_of_start[..., None] + np.arange(12)[None, ...]
213
+ return full_cycles_indices.reshape(-1)
214
+
215
+
216
+ def process_sweep_data(full_sweep_sci: xr.Dataset, cem_prefix: str) -> xr.Dataset:
217
+ """
218
+ Group full sweep data into correct sequence order.
219
+
220
+ Data from each packet comes like this:
221
+
222
+ | SEQ_NUMBER
223
+ | .
224
+ | PCEM_RNG_ST0
225
+ | SCEM_RNG_ST0
226
+ | COIN_RNG_ST0
227
+ | PCEM_RNG_ST1
228
+ | SCEM_RNG_ST1
229
+ | COIN_RNG_ST1
230
+ | PCEM_RNG_ST2
231
+ | SCEM_RNG_ST2
232
+ | COIN_RNG_ST2
233
+ | PCEM_RNG_ST3
234
+ | SCEM_RNG_ST3
235
+ | COIN_RNG_ST3
236
+ | PCEM_RNG_ST4
237
+ | SCEM_RNG_ST4
238
+ | COIN_RNG_ST4
239
+ | PCEM_RNG_ST5
240
+ | SCEM_RNG_ST5
241
+ | COIN_RNG_ST5
242
+ | PCEM_CNT0
243
+ | SCEM_CNT0
244
+ | COIN_CNT0
245
+ | PCEM_CNT1
246
+ | SCEM_CNT1
247
+ | COIN_CNT1
248
+ | PCEM_CNT2
249
+ | SCEM_CNT2
250
+ | COIN_CNT2
251
+ | PCEM_CNT3
252
+ | SCEM_CNT3
253
+ | COIN_CNT3
254
+ | PCEM_CNT4
255
+ | SCEM_CNT4
256
+ | COIN_CNT4
257
+ | PCEM_CNT5
258
+ | SCEM_CNT5
259
+ | COIN_CNT5
260
+
261
+ When we read all packets and store data for above fields, it
262
+ looks like this:
263
+
264
+ | SEQ_NUMBER -> [0, 1, 2, 3, 4,..., 11, 1, 2, ......, 9, 10, 11]
265
+ | PCEM_RNG_ST0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
266
+ | SCEM_RNG_ST0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
267
+ | COIN_RNG_ST0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
268
+ | PCEM_RNG_ST1 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
269
+ | SCEM_RNG_ST1 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
270
+ | COIN_RNG_ST1 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
271
+ | ....
272
+ | PCEM_RNG_ST5 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
273
+ | SCEM_RNG_ST5 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
274
+ | PCEM_CNT_0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
275
+ | SCEM_CNT_0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
276
+ | COIN_CNT_0 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
277
+ | ....
278
+ | PCEM_CNT_5 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
279
+ | SCEM_CNT_5 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
280
+ | COIN_CNT_5 -> [x, x, x, x, x,..., x, x, x, ..., x, x, x]
281
+
282
+ This function reads each sweep data in this order:
283
+
284
+ | PCEM_CNT0 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
285
+ | PCEM_CNT1 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
286
+ | PCEM_CNT2 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
287
+ | PCEM_CNT3 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
288
+ | PCEM_CNT4 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
289
+ | PCEM_CNT5 --> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
290
+
291
+ This example show for PCEM_CNT but same logic applies
292
+ to SCEM_CNT, COIN_CNT, PCEM_RNG, SCEM_RNG, and COIN_RNG.
293
+
294
+ In the final L1A product of (total_number_of_sweep x 72) array where
295
+ we store final PCEM, SCEM, COIN counts or compression indicator
296
+ such as PCEM_RNG, SCEM_RNG, COIN_RNG,
297
+ we want data in this order. Transpose of above layout
298
+
299
+ | 0, 0, 0, 0, 0, 0,
300
+ | 1, 1, 1, 1, 1, 1,
301
+ | 2, 2, 2, 2, 2, 2,
302
+ | 3, 3, 3, 3, 3, 3,
303
+ | ....,
304
+ | 11, 11, 11, 11, 11, 11.
305
+
306
+ Reordering in this order is reordering all data of
307
+ sequence 0 first, then sequence 1, then sequence 2,
308
+ and so on until sequence 11.
309
+
310
+ Parameters
311
+ ----------
312
+ full_sweep_sci : xarray.Dataset
313
+ Full dataset.
314
+ cem_prefix : str
315
+ Indicate which CEM or its flag we are processing.
316
+ Options are:
317
+
318
+ | PCEM_CNT
319
+ | SCEM_CNT
320
+ | COIN_CNT
321
+ | PCEM_RNG_ST
322
+ | SCEM_RNG_ST
323
+ | COIN_RNG_ST.
324
+
325
+ Returns
326
+ -------
327
+ all_cem_data : xarray.Dataset
328
+ Correctly order dataset.
329
+ """
330
+ # First, concat all CEM data
331
+ current_cem_counts = np.concatenate(
332
+ (
333
+ full_sweep_sci[f"{cem_prefix}0"],
334
+ full_sweep_sci[f"{cem_prefix}1"],
335
+ full_sweep_sci[f"{cem_prefix}2"],
336
+ full_sweep_sci[f"{cem_prefix}3"],
337
+ full_sweep_sci[f"{cem_prefix}4"],
338
+ full_sweep_sci[f"{cem_prefix}5"],
339
+ ),
340
+ axis=0,
341
+ )
342
+
343
+ # Next:
344
+ # Reshape data by CEM, number of sweeps and sequence counts.
345
+ # Therefore, the data shape is 6 x total_full_sweeps x 12
346
+ # Output looks like this:
347
+ # [
348
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
349
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
350
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]
351
+
352
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
353
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
354
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]
355
+
356
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
357
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
358
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]
359
+
360
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
361
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
362
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]
363
+
364
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
365
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
366
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]
367
+
368
+ # [[ 0 1 2 3 4 5 6 7 8 9 10 11]
369
+ # [ 1 2 3 4 5 6 7 8 9 10 11 12]
370
+ # [ 2 3 4 5 6 7 8 9 10 11 12 13]]]
371
+ # In other word, we grouped each cem's
372
+ # data by full sweep.
373
+ current_cem_counts = current_cem_counts.reshape(6, -1, 12)
374
+
375
+ # Then, we go from above to
376
+ # to this final output:
377
+ # [
378
+ # [[0 0 0 0 0 0]
379
+ # [1 1 1 1 1 1]
380
+ # [2 2 2 2 2 2]
381
+ # [3 3 3 3 3 3]
382
+ # [4 4 4 4 4 4]
383
+ # [5 5 5 5 5 5]
384
+ # [6 6 6 6 6 6]
385
+ # [7 7 7 7 7 7]
386
+ # [8 8 8 8 8 8]
387
+ # [9 9 9 9 9 9]
388
+ # [10 10 10 10 10 10]
389
+ # [11 11 11 11 11 11]],
390
+ #
391
+ # [[1 1 1 1 1 1]
392
+ # [2 2 2 2 2 2]
393
+ # [3 3 3 3 3 3]
394
+ # ...
395
+ # [12 12 12 12 12 12]],
396
+ #
397
+ # [[2 2 2 2 2 2]
398
+ # [3 3 3 3 3 3]
399
+ # ...
400
+ # [13 13 13 13 13 13]]
401
+ # ]
402
+ # In other word, we grouped by sequence. The shape
403
+ # of this transformed array is total_full_sweeps x 12 x 6
404
+ all_cem_data = np.stack(current_cem_counts, axis=-1)
405
+ # This line just flatten the inner most array to
406
+ # (total_full_sweeps x 72)
407
+ all_cem_data = all_cem_data.reshape(-1, 72)
408
+ return all_cem_data
409
+
410
+
411
+ def process_swapi_science(
412
+ sci_dataset: xr.Dataset, hk_dataset: xr.Dataset, data_version: str
413
+ ) -> xr.Dataset:
414
+ """
415
+ Will process SWAPI science data and create CDF file.
416
+
417
+ Parameters
418
+ ----------
419
+ sci_dataset : xarray.Dataset
420
+ L0 data.
421
+ hk_dataset : xarray.Dataset
422
+ Housekeeping data.
423
+ data_version : str
424
+ Version of the data product being created.
425
+
426
+ Returns
427
+ -------
428
+ dataset : xarray.Dataset
429
+ Dataset.
430
+ """
431
+ # ====================================================
432
+ # Step 1: Filter full cycle data
433
+ # ====================================================
434
+ full_sweep_indices = get_indices_of_full_sweep(sci_dataset)
435
+
436
+ # Filter full sweep data using indices returned from above line
437
+ full_sweep_sci = sci_dataset.isel({"epoch": full_sweep_indices})
438
+
439
+ # Find indices of good sweep cycles
440
+ good_data_indices = filter_good_data(full_sweep_sci)
441
+
442
+ good_sweep_sci = full_sweep_sci.isel({"epoch": good_data_indices})
443
+
444
+ # ====================================================
445
+ # Step 2: Process good sweep data
446
+ # ====================================================
447
+ total_packets = len(good_sweep_sci["seq_number"].data)
448
+
449
+ # It takes 12 sequence data to make one full sweep
450
+ total_sequence = 12
451
+ total_full_sweeps = total_packets // total_sequence
452
+ # These array will be of size (number of good sweep, 72)
453
+ raw_pcem_count = process_sweep_data(good_sweep_sci, "pcem_cnt")
454
+ raw_scem_count = process_sweep_data(good_sweep_sci, "scem_cnt")
455
+ raw_coin_count = process_sweep_data(good_sweep_sci, "coin_cnt")
456
+ pcem_compression_flags = process_sweep_data(good_sweep_sci, "pcem_rng_st")
457
+ scem_compression_flags = process_sweep_data(good_sweep_sci, "scem_rng_st")
458
+ coin_compression_flags = process_sweep_data(good_sweep_sci, "coin_rng_st")
459
+
460
+ swp_pcem_counts = decompress_count(raw_pcem_count, pcem_compression_flags)
461
+ swp_scem_counts = decompress_count(raw_scem_count, scem_compression_flags)
462
+ swp_coin_counts = decompress_count(raw_coin_count, coin_compression_flags)
463
+
464
+ # ====================================================
465
+ # Load the CDF attributes
466
+ # ====================================================
467
+ cdf_manager = ImapCdfAttributes()
468
+ cdf_manager.add_instrument_global_attrs("swapi")
469
+ cdf_manager.load_variable_attributes("imap_swapi_variable_attrs.yaml")
470
+
471
+ # ===================================================================
472
+ # Quality flags
473
+ # ===================================================================
474
+ quality_flags_data = np.zeros((total_full_sweeps, 72), np.uint16)
475
+
476
+ # Add science data quality flags
477
+ quality_flags_data[pcem_compression_flags == 1] |= SWAPIFlags.SWP_PCEM_COMP.value
478
+ quality_flags_data[scem_compression_flags == 1] |= SWAPIFlags.SWP_SCEM_COMP.value
479
+ quality_flags_data[coin_compression_flags == 1] |= SWAPIFlags.SWP_COIN_COMP.value
480
+
481
+ # Add housekeeping-derived quality flags
482
+ # --------------------------------------
483
+ # Get times of good and full sweep data from science dataset.
484
+ # Then use these times to get housekeeping data. Something is wrong if
485
+ # there is no science data that matches exactly one housekeeping data. It
486
+ # should be one-to-one matching per SWAPI team, Jamie Rankin.
487
+ good_sweep_times = good_sweep_sci["epoch"].data
488
+ good_sweep_hk_data = hk_dataset.sel({"epoch": good_sweep_times})
489
+
490
+ # Since there is one SWAPI HK packet for each SWAPI SCI packet,
491
+ # and both are recorded at 1 Hz (1 packet per second),
492
+ # we can leverage this to set the quality flags for each science
493
+ # packet's data. Each SWAPI science packet represents
494
+ # one sequence of data, where the sequence includes measurements
495
+ # like PCEM_CNT0, PCEM_CNT1, PCEM_CNT2, PCEM_CNT3,
496
+ # PCEM_CNT4, and PCEM_CNT5. Because all these measurements come
497
+ # from the same science packet, they should share
498
+ # the same HK quality flag. This is why the HK quality flag is
499
+ # repeated 6 times, once for each measurement within
500
+ # the sequence (each packet corresponds to one sequence).
501
+
502
+ hk_flags_name = [
503
+ "OVR_T_ST",
504
+ "UND_T_ST",
505
+ "PCEM_CNT_ST",
506
+ "SCEM_CNT_ST",
507
+ "PCEM_V_ST",
508
+ "PCEM_I_ST",
509
+ "PCEM_INT_ST",
510
+ "SCEM_V_ST",
511
+ "SCEM_I_ST",
512
+ "SCEM_INT_ST",
513
+ ]
514
+
515
+ for flag_name in hk_flags_name:
516
+ current_flag = np.repeat(good_sweep_hk_data[flag_name.lower()].data, 6).reshape(
517
+ -1, 72
518
+ )
519
+ # Use getattr to dynamically access the flag in SWAPIFlags class
520
+ flag_to_set = getattr(SWAPIFlags, flag_name)
521
+ # set the quality flag for each data
522
+ quality_flags_data[current_flag == 1] |= flag_to_set.value
523
+
524
+ swp_flags = xr.DataArray(
525
+ quality_flags_data,
526
+ dims=["epoch", "energy"],
527
+ attrs=cdf_manager.get_variable_attributes("flags_default"),
528
+ )
529
+
530
+ # ===================================================================
531
+ # Step 3: Create xarray.Dataset
532
+ # ===================================================================
533
+
534
+ # epoch time. Should be same dimension as number of good sweeps
535
+ epoch_values = good_sweep_sci["epoch"].data.reshape(total_full_sweeps, 12)[:, 0]
536
+
537
+ epoch_time = xr.DataArray(
538
+ epoch_values,
539
+ name="epoch",
540
+ dims=["epoch"],
541
+ attrs=cdf_manager.get_variable_attributes("epoch"),
542
+ )
543
+
544
+ # There are 72 energy steps
545
+ energy = xr.DataArray(
546
+ np.arange(72),
547
+ name="energy",
548
+ dims=["energy"],
549
+ attrs=cdf_manager.get_variable_attributes("energy"),
550
+ )
551
+ # LABL_PTR_1 should be CDF_CHAR.
552
+ energy_label = xr.DataArray(
553
+ energy.values.astype(str),
554
+ name="energy_label",
555
+ dims=["energy_label"],
556
+ attrs=cdf_manager.get_variable_attributes("energy_label"),
557
+ )
558
+
559
+ # Add other global attributes
560
+ # TODO: add others like below once add_global_attribute is fixed
561
+ cdf_manager.add_global_attribute("Data_version", data_version)
562
+ l1_global_attrs = cdf_manager.get_global_attributes("imap_swapi_l1_sci")
563
+ l1_global_attrs["Sweep_table"] = f"{sci_dataset['sweep_table'].data[0]}"
564
+ l1_global_attrs["Plan_id"] = f"{sci_dataset['plan_id_science'].data[0]}"
565
+ l1_global_attrs["Apid"] = f"{sci_dataset['pkt_apid'].data[0]}"
566
+
567
+ dataset = xr.Dataset(
568
+ coords={
569
+ "epoch": epoch_time,
570
+ "energy": energy,
571
+ "energy_label": energy_label,
572
+ },
573
+ attrs=l1_global_attrs,
574
+ )
575
+
576
+ dataset["swp_pcem_counts"] = xr.DataArray(
577
+ np.array(swp_pcem_counts, dtype=np.uint16),
578
+ dims=["epoch", "energy"],
579
+ attrs=cdf_manager.get_variable_attributes("pcem_counts"),
580
+ )
581
+ dataset["swp_scem_counts"] = xr.DataArray(
582
+ np.array(swp_scem_counts, dtype=np.uint16),
583
+ dims=["epoch", "energy"],
584
+ attrs=cdf_manager.get_variable_attributes("scem_counts"),
585
+ )
586
+ dataset["swp_coin_counts"] = xr.DataArray(
587
+ np.array(swp_coin_counts, dtype=np.uint16),
588
+ dims=["epoch", "energy"],
589
+ attrs=cdf_manager.get_variable_attributes("coin_counts"),
590
+ )
591
+
592
+ # Add quality flags to the dataset
593
+ dataset["swp_flags"] = swp_flags
594
+ # ===================================================================
595
+ # Step 4: Calculate uncertainty
596
+ # ===================================================================
597
+ # Uncertainty in counts formula:
598
+ # Uncertainty is quantified for the PCEM, SCEM, and COIN counts.
599
+ # The Poisson contribution is
600
+ # uncertainty = sqrt(count)
601
+ # TODO:
602
+ # Above uncertaintly formula will change in the future.
603
+ # Replace it with actual formula once SWAPI provides it.
604
+ # Right now, we are using sqrt(count) as a placeholder
605
+ dataset["swp_pcem_err_plus"] = xr.DataArray(
606
+ np.sqrt(swp_pcem_counts),
607
+ dims=["epoch", "energy"],
608
+ attrs=cdf_manager.get_variable_attributes("pcem_uncertainty"),
609
+ )
610
+ dataset["swp_pcem_err_minus"] = xr.DataArray(
611
+ np.sqrt(swp_pcem_counts),
612
+ dims=["epoch", "energy"],
613
+ attrs=cdf_manager.get_variable_attributes("pcem_uncertainty"),
614
+ )
615
+ dataset["swp_scem_err_plus"] = xr.DataArray(
616
+ np.sqrt(swp_scem_counts),
617
+ dims=["epoch", "energy"],
618
+ attrs=cdf_manager.get_variable_attributes("scem_uncertainty"),
619
+ )
620
+ dataset["swp_scem_err_minus"] = xr.DataArray(
621
+ np.sqrt(swp_scem_counts),
622
+ dims=["epoch", "energy"],
623
+ attrs=cdf_manager.get_variable_attributes("scem_uncertainty"),
624
+ )
625
+ dataset["swp_coin_err_plus"] = xr.DataArray(
626
+ np.sqrt(swp_coin_counts),
627
+ dims=["epoch", "energy"],
628
+ attrs=cdf_manager.get_variable_attributes("coin_uncertainty"),
629
+ )
630
+ dataset["swp_coin_err_minus"] = xr.DataArray(
631
+ np.sqrt(swp_coin_counts),
632
+ dims=["epoch", "energy"],
633
+ attrs=cdf_manager.get_variable_attributes("coin_uncertainty"),
634
+ )
635
+ # TODO: when SWAPI gives formula to calculate this scenario:
636
+ # Compression of counts also contributes to the uncertainty.
637
+ # an empirical expression to estimate the error.
638
+
639
+ return dataset
640
+
641
+
642
+ def swapi_l1(file_path: str, data_version: str) -> xr.Dataset:
643
+ """
644
+ Will process SWAPI level 0 data to level 1.
645
+
646
+ Parameters
647
+ ----------
648
+ file_path : str
649
+ Path to SWAPI L0 file.
650
+ data_version : str
651
+ Version of the data product being created.
652
+
653
+ Returns
654
+ -------
655
+ processed_data : xarray.Dataset
656
+ Set of processed data.
657
+ """
658
+ xtce_definition = (
659
+ f"{imap_module_directory}/swapi/packet_definitions/swapi_packet_definition.xml"
660
+ )
661
+ datasets = packet_file_to_datasets(
662
+ file_path, xtce_definition, use_derived_value=False
663
+ )
664
+ processed_data = []
665
+
666
+ for apid, ds_data in datasets.items():
667
+ # Right now, we only process SWP_HK and SWP_SCI
668
+ # other packets are not process in this processing pipeline
669
+ # If appId is science, then the file should contain all data of science appId
670
+
671
+ if apid == SWAPIAPID.SWP_SCI.value:
672
+ sci_dataset = process_swapi_science(
673
+ ds_data, datasets[SWAPIAPID.SWP_HK], data_version
674
+ )
675
+ processed_data.append(sci_dataset)
676
+ if apid == SWAPIAPID.SWP_HK.value:
677
+ # Add HK datalevel attrs
678
+ # TODO: ask SWAPI if we need to process HK if we can use WebPODA
679
+ hk_attrs = ImapCdfAttributes()
680
+ hk_attrs.add_instrument_global_attrs("swapi")
681
+ hk_attrs.add_global_attribute("Data_version", data_version)
682
+ ds_data.attrs.update(hk_attrs.get_global_attributes("imap_swapi_l1_hk"))
683
+ processed_data.append(ds_data)
684
+
685
+ return processed_data
File without changes