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,2 @@
1
+ __version__ = "01"
2
+ cdf_format_version = "v0.1"
@@ -0,0 +1,108 @@
1
+ """Collection of constant types or values for MAG."""
2
+
3
+ from enum import Enum
4
+
5
+ import numpy as np
6
+
7
+
8
+ class DataMode(Enum):
9
+ """
10
+ Enum for MAG data modes: burst and normal (BURST + NORM).
11
+
12
+ Attributes
13
+ ----------
14
+ BURST: str
15
+ Burst data mode - higher frequency data
16
+ NORM: str
17
+ Normal data mode - lower frequency data (downsampled from burst)
18
+ """
19
+
20
+ BURST = "BURST"
21
+ NORM = "NORM"
22
+
23
+
24
+ class Sensor(Enum):
25
+ """
26
+ Enum for MAG sensors: raw, MAGo, and MAGi (RAW, MAGO, MAGI).
27
+
28
+ Attributes
29
+ ----------
30
+ MAGO : str
31
+ MAGo sensor - for the outboard sensor. This is nominally expected to be the
32
+ primary sensor.
33
+ MAGI : str
34
+ MAGi sensor - for the inboard sensor.
35
+ RAW : str
36
+ RAW data - contains both sensors. Here, the vectors are unprocessed.
37
+ """
38
+
39
+ MAGO = "MAGO"
40
+ MAGI = "MAGI"
41
+ RAW = "RAW"
42
+
43
+
44
+ class PrimarySensor(Enum):
45
+ """
46
+ Enum for primary sensor: MAGo and MAGi (MAGO, MAGI).
47
+
48
+ This corresponds to the PRI_SENS field in the MAG Level 0 data.
49
+
50
+ Attributes
51
+ ----------
52
+ MAGO : int
53
+ Primary sensor is MAGo.
54
+ MAGI : int
55
+ Primary sensor is MAGi.
56
+ """
57
+
58
+ MAGO = 0
59
+ MAGI = 1
60
+
61
+
62
+ FIBONACCI_SEQUENCE = [
63
+ 1,
64
+ 2,
65
+ 3,
66
+ 5,
67
+ 8,
68
+ 13,
69
+ 21,
70
+ 34,
71
+ 55,
72
+ 89,
73
+ 144,
74
+ 233,
75
+ 377,
76
+ 610,
77
+ 987,
78
+ 1597,
79
+ 2584,
80
+ 4181,
81
+ 6765,
82
+ 10946,
83
+ 17711,
84
+ 28657,
85
+ 46368,
86
+ 75025,
87
+ 121393,
88
+ 196418,
89
+ 317811,
90
+ 514229,
91
+ 832040,
92
+ 1346269,
93
+ 2178309,
94
+ 3524578,
95
+ 5702887,
96
+ 9227465,
97
+ 14930352,
98
+ 24157817,
99
+ 39088169,
100
+ 63245986,
101
+ 102334155,
102
+ 165580141,
103
+ ]
104
+
105
+ MAX_FINE_TIME = np.iinfo(np.uint16).max # maximum 16 bit unsigned int
106
+ AXIS_COUNT = 3
107
+ RANGE_BIT_WIDTH = 2
108
+ MAX_COMPRESSED_VECTOR_BITS = 60
@@ -0,0 +1,170 @@
1
+ """Methods for processing raw MAG packets into CDF files for level 0 and level 1a."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import dataclasses
6
+ import logging
7
+ from collections import defaultdict
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import xarray as xr
12
+ from space_packet_parser import parser, xtcedef
13
+
14
+ from imap_processing import imap_module_directory
15
+ from imap_processing.ccsds.ccsds_data import CcsdsData
16
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
17
+ from imap_processing.mag.constants import DataMode
18
+ from imap_processing.mag.l0.mag_l0_data import MagL0, Mode
19
+ from imap_processing.spice.time import met_to_j2000ns
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ def decom_packets(packet_file_path: str | Path) -> dict[str, list[MagL0]]:
25
+ """
26
+ Decom MAG data packets using MAG packet definition.
27
+
28
+ Parameters
29
+ ----------
30
+ packet_file_path : str
31
+ Path to data packet path with filename.
32
+
33
+ Returns
34
+ -------
35
+ data_dict : dict[str, list[MagL0]]
36
+ A dict with 2 keys pointing to lists of MAG L0 data classes. "norm" corresponds
37
+ to normal mode packets, "burst" corresponds to burst mode packets.
38
+ """
39
+ # Define paths
40
+ xtce_document = Path(
41
+ f"{imap_module_directory}/mag/packet_definitions/MAG_SCI_COMBINED.xml"
42
+ )
43
+
44
+ packet_definition = xtcedef.XtcePacketDefinition(xtce_document)
45
+ mag_parser = parser.PacketParser(packet_definition)
46
+
47
+ norm_data = []
48
+ burst_data = []
49
+
50
+ with open(packet_file_path, "rb") as binary_data:
51
+ mag_packets = mag_parser.generator(binary_data)
52
+
53
+ for packet in mag_packets:
54
+ apid = packet.header["PKT_APID"].derived_value
55
+ if apid in (Mode.BURST, Mode.NORMAL):
56
+ values = [
57
+ item.derived_value
58
+ if item.derived_value is not None
59
+ else item.raw_value
60
+ for item in packet.data.values()
61
+ ]
62
+ if apid == Mode.NORMAL:
63
+ norm_data.append(MagL0(CcsdsData(packet.header), *values))
64
+ else:
65
+ burst_data.append(MagL0(CcsdsData(packet.header), *values))
66
+
67
+ return {"norm": norm_data, "burst": burst_data}
68
+
69
+
70
+ def generate_dataset(
71
+ l0_data: list[MagL0], mode: DataMode, attribute_manager: ImapCdfAttributes
72
+ ) -> xr.Dataset:
73
+ """
74
+ Generate a CDF dataset from the sorted raw L0 MAG data.
75
+
76
+ Parameters
77
+ ----------
78
+ l0_data : list[MagL0]
79
+ List of sorted L0 MAG data.
80
+
81
+ mode : DataMode
82
+ The mode of the CDF file - burst or norm.
83
+
84
+ attribute_manager : ImapCdfAttributes
85
+ Attribute manager for the dataset, including all MAG L1A attributes.
86
+
87
+ Returns
88
+ -------
89
+ dataset : xarray.Dataset
90
+ The xarray dataset with proper CDF attributes and shape.
91
+ """
92
+ # TODO: Correct CDF attributes from email
93
+
94
+ vector_data = np.zeros((len(l0_data), len(l0_data[0].VECTORS)))
95
+ shcoarse_data = np.zeros(len(l0_data), dtype="datetime64[ns]")
96
+
97
+ support_data = defaultdict(list)
98
+
99
+ for index, datapoint in enumerate(l0_data):
100
+ vector_len = len(datapoint.VECTORS)
101
+ if vector_len > vector_data.shape[1]:
102
+ # If the new vector is longer than the existing shape, first reshape
103
+ # vector_data and pad the existing vectors with zeros.
104
+ vector_data = np.pad(
105
+ vector_data,
106
+ (
107
+ (
108
+ 0,
109
+ 0,
110
+ ),
111
+ (0, vector_len - vector_data.shape[1]),
112
+ ),
113
+ "constant",
114
+ constant_values=(0,),
115
+ )
116
+ vector_data[index, :vector_len] = datapoint.VECTORS
117
+
118
+ shcoarse_data[index] = met_to_j2000ns(datapoint.SHCOARSE)
119
+ # Add remaining pieces to arrays
120
+ for key, value in dataclasses.asdict(datapoint).items():
121
+ if key not in ("ccsds_header", "VECTORS", "SHCOARSE"):
122
+ support_data[key].append(value)
123
+ if key == "ccsds_header":
124
+ for ccsds_key, ccsds_value in value.items():
125
+ support_data[ccsds_key].append(ccsds_value)
126
+
127
+ # Used in L1A vectors
128
+ direction = xr.DataArray(
129
+ np.arange(vector_data.shape[1]),
130
+ name="direction",
131
+ dims=["direction"],
132
+ attrs=attribute_manager.get_variable_attributes("raw_direction_attrs"),
133
+ )
134
+
135
+ # TODO: Epoch here refers to the start of the sample. Confirm that this is
136
+ # what mag is expecting, and if it is, CATDESC needs to be updated.
137
+ epoch_time = xr.DataArray(
138
+ shcoarse_data,
139
+ name="epoch",
140
+ dims=["epoch"],
141
+ attrs=attribute_manager.get_variable_attributes("epoch"),
142
+ )
143
+ # TODO: raw vectors units
144
+ raw_vectors = xr.DataArray(
145
+ vector_data,
146
+ name="raw_vectors",
147
+ dims=["epoch", "direction"],
148
+ attrs=attribute_manager.get_variable_attributes("raw_vector_attrs"),
149
+ )
150
+
151
+ logical_id = f"imap_mag_l1a_{mode.value.lower()}-raw"
152
+
153
+ output = xr.Dataset(
154
+ coords={"epoch": epoch_time, "direction": direction},
155
+ attrs=attribute_manager.get_global_attributes(logical_id),
156
+ )
157
+
158
+ output["raw_vectors"] = raw_vectors
159
+
160
+ for key, value in support_data.items():
161
+ # Time varying values
162
+ if key not in ["SHCOARSE", "VECTORS"]:
163
+ output[key] = xr.DataArray(
164
+ value,
165
+ name=key.lower(),
166
+ dims=["epoch"],
167
+ attrs=attribute_manager.get_variable_attributes(key),
168
+ )
169
+
170
+ return output
@@ -0,0 +1,118 @@
1
+ """Dataclasses for Level 0 MAG data."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import IntEnum
7
+
8
+ import numpy as np
9
+
10
+ from imap_processing.ccsds.ccsds_data import CcsdsData
11
+
12
+
13
+ class Mode(IntEnum):
14
+ """
15
+ Enum class for MAG mode.
16
+
17
+ Attributes
18
+ ----------
19
+ BURST : int
20
+ APID for Burst mode data.
21
+ NORMAL : int
22
+ ApID for Normal mode data.
23
+ """
24
+
25
+ BURST = 1068
26
+ NORMAL = 1052
27
+
28
+
29
+ @dataclass
30
+ class MagL0:
31
+ """
32
+ Data class for MAG Level 0 data.
33
+
34
+ Attributes
35
+ ----------
36
+ ccsds_header: CcsdsData
37
+ CCSDS Header data.
38
+ SHCOARSE: int
39
+ Mission elapsed time.
40
+ PUS_SPARE1: int
41
+ ESA standard headers, PUS Spare 1.
42
+ PUS_VERSION: int
43
+ PUS Version Number.
44
+ PUS_SPARE2: int
45
+ PUS Spare 2.
46
+ PUS_STYPE: int
47
+ PUS Service Type.
48
+ PUS_SSUBTYPE: int
49
+ PUS Service Subtype - tells number of seconds of data.
50
+ COMPRESSION: int
51
+ Science Data Compression Flag - indicates if the data compressed - throw error
52
+ if 1.
53
+ MAGO_ACT: int
54
+ MAGO Active Status - if MAGo is active. May also be referred to as "FOB".
55
+ MAGI_ACT: int
56
+ MAGI Active Status - if MAGi is active. May also be referred to as "FIB".
57
+ PRI_SENS: int
58
+ Primary Sensor - 0 is MAGo, 1 is MAGi.
59
+ SPARE1: int
60
+ Spare.
61
+ PRI_VECSEC: int
62
+ Primary Vectors per Second - lookup for L1b.
63
+ SEC_VECSEC: int
64
+ Secondary Vectors per second.
65
+ SPARE2: int
66
+ Spare.
67
+ PRI_COARSETM: int
68
+ Primary Coarse Time for first vector, seconds.
69
+ PRI_FNTM: int
70
+ Primary Fine Time for first vector, subseconds.
71
+ SEC_COARSETM: int
72
+ Secondary Coarse Time for first vector, seconds.
73
+ SEC_FNTM: int
74
+ Secondary Fine Time for first vector, subseconds.
75
+ VECTORS: numpy.ndarray or str
76
+ MAG Science Vectors - divide based on PRI_VECSEC and PUS_SSUBTYPE for vector
77
+ counts. There is a post init call to convert a string into a numpy array -
78
+ the only place it is a string is in the class initialization.
79
+ """
80
+
81
+ ccsds_header: CcsdsData
82
+ SHCOARSE: int
83
+ PUS_SPARE1: int
84
+ PUS_VERSION: int
85
+ PUS_SPARE2: int
86
+ PUS_STYPE: int
87
+ PUS_SSUBTYPE: int
88
+ COMPRESSION: int
89
+ MAGO_ACT: int
90
+ MAGI_ACT: int
91
+ PRI_SENS: int
92
+ SPARE1: int
93
+ PRI_VECSEC: int
94
+ SEC_VECSEC: int
95
+ SPARE2: int
96
+ PRI_COARSETM: int
97
+ PRI_FNTM: int
98
+ SEC_COARSETM: int
99
+ SEC_FNTM: int
100
+ VECTORS: np.ndarray | str
101
+
102
+ def __post_init__(self) -> None:
103
+ """
104
+ Convert Vectors attribute from string to bytearray if needed.
105
+
106
+ Also convert encoded "VECSEC" (vectors per second) into proper vectors per
107
+ second values.
108
+ """
109
+ if isinstance(self.VECTORS, str):
110
+ # Convert string output from space_packet_parser to numpy array of
111
+ # big-endian bytes
112
+ self.VECTORS = np.frombuffer(
113
+ int(self.VECTORS, 2).to_bytes(len(self.VECTORS) // 8, "big"),
114
+ dtype=np.dtype(">B"),
115
+ )
116
+
117
+ self.PRI_VECSEC = 2**self.PRI_VECSEC
118
+ self.SEC_VECSEC = 2**self.SEC_VECSEC
@@ -0,0 +1,317 @@
1
+ """Methods for decomming packets, processing to level 1A, and writing CDFs for MAG."""
2
+
3
+ import dataclasses
4
+ import logging
5
+ from pathlib import Path
6
+
7
+ import numpy as np
8
+ import xarray as xr
9
+
10
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
+ from imap_processing.cdf.utils import J2000_EPOCH
12
+ from imap_processing.mag.constants import DataMode, PrimarySensor
13
+ from imap_processing.mag.l0 import decom_mag
14
+ from imap_processing.mag.l0.mag_l0_data import MagL0
15
+ from imap_processing.mag.l1a.mag_l1a_data import (
16
+ MagL1a,
17
+ MagL1aPacketProperties,
18
+ TimeTuple,
19
+ )
20
+ from imap_processing.spice.time import met_to_j2000ns
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def mag_l1a(packet_filepath: Path, data_version: str) -> list[xr.Dataset]:
26
+ """
27
+ Will process MAG L0 data into L1A CDF files at cdf_filepath.
28
+
29
+ Parameters
30
+ ----------
31
+ packet_filepath : pathlib.Path
32
+ Packet files for processing.
33
+ data_version : str
34
+ Data version to write to CDF files.
35
+
36
+ Returns
37
+ -------
38
+ generated_files : list[xarray.Dataset]
39
+ A list of generated filenames.
40
+ """
41
+ packets = decom_mag.decom_packets(packet_filepath)
42
+
43
+ norm_data = packets["norm"]
44
+ burst_data = packets["burst"]
45
+
46
+ input_files = [packet_filepath.name]
47
+
48
+ # Create attribute manager and add MAG L1A attributes and global variables
49
+ attribute_manager = ImapCdfAttributes()
50
+ attribute_manager.add_instrument_global_attrs("mag")
51
+ attribute_manager.add_instrument_variable_attrs("mag", "l1")
52
+
53
+ attribute_manager.add_global_attribute("Data_version", data_version)
54
+ attribute_manager.add_global_attribute("Input_files", str(input_files))
55
+ attribute_manager.add_global_attribute(
56
+ "Generation_date",
57
+ np.datetime64(
58
+ "now",
59
+ ).astype(str),
60
+ )
61
+
62
+ generated_datasets = create_l1a(norm_data, DataMode.NORM, attribute_manager)
63
+ generated_datasets += create_l1a(burst_data, DataMode.BURST, attribute_manager)
64
+
65
+ return generated_datasets
66
+
67
+
68
+ def create_l1a(
69
+ packet_data: list[MagL0], data_mode: DataMode, attribute_manager: ImapCdfAttributes
70
+ ) -> list[xr.Dataset]:
71
+ """
72
+ Will process MAG L0 data into L1A, then create and write out CDF files.
73
+
74
+ Norm and burst mode descriptors are distinguished with the passed in attrs.
75
+
76
+ Parameters
77
+ ----------
78
+ packet_data : list[MagL0]
79
+ List of MagL0 packets to process, containing primary and secondary sensor data.
80
+
81
+ data_mode : DataMode
82
+ Enum for distinguishing between norm and burst mode data.
83
+
84
+ attribute_manager : ImapCdfAttributes
85
+ Attribute manager for CDF files for MAG L1A.
86
+
87
+ Returns
88
+ -------
89
+ generated_files : list[xarray.Dataset]
90
+ A list of generated filenames.
91
+ """
92
+ if not packet_data:
93
+ return []
94
+
95
+ mag_raw = decom_mag.generate_dataset(packet_data, data_mode, attribute_manager)
96
+
97
+ generated_datasets = [mag_raw]
98
+
99
+ l1a = process_packets(packet_data)
100
+
101
+ # TODO: Rearrange generate_dataset to combine these two for loops
102
+ # Split into MAGo and MAGi
103
+ for _, mago in l1a["mago"].items():
104
+ logical_file_id = f"imap_mag_l1a_{data_mode.value.lower()}-mago"
105
+ norm_mago_output = generate_dataset(mago, logical_file_id, attribute_manager)
106
+ generated_datasets.append(norm_mago_output)
107
+
108
+ for _, magi in l1a["magi"].items():
109
+ logical_file_id = f"imap_mag_l1a_{data_mode.value.lower()}-magi"
110
+ norm_magi_output = generate_dataset(
111
+ magi,
112
+ logical_file_id,
113
+ attribute_manager,
114
+ )
115
+ generated_datasets.append(norm_magi_output)
116
+
117
+ return generated_datasets
118
+
119
+
120
+ def process_packets(
121
+ mag_l0_list: list[MagL0],
122
+ ) -> dict[str, dict[np.datetime64, MagL1a]]:
123
+ """
124
+ Given a list of MagL0 packets, process them into MagO and MagI L1A data classes.
125
+
126
+ This splits the MagL0 packets into MagO and MagI data, returning a dictionary with
127
+ keys "mago" and "magi."
128
+
129
+ Parameters
130
+ ----------
131
+ mag_l0_list : list[MagL0]
132
+ List of Mag L0 packets to process.
133
+
134
+ Returns
135
+ -------
136
+ packet_dict : dict[str, dict[numpy.datetime64, MagL1a]]
137
+ Dictionary containing two keys: "mago" which points to a dictionary of mago
138
+ MagL1A objects, and "magi" which points to a dictionary of magi MagL1A objects.
139
+ Each dictionary has keys of days and values of MagL1A objects, so each day
140
+ corresponds to one MagL1A object.
141
+ """
142
+ magi = {}
143
+ mago = {}
144
+
145
+ for mag_l0 in mag_l0_list:
146
+ primary_start_time = TimeTuple(mag_l0.PRI_COARSETM, mag_l0.PRI_FNTM)
147
+ secondary_start_time = TimeTuple(mag_l0.SEC_COARSETM, mag_l0.SEC_FNTM)
148
+
149
+ mago_is_primary = mag_l0.PRI_SENS == PrimarySensor.MAGO.value
150
+
151
+ primary_day = (
152
+ J2000_EPOCH
153
+ + met_to_j2000ns(primary_start_time.to_seconds()).astype("timedelta64[ns]")
154
+ ).astype("datetime64[D]")
155
+ secondary_day = (
156
+ J2000_EPOCH
157
+ + met_to_j2000ns(secondary_start_time.to_seconds()).astype(
158
+ "timedelta64[ns]"
159
+ )
160
+ ).astype("datetime64[D]")
161
+
162
+ primary_packet_data = MagL1aPacketProperties(
163
+ mag_l0.SHCOARSE,
164
+ primary_start_time,
165
+ mag_l0.PRI_VECSEC,
166
+ mag_l0.PUS_SSUBTYPE,
167
+ mag_l0.ccsds_header.SRC_SEQ_CTR,
168
+ mag_l0.COMPRESSION,
169
+ mago_is_primary,
170
+ )
171
+
172
+ secondary_packet_data = dataclasses.replace(
173
+ primary_packet_data,
174
+ start_time=secondary_start_time,
175
+ vectors_per_second=mag_l0.SEC_VECSEC,
176
+ pus_ssubtype=mag_l0.PUS_SSUBTYPE,
177
+ )
178
+ # now we know the number of secs of data in the packet, and the data rates of
179
+ # each sensor, we can calculate how much data is in this packet and where the
180
+ # byte boundaries are.
181
+ primary_vectors, secondary_vectors = MagL1a.process_vector_data(
182
+ mag_l0.VECTORS, # type: ignore
183
+ primary_packet_data.total_vectors,
184
+ secondary_packet_data.total_vectors,
185
+ mag_l0.COMPRESSION,
186
+ )
187
+
188
+ primary_timestamped_vectors = MagL1a.calculate_vector_time(
189
+ primary_vectors,
190
+ primary_packet_data.vectors_per_second,
191
+ primary_packet_data.start_time,
192
+ )
193
+ secondary_timestamped_vectors = MagL1a.calculate_vector_time(
194
+ secondary_vectors,
195
+ secondary_packet_data.vectors_per_second,
196
+ secondary_packet_data.start_time,
197
+ )
198
+
199
+ # Sort primary and secondary into MAGo and MAGi by 24 hour chunks
200
+ mago_day = primary_day if mago_is_primary else secondary_day
201
+ magi_day = primary_day if not mago_is_primary else secondary_day
202
+
203
+ if mago_day not in mago:
204
+ mago[mago_day] = MagL1a(
205
+ True,
206
+ mag_l0.MAGO_ACT,
207
+ mag_l0.SHCOARSE,
208
+ primary_timestamped_vectors
209
+ if mago_is_primary
210
+ else secondary_timestamped_vectors,
211
+ primary_packet_data if mago_is_primary else secondary_packet_data,
212
+ )
213
+ else:
214
+ mago[mago_day].append_vectors(
215
+ (
216
+ primary_timestamped_vectors
217
+ if mago_is_primary
218
+ else secondary_timestamped_vectors
219
+ ),
220
+ primary_packet_data if mago_is_primary else secondary_packet_data,
221
+ )
222
+
223
+ if magi_day not in magi:
224
+ magi[magi_day] = MagL1a(
225
+ False,
226
+ mag_l0.MAGI_ACT,
227
+ mag_l0.SHCOARSE,
228
+ primary_timestamped_vectors
229
+ if not mago_is_primary
230
+ else secondary_timestamped_vectors,
231
+ primary_packet_data if not mago_is_primary else secondary_packet_data,
232
+ )
233
+ else:
234
+ magi[magi_day].append_vectors(
235
+ (
236
+ primary_timestamped_vectors
237
+ if not mago_is_primary
238
+ else secondary_timestamped_vectors
239
+ ),
240
+ primary_packet_data if not mago_is_primary else secondary_packet_data,
241
+ )
242
+
243
+ return {"mago": mago, "magi": magi}
244
+
245
+
246
+ def generate_dataset(
247
+ single_file_l1a: MagL1a,
248
+ logical_file_id: str,
249
+ attribute_manager: ImapCdfAttributes,
250
+ ) -> xr.Dataset:
251
+ """
252
+ Generate a Xarray dataset for L1A data to output to CDF files.
253
+
254
+ Global_attrs should contain all info about mago/magi and burst/norm distinction, as
255
+ well as any general info in the global attributes.
256
+
257
+ Assumes each MagL1a object is a single day of data, so one MagL1a object has one
258
+ CDF file output.
259
+
260
+ Parameters
261
+ ----------
262
+ single_file_l1a : MagL1a
263
+ L1A data covering one day to process into a xarray dataset.
264
+ logical_file_id : str
265
+ Indicates which sensor (MagO or MAGi) and mode (burst or norm) the data is from.
266
+ This is used to retrieve the global attributes from attribute_manager.
267
+ attribute_manager : ImapCdfAttributes
268
+ Attributes for the dataset, as created by ImapCdfAttributes.
269
+
270
+ Returns
271
+ -------
272
+ dataset : xarray.Dataset
273
+ One xarray dataset with proper CDF attributes and shape containing MAG L1A data.
274
+ """
275
+ # TODO: add:
276
+ # gaps_in_data global attr
277
+ # magl1avectordefinition data
278
+
279
+ # TODO: Just leave time in datetime64 type with vector as dtype object to avoid this
280
+ # Get the timestamp from the end of the vector
281
+ time_data = single_file_l1a.vectors[:, 4].astype(
282
+ np.dtype("datetime64[ns]"), copy=False
283
+ )
284
+
285
+ direction = xr.DataArray(
286
+ np.arange(4),
287
+ name="direction",
288
+ dims=["direction"],
289
+ attrs=attribute_manager.get_variable_attributes("direction_attrs"),
290
+ )
291
+
292
+ # TODO: Epoch here refers to the start of the sample. Confirm that this is
293
+ # what mag is expecting, and if it is, CATDESC needs to be updated.
294
+ epoch_time = xr.DataArray(
295
+ time_data,
296
+ name="epoch",
297
+ dims=["epoch"],
298
+ attrs=attribute_manager.get_variable_attributes("epoch"),
299
+ )
300
+
301
+ vectors = xr.DataArray(
302
+ single_file_l1a.vectors[:, :4],
303
+ name="vectors",
304
+ dims=["epoch", "direction"],
305
+ attrs=attribute_manager.get_variable_attributes("vector_attrs"),
306
+ )
307
+
308
+ output = xr.Dataset(
309
+ coords={"epoch": epoch_time, "direction": direction},
310
+ attrs=attribute_manager.get_global_attributes(logical_file_id),
311
+ )
312
+
313
+ output["vectors"] = vectors
314
+
315
+ # TODO: Put is_mago and active in the header
316
+
317
+ return output