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,764 @@
1
+ """Calculates Extended Raw Events for ULTRA L1b."""
2
+
3
+ import logging
4
+ from enum import Enum
5
+ from typing import ClassVar
6
+
7
+ import numpy as np
8
+ import xarray
9
+ from numpy import ndarray
10
+ from numpy.typing import NDArray
11
+
12
+ from imap_processing.ultra.constants import UltraConstants
13
+ from imap_processing.ultra.l1b.lookup_utils import (
14
+ get_back_position,
15
+ get_energy_norm,
16
+ get_image_params,
17
+ get_norm,
18
+ get_y_adjust,
19
+ )
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ class StartType(Enum):
25
+ """Start Type: 1=Left, 2=Right."""
26
+
27
+ Left = 1
28
+ Right = 2
29
+
30
+
31
+ class StopType(Enum):
32
+ """Stop Type: 1=Top, 2=Bottom, SSD: 8-15."""
33
+
34
+ Top = 1
35
+ Bottom = 2
36
+ PH: ClassVar[list[int]] = [1, 2]
37
+ SSD: ClassVar[list[int]] = [8, 9, 10, 11, 12, 13, 14, 15]
38
+
39
+
40
+ class CoinType(Enum):
41
+ """Coin Type: 1=Top, 2=Bottom."""
42
+
43
+ Top = 1
44
+ Bottom = 2
45
+
46
+
47
+ def get_front_x_position(start_type: ndarray, start_position_tdc: ndarray) -> ndarray:
48
+ """
49
+ Calculate the front xf position.
50
+
51
+ Converts Start Position Time to Digital Converter (TDC)
52
+ values into units of hundredths of a millimeter using a scale factor and offsets.
53
+ Further description is available on pages 30 of
54
+ IMAP-Ultra Flight Software Specification document (7523-9009_Rev_-.pdf).
55
+
56
+ Parameters
57
+ ----------
58
+ start_type : ndarray
59
+ Start Type: 1=Left, 2=Right.
60
+ start_position_tdc : ndarray
61
+ Start Position Time to Digital Converter (TDC).
62
+
63
+ Returns
64
+ -------
65
+ xf : ndarray
66
+ X front position (hundredths of a millimeter).
67
+ """
68
+ # Left and right start types.
69
+ indices = np.nonzero((start_type == 1) | (start_type == 2))
70
+
71
+ xftsc = get_image_params("XFTSC")
72
+ xft_lt_off = get_image_params("XFTLTOFF")
73
+ xft_rt_off = get_image_params("XFTRTOFF")
74
+ xft_off = np.where(start_type[indices] == 1, xft_lt_off, xft_rt_off)
75
+
76
+ # Calculate xf and convert to hundredths of a millimeter
77
+ xf: ndarray = (xftsc * -start_position_tdc[indices] + xft_off) * 100
78
+
79
+ return xf
80
+
81
+
82
+ def get_front_y_position(start_type: ndarray, yb: ndarray) -> tuple[ndarray, ndarray]:
83
+ """
84
+ Compute the adjustments for the front y position and distance front to back.
85
+
86
+ This function utilizes lookup tables and trigonometry based on
87
+ the angle of the foil. Further description is available in the
88
+ IMAP-Ultra Flight Software Specification document pg 30.
89
+
90
+ Parameters
91
+ ----------
92
+ start_type : np.array
93
+ Start Type: 1=Left, 2=Right.
94
+ yb : np.array
95
+ Y back position in hundredths of a millimeter.
96
+
97
+ Returns
98
+ -------
99
+ d : np.array
100
+ Distance front to back in hundredths of a millimeter.
101
+ yf : np.array
102
+ Front y position in hundredths of a millimeter.
103
+ """
104
+ # Determine start types
105
+ index_left = np.nonzero(start_type == 1)
106
+ index_right = np.nonzero(start_type == 2)
107
+
108
+ yf = np.zeros(len(start_type))
109
+ d = np.zeros(len(start_type))
110
+
111
+ # Compute adjustments for left start type
112
+ dy_lut_left = np.floor(
113
+ (UltraConstants.YF_ESTIMATE_LEFT - yb[index_left] / 100)
114
+ * UltraConstants.N_ELEMENTS
115
+ / UltraConstants.TRIG_CONSTANT
116
+ + 0.5
117
+ )
118
+ # y adjustment in mm
119
+ y_adjust_left = get_y_adjust(dy_lut_left) / 100
120
+ # hundredths of a millimeter
121
+ yf[index_left] = (UltraConstants.YF_ESTIMATE_LEFT - y_adjust_left) * 100
122
+ # distance adjustment in mm
123
+ distance_adjust_left = np.sqrt(2) * UltraConstants.D_SLIT_FOIL - y_adjust_left
124
+ # hundredths of a millimeter
125
+ d[index_left] = (UltraConstants.SLIT_Z - distance_adjust_left) * 100
126
+
127
+ # Compute adjustments for right start type
128
+ dy_lut_right = np.floor(
129
+ (yb[index_right] / 100 - UltraConstants.YF_ESTIMATE_RIGHT)
130
+ * UltraConstants.N_ELEMENTS
131
+ / UltraConstants.TRIG_CONSTANT
132
+ + 0.5
133
+ )
134
+ # y adjustment in mm
135
+ y_adjust_right = get_y_adjust(dy_lut_right) / 100
136
+ # hundredths of a millimeter
137
+ yf[index_right] = (UltraConstants.YF_ESTIMATE_RIGHT + y_adjust_right) * 100
138
+ # distance adjustment in mm
139
+ distance_adjust_right = np.sqrt(2) * UltraConstants.D_SLIT_FOIL - y_adjust_right
140
+ # hundredths of a millimeter
141
+ d[index_right] = (UltraConstants.SLIT_Z - distance_adjust_right) * 100
142
+
143
+ return np.array(d), np.array(yf)
144
+
145
+
146
+ def get_ph_tof_and_back_positions(
147
+ de_dataset: xarray.Dataset, xf: np.ndarray, sensor: str
148
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
149
+ """
150
+ Calculate back xb, yb position and tof.
151
+
152
+ An incoming particle may trigger pulses from one of the stop anodes.
153
+ If so, four pulses are produced, one each from the north, south,
154
+ east, and west sides.
155
+
156
+ The Time Of Flight (tof) and the position of the particle at the
157
+ back of the sensor are measured using the timing of the pulses.
158
+ Further description is available on pages 32-33 of
159
+ IMAP-Ultra Flight Software Specification document
160
+ (7523-9009_Rev_-.pdf).
161
+
162
+ Parameters
163
+ ----------
164
+ de_dataset : xarray.Dataset
165
+ Data in xarray format.
166
+ xf : np.array
167
+ X front position in (hundredths of a millimeter).
168
+ Has same length as de_dataset.
169
+ sensor : str
170
+ Sensor name.
171
+
172
+ Returns
173
+ -------
174
+ tof : np.array
175
+ Time of flight (nanoseconds).
176
+ t2 : np.array
177
+ Particle time of flight from start to stop (tenths of a nanosecond).
178
+ xb : np.array
179
+ Back positions in x direction (hundredths of a millimeter).
180
+ yb : np.array
181
+ Back positions in y direction (hundredths of a millimeter).
182
+ """
183
+ indices = np.nonzero(
184
+ np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
185
+ )[0]
186
+ de_filtered = de_dataset.isel(epoch=indices)
187
+
188
+ xf_ph = xf[indices]
189
+
190
+ # There are mismatches between the stop TDCs, i.e., SpN, SpS, SpE, and SpW.
191
+ # This normalizes the TDCs
192
+ sp_n_norm = get_norm(de_filtered["STOP_NORTH_TDC"].data, "SpN", sensor)
193
+ sp_s_norm = get_norm(de_filtered["STOP_SOUTH_TDC"].data, "SpS", sensor)
194
+ sp_e_norm = get_norm(de_filtered["STOP_EAST_TDC"].data, "SpE", sensor)
195
+ sp_w_norm = get_norm(de_filtered["STOP_WEST_TDC"].data, "SpW", sensor)
196
+
197
+ # Convert normalized TDC values into units of hundredths of a
198
+ # millimeter using lookup tables.
199
+ xb_index = sp_s_norm - sp_n_norm + 2047
200
+ yb_index = sp_e_norm - sp_w_norm + 2047
201
+
202
+ # Convert xf to a tof offset
203
+ tofx = sp_n_norm + sp_s_norm
204
+ tofy = sp_e_norm + sp_w_norm
205
+
206
+ # tof is the average of the two tofs measured in the X and Y directions,
207
+ # tofx and tofy
208
+ # Units in tenths of a nanosecond
209
+ t1 = tofx + tofy # /2 incorporated into scale
210
+
211
+ xb = np.zeros(len(indices))
212
+ yb = np.zeros(len(indices))
213
+
214
+ # particle_tof (t2) used later to compute etof
215
+ t2 = np.zeros(len(indices))
216
+ tof = np.zeros(len(indices))
217
+
218
+ # Stop Type: 1=Top, 2=Bottom
219
+ # Convert converts normalized TDC values into units of
220
+ # hundredths of a millimeter using lookup tables.
221
+ stop_type_top = de_filtered["STOP_TYPE"].data == StopType.Top.value
222
+ xb[stop_type_top] = get_back_position(xb_index[stop_type_top], "XBkTp", sensor)
223
+ yb[stop_type_top] = get_back_position(yb_index[stop_type_top], "YBkTp", sensor)
224
+
225
+ # Correction for the propagation delay of the start anode and other effects.
226
+ t2[stop_type_top] = get_image_params("TOFSC") * t1[
227
+ stop_type_top
228
+ ] + get_image_params("TOFTPOFF")
229
+ # Variable xf_ph divided by 10 to convert to mm.
230
+ tof[stop_type_top] = t2[stop_type_top] + xf_ph[
231
+ stop_type_top
232
+ ] / 10 * get_image_params("XFTTOF")
233
+
234
+ stop_type_bottom = de_filtered["STOP_TYPE"].data == StopType.Bottom.value
235
+ xb[stop_type_bottom] = get_back_position(
236
+ xb_index[stop_type_bottom], "XBkBt", sensor
237
+ )
238
+ yb[stop_type_bottom] = get_back_position(
239
+ yb_index[stop_type_bottom], "YBkBt", sensor
240
+ )
241
+
242
+ # Correction for the propagation delay of the start anode and other effects.
243
+ t2[stop_type_bottom] = get_image_params("TOFSC") * t1[
244
+ stop_type_bottom
245
+ ] + get_image_params("TOFBTOFF") # 10*ns
246
+
247
+ # Variable xf_ph divided by 10 to convert to mm.
248
+ tof[stop_type_bottom] = t2[stop_type_bottom] + xf_ph[
249
+ stop_type_bottom
250
+ ] / 10 * get_image_params("XFTTOF")
251
+
252
+ return tof, t2, xb, yb
253
+
254
+
255
+ def get_path_length(front_position: tuple, back_position: tuple, d: float) -> float:
256
+ """
257
+ Calculate the path length.
258
+
259
+ Parameters
260
+ ----------
261
+ front_position : tuple of floats
262
+ Front position (xf,yf) (hundredths of a millimeter).
263
+ back_position : tuple of floats
264
+ Back position (xb,yb) (hundredths of a millimeter).
265
+ d : float
266
+ Distance from slit to foil (hundredths of a millimeter).
267
+
268
+ Returns
269
+ -------
270
+ path_length : float
271
+ Path length (r) (hundredths of a millimeter).
272
+ """
273
+ path_length: float = np.sqrt(
274
+ (front_position[0] - back_position[0]) ** 2
275
+ + (front_position[1] - back_position[1]) ** 2
276
+ + (d) ** 2
277
+ )
278
+
279
+ return path_length
280
+
281
+
282
+ def get_ssd_back_position_and_tof_offset(
283
+ de_dataset: xarray.Dataset,
284
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
285
+ """
286
+ Lookup the Y SSD positions (yb), TOF Offset, and SSD number.
287
+
288
+ Parameters
289
+ ----------
290
+ de_dataset : xarray.Dataset
291
+ The input dataset containing STOP_TYPE and SSD_FLAG data.
292
+
293
+ Returns
294
+ -------
295
+ yb : np.ndarray
296
+ Y SSD positions in hundredths of a millimeter.
297
+ tof_offset : np.ndarray
298
+ TOF offset.
299
+ ssd_number : np.ndarray
300
+ SSD number.
301
+
302
+ Notes
303
+ -----
304
+ The X back position (xb) is assumed to be 0 for SSD.
305
+ """
306
+ indices = np.nonzero(np.isin(de_dataset["STOP_TYPE"], StopType.SSD.value))[0]
307
+ de_filtered = de_dataset.isel(epoch=indices)
308
+
309
+ yb = np.zeros(len(indices), dtype=np.float64)
310
+ ssd_number = np.zeros(len(indices), dtype=int)
311
+ tof_offset = np.zeros(len(indices), dtype=np.float64)
312
+
313
+ for i in range(8):
314
+ ssd_flag_mask = de_filtered[f"SSD_FLAG_{i}"].data == 1
315
+
316
+ # Multiply ybs times 100 to convert to hundredths of a millimeter.
317
+ yb[ssd_flag_mask] = get_image_params(f"YBKSSD{i}") * 100
318
+ ssd_number[ssd_flag_mask] = i
319
+
320
+ tof_offset[
321
+ (de_filtered["START_TYPE"] == StartType.Left.value) & ssd_flag_mask
322
+ ] = get_image_params(f"TOFSSDLTOFF{i}")
323
+ tof_offset[
324
+ (de_filtered["START_TYPE"] == StartType.Right.value) & ssd_flag_mask
325
+ ] = get_image_params(f"TOFSSDRTOFF{i}")
326
+
327
+ return yb, tof_offset, ssd_number
328
+
329
+
330
+ def calculate_etof_xc(
331
+ de_subset: xarray.Dataset, particle_tof: np.ndarray, sensor: str, location: str
332
+ ) -> tuple[np.ndarray, np.ndarray]:
333
+ """
334
+ Calculate the etof and xc values for the given subset.
335
+
336
+ Parameters
337
+ ----------
338
+ de_subset : xarray.Dataset
339
+ Subset of the dataset for a specific COIN_TYPE.
340
+ particle_tof : np.ndarray
341
+ Particle time of flight (i.e. from start to stop).
342
+ sensor : str
343
+ Sensor name.
344
+ location : str
345
+ Location indicator, either 'TP' (Top) or 'BT' (Bottom).
346
+
347
+ Returns
348
+ -------
349
+ etof : np.ndarray
350
+ Time for the electrons to travel back to the coincidence
351
+ anode (tenths of a nanosecond).
352
+ xc : np.ndarray
353
+ X coincidence position (millimeters).
354
+ """
355
+ # CoinNNorm
356
+ coin_n_norm = get_norm(de_subset["COIN_NORTH_TDC"], "CoinN", sensor)
357
+ # CoinSNorm
358
+ coin_s_norm = get_norm(de_subset["COIN_SOUTH_TDC"], "CoinS", sensor)
359
+ xc = get_image_params(f"XCOIN{location}SC") * (
360
+ coin_s_norm - coin_n_norm
361
+ ) + get_image_params(f"XCOIN{location}OFF") # millimeter
362
+
363
+ # Time for the electrons to travel back to coincidence anode.
364
+ t2 = get_image_params("ETOFSC") * (coin_n_norm + coin_s_norm) + get_image_params(
365
+ f"ETOF{location}OFF"
366
+ )
367
+
368
+ # Multiply by 10 to convert to tenths of a nanosecond.
369
+ etof = t2 * 10 - particle_tof
370
+
371
+ return etof, xc
372
+
373
+
374
+ def get_coincidence_positions(
375
+ de_dataset: xarray.Dataset, particle_tof: np.ndarray, sensor: str
376
+ ) -> tuple[np.ndarray, np.ndarray]:
377
+ """
378
+ Calculate coincidence positions.
379
+
380
+ Calculate time for electrons to travel back to
381
+ the coincidence anode (etof) and the x coincidence position (xc).
382
+
383
+ The tof measured by the coincidence anode consists of the particle
384
+ tof from start to stop, plus the time for the electrons to travel
385
+ back to the coincidence anode.
386
+
387
+ Further description is available on pages 34-35 of
388
+ IMAP-Ultra Flight Software Specification document
389
+ (7523-9009_Rev_-.pdf).
390
+
391
+ Parameters
392
+ ----------
393
+ de_dataset : xarray.Dataset
394
+ Data in xarray format.
395
+ particle_tof : np.ndarray
396
+ Particle time of flight (i.e. from start to stop)
397
+ (tenths of a nanosecond).
398
+ sensor : str
399
+ Sensor name.
400
+
401
+ Returns
402
+ -------
403
+ etof : np.ndarray
404
+ Time for the electrons to travel back to
405
+ coincidence anode (tenths of a nanosecond).
406
+ xc : np.ndarray
407
+ X coincidence position (hundredths of a millimeter).
408
+ """
409
+ index_top = np.nonzero(np.isin(de_dataset["COIN_TYPE"], CoinType.Top.value))[0]
410
+ de_top = de_dataset.isel(epoch=index_top)
411
+
412
+ index_bottom = np.nonzero(np.isin(de_dataset["COIN_TYPE"], CoinType.Bottom.value))[
413
+ 0
414
+ ]
415
+ de_bottom = de_dataset.isel(epoch=index_bottom)
416
+
417
+ etof = np.zeros(len(de_dataset["COIN_TYPE"]), dtype=np.float64)
418
+ xc_array = np.zeros(len(de_dataset["COIN_TYPE"]), dtype=np.float64)
419
+
420
+ # Normalized TDCs
421
+ # For the stop anode, there are mismatches between the coincidence TDCs,
422
+ # i.e., CoinN and CoinS. They must be normalized via lookup tables.
423
+ etof_top, xc_top = calculate_etof_xc(de_top, particle_tof[index_top], sensor, "TP")
424
+ etof[index_top] = etof_top
425
+ xc_array[index_top] = xc_top
426
+
427
+ etof_bottom, xc_bottom = calculate_etof_xc(
428
+ de_bottom, particle_tof[index_bottom], sensor, "BT"
429
+ )
430
+ etof[index_bottom] = etof_bottom
431
+ xc_array[index_bottom] = xc_bottom
432
+
433
+ # Convert to hundredths of a millimeter by multiplying times 100
434
+ return etof, xc_array * 100
435
+
436
+
437
+ def get_particle_velocity(
438
+ front_position: tuple[float, float],
439
+ back_position: tuple[float, float],
440
+ d: np.ndarray,
441
+ tof: np.ndarray,
442
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
443
+ """
444
+ Determine the particle velocity.
445
+
446
+ The equation is: velocity = ((xf - xb), (yf - yb), d).
447
+
448
+ Further description is available on pages 39 of
449
+ IMAP-Ultra Flight Software Specification document
450
+ (7523-9009_Rev_-.pdf).
451
+
452
+ Parameters
453
+ ----------
454
+ front_position : tuple
455
+ Front position (xf,yf) (hundredths of a millimeter).
456
+ back_position : tuple
457
+ Back position (xb,yb) (hundredths of a millimeter).
458
+ d : np.array
459
+ Distance from slit to foil (hundredths of a millimeter).
460
+ tof : np.array
461
+ Time of flight (tenths of a nanosecond).
462
+
463
+ Returns
464
+ -------
465
+ vhat_x : np.array
466
+ Normalized component of the velocity vector in x direction.
467
+ vhat_y : np.array
468
+ Normalized component of the velocity vector in y direction.
469
+ vhat_z : np.array
470
+ Normalized component of the velocity vector in z direction.
471
+ """
472
+ if tof[tof < 0].any():
473
+ logger.info("Negative tof values found.")
474
+
475
+ delta_x = front_position[0] - back_position[0]
476
+ delta_y = front_position[1] - back_position[1]
477
+
478
+ v_x = delta_x / tof
479
+ v_y = delta_y / tof
480
+ v_z = d / tof
481
+
482
+ # Magnitude of the velocity vector
483
+ magnitude_v = np.sqrt(v_x**2 + v_y**2 + v_z**2)
484
+
485
+ vhat_x = -v_x / magnitude_v
486
+ vhat_y = -v_y / magnitude_v
487
+ vhat_z = -v_z / magnitude_v
488
+
489
+ vhat_x[tof < 0] = np.iinfo(np.int64).min # used as fillvals
490
+ vhat_y[tof < 0] = np.iinfo(np.int64).min
491
+ vhat_z[tof < 0] = np.iinfo(np.int64).min
492
+
493
+ return vhat_x, vhat_y, vhat_z
494
+
495
+
496
+ def get_ssd_tof(de_dataset: xarray.Dataset, xf: np.ndarray) -> NDArray[np.float64]:
497
+ """
498
+ Calculate back xb, yb position for the SSDs.
499
+
500
+ An incoming particle could miss the stop anodes and instead
501
+ hit one of the SSDs between the anodes. Which SSD is hit
502
+ gives a coarse measurement of the y back position;
503
+ the x back position will be fixed.
504
+
505
+ Before hitting the SSD, particles pass through the stop foil;
506
+ dislodged electrons are accelerated back towards the coincidence anode.
507
+ The Coincidence Discrete provides a measure of the TOF.
508
+ A scale factor and offsets, and a multiplier convert xf to a tof offset.
509
+
510
+ Further description is available on pages 36 of
511
+ IMAP-Ultra Flight Software Specification document
512
+ (7523-9009_Rev_-.pdf).
513
+
514
+ Parameters
515
+ ----------
516
+ de_dataset : xarray.Dataset
517
+ Data in xarray format.
518
+ xf : np.array
519
+ Front x position (hundredths of a millimeter).
520
+
521
+ Returns
522
+ -------
523
+ tof : np.ndarray
524
+ Time of flight (tenths of a nanosecond).
525
+ """
526
+ _, tof_offset, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
527
+ indices = np.nonzero(np.isin(de_dataset["STOP_TYPE"], [StopType.SSD.value]))[0]
528
+
529
+ de_discrete = de_dataset.isel(epoch=indices)["COIN_DISCRETE_TDC"]
530
+
531
+ time = get_image_params("TOFSSDSC") * de_discrete.values + tof_offset
532
+
533
+ # The scale factor and offsets, and a multiplier to convert xf to a tof offset.
534
+ # Convert xf to mm by dividing by 100.
535
+ tof = (
536
+ time
537
+ + get_image_params("TOFSSDTOTOFF")
538
+ + xf[indices] / 100 * get_image_params("XFTTOF")
539
+ ) * 10
540
+
541
+ # Convert TOF to tenths of a nanosecond.
542
+ return np.asarray(tof, dtype=np.float64)
543
+
544
+
545
+ def get_energy_pulse_height(
546
+ stop_type: np.ndarray, energy: np.ndarray, xb: np.ndarray, yb: np.ndarray
547
+ ) -> NDArray[np.float64]:
548
+ """
549
+ Calculate the pulse-height energy.
550
+
551
+ Calculate energy measured using the
552
+ pulse height from the stop anode.
553
+ Lookup tables (lut) are used for corrections.
554
+ Further description is available on pages 40-41 of
555
+ IMAP-Ultra Flight Software Specification document
556
+ (7523-9009_Rev_-.pdf).
557
+
558
+ Parameters
559
+ ----------
560
+ stop_type : np.ndarray
561
+ Stop type: 1=Top, 2=Bottom.
562
+ energy : np.ndarray
563
+ Energy measured using the pulse height.
564
+ xb : np.ndarray
565
+ X back position (hundredths of a millimeter).
566
+ yb : np.ndarray
567
+ Y back position (hundredths of a millimeter).
568
+
569
+ Returns
570
+ -------
571
+ energy_ph : np.ndarray
572
+ Energy measured using the pulse height
573
+ from the stop anode (DN).
574
+ """
575
+ indices_top = np.where(stop_type == 1)[0]
576
+ indices_bottom = np.where(stop_type == 2)[0]
577
+
578
+ xlut = np.zeros(len(stop_type), dtype=np.float64)
579
+ ylut = np.zeros(len(stop_type), dtype=np.float64)
580
+ energy_ph = np.zeros(len(stop_type), dtype=np.float64)
581
+
582
+ # Stop type 1
583
+ xlut[indices_top] = (xb[indices_top] / 100 - 25 / 2) * 20 / 50 # mm
584
+ ylut[indices_top] = (yb[indices_top] / 100 + 82 / 2) * 32 / 82 # mm
585
+ # Stop type 2
586
+ xlut[indices_bottom] = (xb[indices_bottom] / 100 + 50 + 25 / 2) * 20 / 50 # mm
587
+ ylut[indices_bottom] = (yb[indices_bottom] / 100 + 82 / 2) * 32 / 82 # mm
588
+
589
+ # TODO: waiting on these lookup tables: SpTpPHCorr, SpBtPHCorr
590
+ energy_ph[indices_top] = energy[indices_top] - get_image_params(
591
+ "SPTPPHOFF"
592
+ ) # * SpTpPHCorr[
593
+ # xlut[indices_top], ylut[indices_top]] / 1024
594
+
595
+ energy_ph[indices_bottom] = energy[indices_bottom] - get_image_params(
596
+ "SPBTPHOFF"
597
+ ) # * SpBtPHCorr[
598
+ # xlut[indices_bottom], ylut[indices_bottom]] / 1024
599
+
600
+ return energy_ph
601
+
602
+
603
+ def get_energy_ssd(de_dataset: xarray.Dataset, ssd: np.ndarray) -> NDArray[np.float64]:
604
+ """
605
+ Get SSD energy.
606
+
607
+ For SSD events, the SSD itself provides a direct
608
+ measurement of the energy. To cover higher energies,
609
+ a so-called composite energy is calculated using the
610
+ SSD energy and SSD energy pulse width.
611
+ The result is then normalized per SSD via a lookup table.
612
+ Further description is available on pages 41 of
613
+ IMAP-Ultra Flight Software Specification document
614
+ (7523-9009_Rev_-.pdf).
615
+
616
+ Parameters
617
+ ----------
618
+ de_dataset : xarray.Dataset
619
+ Events dataset.
620
+ ssd : np.ndarray
621
+ SSD number.
622
+
623
+ Returns
624
+ -------
625
+ energy_norm : np.ndarray
626
+ Energy measured using the SSD.
627
+ """
628
+ ssd_indices = np.where(de_dataset["STOP_TYPE"].data >= 8)[0]
629
+ energy = de_dataset["ENERGY_PH"].data[ssd_indices]
630
+
631
+ composite_energy = np.empty(len(energy), dtype=np.float64)
632
+
633
+ composite_energy[energy >= UltraConstants.COMPOSITE_ENERGY_THRESHOLD] = (
634
+ UltraConstants.COMPOSITE_ENERGY_THRESHOLD
635
+ + de_dataset["PULSE_WIDTH"].data[ssd_indices][
636
+ energy >= UltraConstants.COMPOSITE_ENERGY_THRESHOLD
637
+ ]
638
+ )
639
+ composite_energy[energy < UltraConstants.COMPOSITE_ENERGY_THRESHOLD] = energy[
640
+ energy < UltraConstants.COMPOSITE_ENERGY_THRESHOLD
641
+ ]
642
+
643
+ energy_norm = get_energy_norm(ssd, composite_energy)
644
+
645
+ return energy_norm
646
+
647
+
648
+ def get_ctof(tof: np.ndarray, path_length: np.ndarray) -> NDArray:
649
+ """
650
+ Calculate the corrected TOF.
651
+
652
+ The corrected TOF (ctof) is the TOF normalized with respect
653
+ to a fixed distance dmin between the front and back detectors.
654
+ The normalized TOF is termed the corrected TOF (ctof).
655
+ Further description is available on pages 42-44 of
656
+ IMAP-Ultra Flight Software Specification document
657
+ (7523-9009_Rev_-.pdf).
658
+
659
+ Parameters
660
+ ----------
661
+ tof : np.ndarray
662
+ Time of flight (tenths of a nanosecond).
663
+ path_length : np.ndarray
664
+ Path length (r) (hundredths of a millimeter).
665
+
666
+ Returns
667
+ -------
668
+ ctof : np.ndarray
669
+ Corrected TOF (tenths of a ns).
670
+ """
671
+ # Multiply times 100 to convert to hundredths of a millimeter.
672
+ ctof = tof * UltraConstants.DMIN * 100 / path_length
673
+
674
+ return ctof
675
+
676
+
677
+ def determine_species_pulse_height(
678
+ energy: np.ndarray, tof: np.ndarray, path_length: np.ndarray
679
+ ) -> NDArray:
680
+ """
681
+ Determine the species for pulse-height events.
682
+
683
+ Species is determined from the particle energy and velocity.
684
+ For velocity, the particle TOF is normalized with respect
685
+ to a fixed distance dmin between the front and back detectors.
686
+ The normalized TOF is termed the corrected TOF (ctof).
687
+ Particle species are determined from
688
+ the energy and ctof using a lookup table.
689
+
690
+ Further description is available on pages 42-44 of
691
+ IMAP-Ultra Flight Software Specification document
692
+ (7523-9009_Rev_-.pdf).
693
+
694
+ Parameters
695
+ ----------
696
+ energy : np.ndarray
697
+ Energy from the SSD event (keV).
698
+ tof : np.ndarray
699
+ Time of flight of the SSD event (tenths of a nanosecond).
700
+ path_length : np.ndarray
701
+ Path length (r) (hundredths of a millimeter).
702
+
703
+ Returns
704
+ -------
705
+ bin : np.array
706
+ Species bin.
707
+ """
708
+ # PH event TOF normalization to Z axis
709
+ ctof = get_ctof(tof, path_length)
710
+ # TODO: need lookup tables
711
+ # placeholder
712
+ bin = np.zeros(len(ctof))
713
+ # bin = PHxTOFSpecies[ctof, energy]
714
+
715
+ return bin
716
+
717
+
718
+ def determine_species_ssd(
719
+ energy: np.ndarray, tof: np.ndarray, path_length: np.ndarray
720
+ ) -> NDArray:
721
+ """
722
+ Determine the species for SSD events.
723
+
724
+ Species is determined from the particle's energy and velocity.
725
+ For velocity, the particle's TOF is normalized with respect
726
+ to a fixed distance dmin between the front and back detectors.
727
+ For SSD events, an adjustment is also made to the path length
728
+ to account for the shorter distances that such events
729
+ travel to reach the detector. The normalized TOF is termed
730
+ the corrected tof (ctof). Particle species are determined from
731
+ the energy and cTOF using a lookup table.
732
+
733
+ Further description is available on pages 42-44 of
734
+ IMAP-Ultra Flight Software Specification document
735
+ (7523-9009_Rev_-.pdf).
736
+
737
+ Parameters
738
+ ----------
739
+ energy : np.ndarray
740
+ Energy from the SSD event (keV).
741
+ tof : np.ndarray
742
+ Time of flight of the SSD event (tenths of a nanosecond).
743
+ path_length : np.ndarray
744
+ Path length (r) (hundredths of a millimeter).
745
+
746
+ Returns
747
+ -------
748
+ bin : np.ndarray
749
+ Species bin.
750
+ """
751
+ # SSD event TOF normalization to Z axis
752
+ ctof = get_ctof(tof, path_length)
753
+
754
+ bin = np.zeros(len(ctof)) # placeholder
755
+
756
+ # TODO: get these lookup tables
757
+ # if r < get_image_params("PathSteepThresh"):
758
+ # # bin = ExTOFSpeciesSteep[energy, ctof]
759
+ # elif r < get_image_params("PathMediumThresh"):
760
+ # # bin = ExTOFSpeciesMedium[energy, ctof]
761
+ # else:
762
+ # # bin = ExTOFSpeciesFlat[energy, ctof]
763
+
764
+ return bin