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,49 @@
1
+ """Contains code to perform SWE L1b processing."""
2
+
3
+ import logging
4
+
5
+ import xarray as xr
6
+
7
+ from imap_processing import imap_module_directory
8
+ from imap_processing.swe.l1b.swe_l1b_science import swe_l1b_science
9
+ from imap_processing.swe.utils.swe_utils import SWEAPID
10
+ from imap_processing.utils import convert_raw_to_eu
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def swe_l1b(l1a_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
16
+ """
17
+ Will process data to L1B.
18
+
19
+ Parameters
20
+ ----------
21
+ l1a_dataset : xarray.Dataset
22
+ The l1a data input.
23
+ data_version : str
24
+ Version of the data product being created.
25
+
26
+ Returns
27
+ -------
28
+ data : xarray.Dataset
29
+ Processed data to L1B.
30
+ """
31
+ apid = int(l1a_dataset.attrs["packet_apid"])
32
+
33
+ # convert value from raw to engineering units as needed
34
+ conversion_table_path = str(
35
+ imap_module_directory / "swe/l1b/engineering_unit_convert_table.csv"
36
+ )
37
+ # Look up packet name from APID
38
+ packet_name = next(packet for packet in SWEAPID if packet.value == apid)
39
+
40
+ # Convert raw data to engineering units as needed
41
+ eu_data = convert_raw_to_eu(
42
+ l1a_dataset,
43
+ conversion_table_path=conversion_table_path,
44
+ packet_name=packet_name.name,
45
+ )
46
+ data = swe_l1b_science(eu_data, data_version)
47
+ if data is None:
48
+ logger.info("No data to write to CDF")
49
+ return data
@@ -0,0 +1,557 @@
1
+ """Contains code to perform SWE L1b science processing."""
2
+
3
+ import logging
4
+ from typing import Any
5
+
6
+ import numpy as np
7
+ import numpy.typing as npt
8
+ import pandas as pd
9
+ import xarray as xr
10
+
11
+ from imap_processing import imap_module_directory
12
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # ESA voltage and index in the final data table
17
+ esa_voltage_row_index_dict = {
18
+ 0.56: 0,
19
+ 0.78: 1,
20
+ 1.08: 2,
21
+ 1.51: 3,
22
+ 2.10: 4,
23
+ 2.92: 5,
24
+ 4.06: 6,
25
+ 5.64: 7,
26
+ 7.85: 8,
27
+ 10.92: 9,
28
+ 15.19: 10,
29
+ 21.13: 11,
30
+ 29.39: 12,
31
+ 40.88: 13,
32
+ 56.87: 14,
33
+ 79.10: 15,
34
+ 110.03: 16,
35
+ 153.05: 17,
36
+ 212.89: 18,
37
+ 296.14: 19,
38
+ 411.93: 20,
39
+ 572.99: 21,
40
+ 797.03: 22,
41
+ 1108.66: 23,
42
+ }
43
+
44
+
45
+ def read_lookup_table(table_index_value: int) -> Any:
46
+ """
47
+ Read lookup table from file.
48
+
49
+ Parameters
50
+ ----------
51
+ table_index_value : int
52
+ ESA table index number.
53
+
54
+ Returns
55
+ -------
56
+ list
57
+ Line from lookup table todo check.
58
+ """
59
+ # This is equivalent of os.path.join in Path
60
+ lookup_table_filepath = imap_module_directory / "swe/l1b/swe_esa_lookup_table.csv"
61
+ lookup_table = pd.read_csv(
62
+ lookup_table_filepath,
63
+ index_col="e_step",
64
+ )
65
+
66
+ if table_index_value == 0:
67
+ return lookup_table.loc[lookup_table["table_index"] == 0]
68
+ elif table_index_value == 1:
69
+ return lookup_table.loc[lookup_table["table_index"] == 1]
70
+ else:
71
+ raise ValueError("Error: Invalid table index value")
72
+
73
+
74
+ def deadtime_correction(counts: np.ndarray, acq_duration: int) -> npt.NDArray:
75
+ """
76
+ Calculate deadtime correction.
77
+
78
+ Deadtime correction is a technique used in various fields, including
79
+ nuclear physics, radiation detection, and particle counting, to compensate
80
+ for the effects of the time period during which a detector is not able to
81
+ record new events or measurements after detecting a previous event.
82
+ This "deadtime" is essentially the time during which the detector is
83
+ recovering from the previous detection and is unable to detect new events.
84
+
85
+ In particle detectors, there is a finite time required for the detector to
86
+ reset or recover after detecting a particle. During this deadtime, any
87
+ subsequent particles that may have arrived go undetected. As a result,
88
+ the recorded count rate appears to be lower than the actual count rate.
89
+
90
+ Deadtime correction involves mathematically adjusting the measured count
91
+ rates to compensate for this deadtime effect. This correction is crucial
92
+ when dealing with high-intensity sources or particle fluxes, as the deadtime
93
+ can significantly affect the accuracy of the measurements.
94
+
95
+ Deadtime correction is important to ensure accurate measurements and data
96
+ analysis in fields where event detection rates are high and where every
97
+ detected event is critical for understanding physical processes.
98
+
99
+ Parameters
100
+ ----------
101
+ counts : numpy.ndarray
102
+ Counts data before deadtime corrections.
103
+ acq_duration : int
104
+ This is ACQ_DURATION from science packet.
105
+
106
+ Returns
107
+ -------
108
+ corrected_count : numpy.ndarray
109
+ Corrected counts.
110
+ """
111
+ # deadtime will be constant once it's defined.
112
+ # This deadtime value is from previous mission. SWE
113
+ # will give new one once they have it ready.
114
+ # TODO: update deadtime when we get new number
115
+ deadtime = 1.5e-6
116
+ correct = 1.0 - (deadtime * counts / acq_duration)
117
+ correct = np.maximum(0.1, correct)
118
+ corrected_count = np.divide(counts, correct)
119
+ return corrected_count
120
+
121
+
122
+ def convert_counts_to_rate(data: np.ndarray, acq_duration: int) -> npt.NDArray:
123
+ """
124
+ Convert counts to rate using sampling time.
125
+
126
+ acq_duration is ACQ_DURATION from science packet.
127
+
128
+ Parameters
129
+ ----------
130
+ data : numpy.ndarray
131
+ Counts data.
132
+ acq_duration : int
133
+ Acquisition duration. acq_duration is in millieseconds.
134
+
135
+ Returns
136
+ -------
137
+ numpy.ndarray
138
+ Count rates array in seconds.
139
+ """
140
+ # convert milliseconds to seconds
141
+ # Todo: check with SWE team about int or float types.
142
+ acq_duration = int(acq_duration / 1000.0)
143
+ return data / acq_duration
144
+
145
+
146
+ def calculate_calibration_factor(time: int) -> None:
147
+ """
148
+ Calculate calibration factor.
149
+
150
+ Steps to calculate calibration factor:
151
+
152
+ 1. Convert input time to match time format in the calibration data file.
153
+ 2. Find the nearest in time calibration data point.
154
+ 3. Linear interpolate between those two nearest time and get factor for input time.
155
+
156
+ What this function is doing:
157
+
158
+ | 1. **Reading Calibration Data**: The function first reads a file containing
159
+ | calibration data for electron measurements over time. This data helps
160
+ | adjust or correct the measurements based on changes in the instrument's
161
+ | sensitivity.
162
+
163
+ | 2. **Interpolating Calibration Factors**: Imagine you have several points on
164
+ | a graph, and you want to estimate values between those points. In our case,
165
+ | these points represent calibration measurements taken at different times.
166
+ | The function figures out which two calibration points are closest in time
167
+ | to the specific measurement time you're interested in.
168
+
169
+ | 3. **Calculating Factors**: Once it finds these two nearby calibration points,
170
+ | the function calculates a correction factor by drawing a straight line
171
+ | between them (linear interpolation). This factor helps adjust the measurement
172
+ | to make it more accurate, considering how the instrument's sensitivity changed
173
+ | between those two calibration points.
174
+
175
+ | 4. **Returning the Correction Factor**: Finally, the function returns this
176
+ | correction factor. You can then use this factor to adjust or calibrate your
177
+ | measurements at the specific time you're interested in. This ensures that
178
+ | your measurements are as accurate as possible, taking into account the
179
+ | instrument's changing sensitivity over time.
180
+
181
+ Parameters
182
+ ----------
183
+ time : int
184
+ Input time.
185
+ """
186
+ # NOTE: waiting on fake calibration data to write this.
187
+ pass
188
+
189
+
190
+ def apply_in_flight_calibration(data: np.ndarray) -> None:
191
+ """
192
+ Apply in flight calibration to full cycle data.
193
+
194
+ These factors are used to account for changes in gain with time.
195
+
196
+ They are derived from the weekly electron calibration data.
197
+
198
+ Parameters
199
+ ----------
200
+ data : numpy.ndarray
201
+ Full cycle data array.
202
+ """
203
+ # calculate calibration factor
204
+ # Apply to all data
205
+ pass
206
+
207
+
208
+ def populate_full_cycle_data(
209
+ l1a_data: xr.Dataset, packet_index: int, esa_table_num: int
210
+ ) -> npt.NDArray:
211
+ """
212
+ Populate full cycle data array using esa lookup table and l1a_data.
213
+
214
+ Parameters
215
+ ----------
216
+ l1a_data : xarray.Dataset
217
+ L1a data with full cycle data only.
218
+ packet_index : int
219
+ Index of current packet in the whole packet list.
220
+ esa_table_num : int
221
+ ESA lookup table number.
222
+
223
+ Returns
224
+ -------
225
+ numpy.ndarray
226
+ Array with full cycle data populated.
227
+ """
228
+ esa_lookup_table = read_lookup_table(esa_table_num)
229
+
230
+ # If esa lookup table number is 0, then populate using esa lookup table data
231
+ # with information that esa step ramps up in even column and ramps down
232
+ # in odd column every six steps.
233
+ if esa_table_num == 0:
234
+ # create new full cycle data array
235
+ full_cycle_data = np.zeros((24, 30, 7))
236
+
237
+ # Initialize esa_step_number and column_index.
238
+ # esa_step_number goes from 0 to 719 range where
239
+ # 720 came from 24 x 30. full_cycle_data array has (24, 30)
240
+ # dimension.
241
+ esa_step_number = 0
242
+ # column_index goes from 0 to 29 range where
243
+ # 30 came from 30 column in full_cycle_data array
244
+ column_index = -1
245
+
246
+ # Go through four quarter cycle data packets
247
+ for index in range(4):
248
+ decompressed_counts = l1a_data["science_data"].data[packet_index + index]
249
+ # Do deadtime correction
250
+ acq_duration = l1a_data["acq_duration"].data[packet_index + index]
251
+ corrected_counts = deadtime_correction(decompressed_counts, acq_duration)
252
+ # Convert counts to rate
253
+ counts_rate = convert_counts_to_rate(corrected_counts, acq_duration)
254
+
255
+ # Go through each quarter cycle's 180 ESA measurements
256
+ # and put counts rate in full cycle data array
257
+ for step in range(180):
258
+ # Get esa voltage value from esa lookup table and
259
+ # use that to get row index in full data array
260
+ esa_voltage_value = esa_lookup_table.loc[esa_step_number]["esa_v"]
261
+ esa_voltage_row_index = esa_voltage_row_index_dict[esa_voltage_value]
262
+
263
+ # every six steps, increment column index
264
+ if esa_step_number % 6 == 0:
265
+ column_index += 1
266
+ # Put counts rate in full cycle data array
267
+ full_cycle_data[esa_voltage_row_index][column_index] = counts_rate[step]
268
+ esa_step_number += 1
269
+
270
+ # reset column index for next quarter cycle
271
+ column_index = -1
272
+ # TODO: Apply in flight calibration to full cycle data
273
+
274
+ # NOTE: We may get more lookup table with different setup when we get real
275
+ # data. But for now, we are advice to continue with current setup and can
276
+ # add/change it when we get real data.
277
+
278
+ return full_cycle_data
279
+
280
+
281
+ def find_cycle_starts(cycles: np.ndarray) -> npt.NDArray:
282
+ """
283
+ Find index of where new cycle started.
284
+
285
+ Brandon Stone helped developed this algorithm.
286
+
287
+ Parameters
288
+ ----------
289
+ cycles : numpy.ndarray
290
+ Array that contains quarter cycle information.
291
+
292
+ Returns
293
+ -------
294
+ numpy.ndarray
295
+ Array of indices of start cycle.
296
+ """
297
+ if cycles.size < 4:
298
+ return np.array([], np.int64)
299
+
300
+ # calculate difference between consecutive cycles
301
+ diff = cycles[1:] - cycles[:-1]
302
+
303
+ # This uses sliding window to find index where cycle starts.
304
+ # This is what this below code line is doing:
305
+ # [1 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0] # Is cycle zero?
306
+ # [1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1] # Next diff is one?
307
+ # [1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0] # Next diff is one?
308
+ # [0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0] # Next diff is one?
309
+ #
310
+ # [0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0] # And all?
311
+ ione = diff == 1
312
+ valid = (cycles == 0)[:-3] & ione[:-2] & ione[1:-1] & ione[2:]
313
+ return np.where(valid)[0]
314
+
315
+
316
+ def get_indices_of_full_cycles(quarter_cycle: np.ndarray) -> npt.NDArray:
317
+ """
318
+ Get indices of full cycles.
319
+
320
+ Parameters
321
+ ----------
322
+ quarter_cycle : numpy.ndarray
323
+ Array that contains quarter cycles information.
324
+
325
+ Returns
326
+ -------
327
+ numpy.ndarray
328
+ 1D array with indices of full cycle data.
329
+ """
330
+ indices_of_start = find_cycle_starts(quarter_cycle)
331
+ # indices_of_start[..., None] creates array of shape(n, 1).
332
+ # Eg. [[3], [8]]
333
+ # np.arange(4)[None, ...] creates array of shape(1, 4)
334
+ # Eg. [[0, 1, 2, 3]]
335
+ # then we add both of them together to get an array of shape(n, 4)
336
+ # Eg. [[3, 4, 5, 6], [8, 9, 10, 11]]
337
+ full_cycles_indices = indices_of_start[..., None] + np.arange(4)[None, ...]
338
+ return full_cycles_indices.reshape(-1)
339
+
340
+
341
+ def filter_full_cycle_data(
342
+ full_cycle_data_indices: np.ndarray, l1a_data: xr.Dataset
343
+ ) -> xr.Dataset:
344
+ """
345
+ Filter metadata and science of packets that makes full cycles.
346
+
347
+ Parameters
348
+ ----------
349
+ full_cycle_data_indices : numpy.ndarray
350
+ Array with indices of full cycles.
351
+ l1a_data : xarray.Dataset
352
+ L1A dataset.
353
+
354
+ Returns
355
+ -------
356
+ xarray.Dataset
357
+ L1A dataset with filtered metadata.
358
+ """
359
+ for key, value in l1a_data.items():
360
+ l1a_data[key] = value.data[full_cycle_data_indices]
361
+ return l1a_data
362
+
363
+
364
+ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
365
+ """
366
+ SWE l1b science processing.
367
+
368
+ Parameters
369
+ ----------
370
+ l1a_data : xarray.Dataset
371
+ Input data.
372
+ data_version : str
373
+ Version of the data product being created.
374
+
375
+ Returns
376
+ -------
377
+ xarray.Dataset
378
+ Processed l1b data.
379
+ """
380
+ total_packets = len(l1a_data["science_data"].data)
381
+
382
+ # Array to store list of table populated with data
383
+ # of full cycles
384
+ all_data = []
385
+ packet_index = 0
386
+ l1a_data_copy = l1a_data.copy(deep=True)
387
+
388
+ full_cycle_data_indices = get_indices_of_full_cycles(l1a_data["quarter_cycle"].data)
389
+ logger.debug(
390
+ f"Quarter cycle data before filtering: {l1a_data_copy['quarter_cycle'].data}"
391
+ )
392
+
393
+ # Delete Raw Science Data from l1b and onwards
394
+ del l1a_data_copy["raw_science_data"]
395
+
396
+ if full_cycle_data_indices.size == 0:
397
+ # Log that no data is found for science data
398
+ return None
399
+
400
+ if len(full_cycle_data_indices) != total_packets:
401
+ # Filter metadata and science data of packets that makes full cycles
402
+ full_cycle_l1a_data = l1a_data_copy.isel({"epoch": full_cycle_data_indices})
403
+
404
+ # Update total packets
405
+ total_packets = len(full_cycle_data_indices)
406
+ logger.debug(
407
+ "Quarters cycle after filtering: "
408
+ f"{full_cycle_l1a_data['quarter_cycle'].data}"
409
+ )
410
+ if len(full_cycle_data_indices) != len(
411
+ full_cycle_l1a_data["quarter_cycle"].data
412
+ ):
413
+ raise ValueError(
414
+ "Error: full cycle data indices and filtered quarter cycle data size "
415
+ "mismatch"
416
+ )
417
+
418
+ # Go through each cycle and populate full cycle data
419
+ for packet_index in range(0, total_packets, 4):
420
+ # get ESA lookup table information
421
+ esa_table_num = l1a_data["esa_table_num"].data[packet_index]
422
+
423
+ # If ESA lookup table number is in-flight calibration
424
+ # data, then skip current cycle per SWE teams specification.
425
+ # SWE team only wants in-flight calibration data to be processed
426
+ # upto l1a. In-flight calibration data looks same as science data
427
+ # but it only measures one energy steps during the whole duration.
428
+ if esa_table_num == 1:
429
+ continue
430
+
431
+ full_cycle_data = populate_full_cycle_data(
432
+ full_cycle_l1a_data, packet_index, esa_table_num
433
+ )
434
+
435
+ # save full data array to file
436
+ all_data.append(full_cycle_data)
437
+
438
+ # ------------------------------------------------------------------
439
+ # Save data to dataset.
440
+ # ------------------------------------------------------------------
441
+ # Load CDF attrs
442
+ cdf_attrs = ImapCdfAttributes()
443
+ cdf_attrs.add_instrument_global_attrs("swe")
444
+ cdf_attrs.add_instrument_variable_attrs("swe", "l1b")
445
+ cdf_attrs.add_global_attribute("Data_version", data_version)
446
+
447
+ # Get epoch time of full cycle data and then reshape it to
448
+ # (n, 4) where n = total number of full cycles and 4 = four
449
+ # quarter cycle data metadata. For epoch's data, we take the first element
450
+ # of each quarter cycle data metadata.
451
+ epoch_time = xr.DataArray(
452
+ l1a_data["epoch"].data[full_cycle_data_indices].reshape(-1, 4)[:, 0],
453
+ name="epoch",
454
+ dims=["epoch"],
455
+ attrs=cdf_attrs.get_variable_attributes("epoch"),
456
+ )
457
+
458
+ energy = xr.DataArray(
459
+ np.arange(24),
460
+ name="energy",
461
+ dims=["energy"],
462
+ attrs=cdf_attrs.get_variable_attributes("energy"),
463
+ )
464
+
465
+ # NOTE: LABL_PTR_1 should be CDF_CHAR.
466
+ energy_label = xr.DataArray(
467
+ energy.values.astype(str),
468
+ name="energy_label",
469
+ dims=["energy_label"],
470
+ attrs=cdf_attrs.get_variable_attributes("energy_label"),
471
+ )
472
+
473
+ angle = xr.DataArray(
474
+ np.arange(30),
475
+ name="angle",
476
+ dims=["angle"],
477
+ attrs=cdf_attrs.get_variable_attributes("angle"),
478
+ )
479
+
480
+ # NOTE: LABL_PTR_2 should be CDF_CHAR.
481
+ angle_label = xr.DataArray(
482
+ angle.values.astype(str),
483
+ name="angle_label",
484
+ dims=["angle_label"],
485
+ attrs=cdf_attrs.get_variable_attributes("angle_label"),
486
+ )
487
+
488
+ cycle = xr.DataArray(
489
+ np.arange(4),
490
+ name="cycle",
491
+ dims=["cycle"],
492
+ attrs=cdf_attrs.get_variable_attributes("cycle"),
493
+ )
494
+
495
+ cem = xr.DataArray(
496
+ np.arange(7, dtype=np.float64),
497
+ name="cem",
498
+ dims=["cem"],
499
+ attrs=cdf_attrs.get_variable_attributes("cem"),
500
+ )
501
+
502
+ # NOTE: LABL_PTR_3 should be CDF_CHAR.
503
+ cem_label = xr.DataArray(
504
+ cem.values.astype(str),
505
+ name="cem_label",
506
+ dims=["cem_label"],
507
+ attrs=cdf_attrs.get_variable_attributes("cem_label"),
508
+ )
509
+
510
+ # Add science data and it's associated metadata into dataset.
511
+ # SCIENCE_DATA has array of this shape:
512
+ # (n, 24, 30, 7)
513
+ # n = total number of full cycles
514
+ # 24 rows --> 24 esa voltage measurements
515
+ # 30 columns --> 30 spin angle measurements
516
+ # 7 elements --> 7 CEMs counts
517
+ #
518
+ # The metadata array will need to have this shape:
519
+ # (n, 4)
520
+ # n = total number of full cycles
521
+ # 4 rows --> metadata for each full cycle. Each element of 4 maps to
522
+ # metadata of one quarter cycle.
523
+
524
+ # Create the dataset
525
+ dataset = xr.Dataset(
526
+ coords={
527
+ "epoch": epoch_time,
528
+ "energy": energy,
529
+ "angle": angle,
530
+ "cem": cem,
531
+ "cycle": cycle,
532
+ "energy_label": energy_label,
533
+ "angle_label": angle_label,
534
+ "cem_label": cem_label,
535
+ },
536
+ attrs=cdf_attrs.get_global_attributes("imap_swe_l1b_sci"),
537
+ )
538
+
539
+ dataset["science_data"] = xr.DataArray(
540
+ all_data,
541
+ dims=["epoch", "energy", "angle", "cem"],
542
+ attrs=cdf_attrs.get_variable_attributes("science_data"),
543
+ )
544
+
545
+ # create xarray dataset for each metadata field
546
+ for key, value in full_cycle_l1a_data.items():
547
+ if key == "science_data":
548
+ continue
549
+ metadata_field = key.lower()
550
+ dataset[metadata_field] = xr.DataArray(
551
+ value.data.reshape(-1, 4),
552
+ dims=["epoch", "cycle"],
553
+ attrs=cdf_attrs.get_variable_attributes(metadata_field),
554
+ )
555
+
556
+ logger.info("SWE L1b science processing completed")
557
+ return dataset
File without changes