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,150 @@
1
+ KPL/LSK
2
+
3
+
4
+ LEAPSECONDS KERNEL FILE
5
+ ===========================================================================
6
+
7
+ Modifications:
8
+ --------------
9
+
10
+ 2016, Jul. 14 NJB Modified file to account for the leapsecond that
11
+ will occur on December 31, 2016.
12
+
13
+ 2015, Jan. 5 NJB Modified file to account for the leapsecond that
14
+ will occur on June 30, 2015.
15
+
16
+ 2012, Jan. 5 NJB Modified file to account for the leapsecond that
17
+ will occur on June 30, 2012.
18
+
19
+ 2008, Jul. 7 NJB Modified file to account for the leapsecond that
20
+ will occur on December 31, 2008.
21
+
22
+ 2005, Aug. 3 NJB Modified file to account for the leapsecond that
23
+ will occur on December 31, 2005.
24
+
25
+ 1998, Jul 17 WLT Modified file to account for the leapsecond that
26
+ will occur on December 31, 1998.
27
+
28
+ 1997, Feb 22 WLT Modified file to account for the leapsecond that
29
+ will occur on June 30, 1997.
30
+
31
+ 1995, Dec 14 KSZ Corrected date of last leapsecond from 1-1-95
32
+ to 1-1-96.
33
+
34
+ 1995, Oct 25 WLT Modified file to account for the leapsecond that
35
+ will occur on Dec 31, 1995.
36
+
37
+ 1994, Jun 16 WLT Modified file to account for the leapsecond on
38
+ June 30, 1994.
39
+
40
+ 1993, Feb. 22 CHA Modified file to account for the leapsecond on
41
+ June 30, 1993.
42
+
43
+ 1992, Mar. 6 HAN Modified file to account for the leapsecond on
44
+ June 30, 1992.
45
+
46
+ 1990, Oct. 8 HAN Modified file to account for the leapsecond on
47
+ Dec. 31, 1990.
48
+
49
+
50
+ Explanation:
51
+ ------------
52
+
53
+ The contents of this file are used by the routine DELTET to compute the
54
+ time difference
55
+
56
+ [1] DELTA_ET = ET - UTC
57
+
58
+ the increment to be applied to UTC to give ET.
59
+
60
+ The difference between UTC and TAI,
61
+
62
+ [2] DELTA_AT = TAI - UTC
63
+
64
+ is always an integral number of seconds. The value of DELTA_AT was 10
65
+ seconds in January 1972, and increases by one each time a leap second
66
+ is declared. Combining [1] and [2] gives
67
+
68
+ [3] DELTA_ET = ET - (TAI - DELTA_AT)
69
+
70
+ = (ET - TAI) + DELTA_AT
71
+
72
+ The difference (ET - TAI) is periodic, and is given by
73
+
74
+ [4] ET - TAI = DELTA_T_A + K sin E
75
+
76
+ where DELTA_T_A and K are constant, and E is the eccentric anomaly of the
77
+ heliocentric orbit of the Earth-Moon barycenter. Equation [4], which ignores
78
+ small-period fluctuations, is accurate to about 0.000030 seconds.
79
+
80
+ The eccentric anomaly E is given by
81
+
82
+ [5] E = M + EB sin M
83
+
84
+ where M is the mean anomaly, which in turn is given by
85
+
86
+ [6] M = M + M t
87
+ 0 1
88
+
89
+ where t is the number of ephemeris seconds past J2000.
90
+
91
+ Thus, in order to compute DELTA_ET, the following items are necessary.
92
+
93
+ DELTA_TA
94
+ K
95
+ EB
96
+ M0
97
+ M1
98
+ DELTA_AT after each leap second.
99
+
100
+ The numbers, and the formulation, are taken from the following sources.
101
+
102
+ 1) Moyer, T.D., Transformation from Proper Time on Earth to
103
+ Coordinate Time in Solar System Barycentric Space-Time Frame
104
+ of Reference, Parts 1 and 2, Celestial Mechanics 23 (1981),
105
+ 33-56 and 57-68.
106
+
107
+ 2) Moyer, T.D., Effects of Conversion to the J2000 Astronomical
108
+ Reference System on Algorithms for Computing Time Differences
109
+ and Clock Rates, JPL IOM 314.5--942, 1 October 1985.
110
+
111
+ The variable names used above are consistent with those used in the
112
+ Astronomical Almanac.
113
+
114
+ \begindata
115
+
116
+ DELTET/DELTA_T_A = 32.184
117
+ DELTET/K = 1.657D-3
118
+ DELTET/EB = 1.671D-2
119
+ DELTET/M = ( 6.239996D0 1.99096871D-7 )
120
+
121
+ DELTET/DELTA_AT = ( 10, @1972-JAN-1
122
+ 11, @1972-JUL-1
123
+ 12, @1973-JAN-1
124
+ 13, @1974-JAN-1
125
+ 14, @1975-JAN-1
126
+ 15, @1976-JAN-1
127
+ 16, @1977-JAN-1
128
+ 17, @1978-JAN-1
129
+ 18, @1979-JAN-1
130
+ 19, @1980-JAN-1
131
+ 20, @1981-JUL-1
132
+ 21, @1982-JUL-1
133
+ 22, @1983-JUL-1
134
+ 23, @1985-JUL-1
135
+ 24, @1988-JAN-1
136
+ 25, @1990-JAN-1
137
+ 26, @1991-JAN-1
138
+ 27, @1992-JUL-1
139
+ 28, @1993-JUL-1
140
+ 29, @1994-JUL-1
141
+ 30, @1996-JAN-1
142
+ 31, @1997-JUL-1
143
+ 32, @1999-JAN-1
144
+ 33, @2006-JAN-1
145
+ 34, @2009-JAN-1
146
+ 35, @2012-JUL-1
147
+ 36, @2015-JUL-1
148
+ 37, @2017-JAN-1 )
149
+
150
+ \begintext
@@ -0,0 +1,214 @@
1
+ """Tests coverage for imap_processing/spice/geometry.py"""
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import pytest
6
+ import spiceypy as spice
7
+
8
+ from imap_processing.spice.geometry import (
9
+ SpiceBody,
10
+ SpiceFrame,
11
+ frame_transform,
12
+ get_rotation_matrix,
13
+ get_spacecraft_spin_phase,
14
+ get_spin_data,
15
+ imap_state,
16
+ )
17
+
18
+
19
+ @pytest.mark.parametrize(
20
+ "et",
21
+ [
22
+ 798033670,
23
+ np.linspace(798033670, 798033770),
24
+ ],
25
+ )
26
+ def test_imap_state(et, use_test_metakernel):
27
+ """Test coverage for imap_state()"""
28
+ state = imap_state(et, observer=SpiceBody.EARTH)
29
+ if hasattr(et, "__len__"):
30
+ np.testing.assert_array_equal(state.shape, (len(et), 6))
31
+ else:
32
+ assert state.shape == (6,)
33
+
34
+
35
+ @pytest.mark.external_kernel()
36
+ @pytest.mark.metakernel("imap_ena_sim_metakernel.template")
37
+ def test_imap_state_ecliptic(use_test_metakernel):
38
+ """Tests retrieving IMAP state in the ECLIPJ2000 frame"""
39
+ state = imap_state(798033670)
40
+ assert state.shape == (6,)
41
+
42
+
43
+ @pytest.mark.usefixtures("_set_spin_data_filepath")
44
+ @pytest.mark.parametrize(
45
+ "query_met_times, expected_type, expected_length",
46
+ [
47
+ (453051323.0, float, None), # Scalar test
48
+ (np.array([453051323.0, 453051324.0]), float, 2), # Array test
49
+ (np.array([]), None, 0), # Empty array test
50
+ (np.array([453051323.0]), float, 1), # Single element array test
51
+ # 452995203.0 is a midnight time which should have invalid spin
52
+ # phase and period flags on in the spin data file. The spin phase
53
+ # should be invalid.
54
+ (452995203.0, np.nan, None),
55
+ # Test that five minutes after midnight is also invalid since
56
+ # first 10 minutes after midnight are invalid.
57
+ (np.arange(452995203.0, 452995203.0 + 300), np.nan, 300),
58
+ (
59
+ [453011323.0],
60
+ np.nan,
61
+ 1,
62
+ ), # Test for spin phase that's outside of spin phase range
63
+ (
64
+ 453011323.0,
65
+ np.nan,
66
+ None,
67
+ ), # Test for spin phase that's outside of spin phase range
68
+ ],
69
+ )
70
+ def test_get_spacecraft_spin_phase(query_met_times, expected_type, expected_length):
71
+ """Test get_spacecraft_spin_phase() with generated spin data."""
72
+ # Call the function
73
+ spin_phases = get_spacecraft_spin_phase(query_met_times=query_met_times)
74
+
75
+ # Check the type of the result
76
+ if expected_type is np.nan:
77
+ assert np.isnan(spin_phases).all(), "Spin phase must be NaN."
78
+ elif isinstance(expected_type, float):
79
+ assert isinstance(spin_phases, float), "Spin phase must be a float."
80
+
81
+ # If the expected length is None, it means we're testing a scalar
82
+ if expected_length is None:
83
+ assert isinstance(spin_phases, float), "Spin phase must be a float."
84
+ else:
85
+ assert (
86
+ len(spin_phases) == expected_length
87
+ ), f"Spin phase must have length {expected_length} for array input."
88
+
89
+
90
+ @pytest.mark.usefixtures("_set_spin_data_filepath")
91
+ def test_get_spin_data():
92
+ """Test get_spin_data() with generated spin data."""
93
+
94
+ spin_data = get_spin_data()
95
+
96
+ (
97
+ np.testing.assert_array_equal(spin_data["spin_number"], np.arange(5761)),
98
+ "One day should have 5,761 records of 15 seconds when including end_met.",
99
+ )
100
+ assert isinstance(spin_data, pd.DataFrame), "Return type must be pandas.DataFrame."
101
+
102
+ assert set(spin_data.columns) == {
103
+ "spin_number",
104
+ "spin_start_sec",
105
+ "spin_start_subsec",
106
+ "spin_period_sec",
107
+ "spin_period_valid",
108
+ "spin_phase_valid",
109
+ "spin_period_source",
110
+ "thruster_firing",
111
+ "spin_start_time",
112
+ }, "Spin data must have the specified fields."
113
+
114
+
115
+ def test_frame_transform(furnish_kernels):
116
+ """Test transformation of vectors from one frame to another, with the option
117
+ to normalize the result."""
118
+ # This test requires an IMAP attitude kernel and pointing (despun) kernel
119
+ kernels = [
120
+ "naif0012.tls",
121
+ "imap_wkcp.tf",
122
+ "imap_science_0001.tf",
123
+ "sim_1yr_imap_attitude.bc",
124
+ "sim_1yr_imap_pointing_frame.bc",
125
+ ]
126
+ with furnish_kernels(kernels):
127
+ # Test single et and position calculation
128
+ et_0 = spice.utc2et("2025-04-30T12:00:00.000")
129
+ position = np.arange(3) + 1
130
+ result_0 = frame_transform(
131
+ et_0, position, SpiceFrame.IMAP_ULTRA_45, SpiceFrame.IMAP_DPS
132
+ )
133
+ # compare against pure SPICE calculation
134
+ rotation_matrix = spice.pxform(
135
+ SpiceFrame.IMAP_ULTRA_45.name, SpiceFrame.IMAP_DPS.name, et_0
136
+ )
137
+ spice_result = spice.mxv(rotation_matrix, position)
138
+ np.testing.assert_allclose(result_0, spice_result, atol=1e-12)
139
+
140
+ # test multiple et and position calculation
141
+ ets = np.array([et_0, et_0 + 10])
142
+ positions = np.array([[1, 1, 1], [1, 2, 3]])
143
+ vec_result = frame_transform(
144
+ ets, positions, SpiceFrame.IMAP_HI_90, SpiceFrame.IMAP_DPS
145
+ )
146
+
147
+ assert vec_result.shape == (2, 3)
148
+ # compare with direct spice calculations
149
+ for et, pos, result in zip(ets, positions, vec_result):
150
+ rotation_matrix = spice.pxform(
151
+ SpiceFrame.IMAP_HI_90.name, SpiceFrame.IMAP_DPS.name, et
152
+ )
153
+ spice_result = spice.mxv(rotation_matrix, pos)
154
+ np.testing.assert_allclose(result, spice_result, atol=1e-12)
155
+
156
+
157
+ def test_frame_transform_exceptions():
158
+ """Test that the proper exceptions get raised when input arguments are invalid."""
159
+ with pytest.raises(
160
+ ValueError, match="Position vectors with one dimension must have 3 elements."
161
+ ):
162
+ frame_transform(
163
+ 0, np.arange(4), SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.IMAP_CODICE
164
+ )
165
+ with pytest.raises(
166
+ ValueError,
167
+ match="Ephemeris time must be float when single position vector is provided.",
168
+ ):
169
+ frame_transform(
170
+ np.asarray(0),
171
+ np.array([1, 0, 0]),
172
+ SpiceFrame.ECLIPJ2000,
173
+ SpiceFrame.IMAP_HIT,
174
+ )
175
+ with pytest.raises(ValueError, match="Invalid position shape: "):
176
+ frame_transform(
177
+ np.arange(2),
178
+ np.arange(4).reshape((2, 2)),
179
+ SpiceFrame.ECLIPJ2000,
180
+ SpiceFrame.IMAP_HIT,
181
+ )
182
+ with pytest.raises(
183
+ ValueError,
184
+ match="Mismatch in number of position vectors and Ephemeris times provided.",
185
+ ):
186
+ frame_transform(
187
+ np.arange(2),
188
+ np.arange(9).reshape((3, 3)),
189
+ SpiceFrame.ECLIPJ2000,
190
+ SpiceFrame.IMAP_HIT,
191
+ )
192
+
193
+
194
+ def test_get_rotation_matrix(furnish_kernels):
195
+ """Test coverage for get_rotation_matrix()."""
196
+ kernels = [
197
+ "naif0012.tls",
198
+ "imap_wkcp.tf",
199
+ "imap_science_0001.tf",
200
+ "sim_1yr_imap_attitude.bc",
201
+ "sim_1yr_imap_pointing_frame.bc",
202
+ ]
203
+ with furnish_kernels(kernels):
204
+ et = spice.utc2et("2025-09-30T12:00:00.000")
205
+ # test input of float
206
+ rotation = get_rotation_matrix(
207
+ et, SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT
208
+ )
209
+ assert rotation.shape == (3, 3)
210
+ # test array of et input
211
+ rotation = get_rotation_matrix(
212
+ np.arange(10) + et, SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT
213
+ )
214
+ assert rotation.shape == (10, 3, 3)
@@ -0,0 +1,272 @@
1
+ """Tests coverage for imap_processing/spice/kernels.py"""
2
+
3
+ import numpy as np
4
+ import pytest
5
+ import spiceypy as spice
6
+ from spiceypy.utils.exceptions import SpiceyError
7
+
8
+ from imap_processing.spice.kernels import (
9
+ _average_quaternions,
10
+ _create_rotation_matrix,
11
+ _get_et_times,
12
+ create_pointing_frame,
13
+ ensure_spice,
14
+ )
15
+
16
+
17
+ @pytest.fixture()
18
+ def pointing_frame_kernels(spice_test_data_path):
19
+ """List SPICE kernels."""
20
+ required_kernels = [
21
+ "imap_science_0001.tf",
22
+ "imap_sclk_0000.tsc",
23
+ "imap_sim_ck_2hr_2secsampling_with_nutation.bc",
24
+ "imap_wkcp.tf",
25
+ "naif0012.tls",
26
+ ]
27
+ kernels = [str(spice_test_data_path / kernel) for kernel in required_kernels]
28
+ return kernels
29
+
30
+
31
+ @pytest.fixture()
32
+ def multiple_pointing_kernels(spice_test_data_path):
33
+ """List SPICE kernels."""
34
+ required_kernels = [
35
+ "imap_science_0001.tf",
36
+ "imap_sclk_0000.tsc",
37
+ "sim_1yr_imap_attitude.bc",
38
+ "imap_wkcp.tf",
39
+ "naif0012.tls",
40
+ ]
41
+ kernels = [str(spice_test_data_path / kernel) for kernel in required_kernels]
42
+ return kernels
43
+
44
+
45
+ @pytest.fixture()
46
+ def et_times(pointing_frame_kernels):
47
+ """Tests get_et_times function."""
48
+ spice.furnsh(pointing_frame_kernels)
49
+
50
+ ck_kernel, _, _, _ = spice.kdata(0, "ck")
51
+ ck_cover = spice.ckcov(ck_kernel, -43000, True, "INTERVAL", 0, "TDB")
52
+ et_start, et_end = spice.wnfetd(ck_cover, 0)
53
+ et_times = _get_et_times(et_start, et_end)
54
+
55
+ return et_times
56
+
57
+
58
+ @ensure_spice
59
+ def single_wrap_et2utc(et, fmt, prec):
60
+ """Directly decorate a spice function with ensure_spice for use in tests"""
61
+ return spice.et2utc(et, fmt, prec)
62
+
63
+
64
+ @ensure_spice
65
+ def double_wrap_et2utc(et, fmt, prec):
66
+ """Decorate a spice function twice with ensure_spice for use in tests. This
67
+ simulates some decorated outer functions that call lower level functions
68
+ that are already decorated."""
69
+ return single_wrap_et2utc(et, fmt, prec)
70
+
71
+
72
+ @ensure_spice(time_kernels_only=True)
73
+ def single_wrap_et2utc_tk_only(et, fmt, prec):
74
+ """Directly wrap a spice function with optional time_kernels_only set True"""
75
+ return spice.et2utc(et, fmt, prec)
76
+
77
+
78
+ @ensure_spice(time_kernels_only=True)
79
+ def double_wrap_et2utc_tk_only(et, fmt, prec):
80
+ """Decorate a spice function twice with ensure_spice for use in tests. This
81
+ simulates some decorated outer functions that call lower level functions
82
+ that are already decorated."""
83
+ return single_wrap_et2utc(et, fmt, prec)
84
+
85
+
86
+ @pytest.mark.parametrize(
87
+ "func",
88
+ [
89
+ single_wrap_et2utc,
90
+ single_wrap_et2utc_tk_only,
91
+ double_wrap_et2utc,
92
+ double_wrap_et2utc_tk_only,
93
+ ],
94
+ )
95
+ def test_ensure_spice_emus_mk_path(func, use_test_metakernel):
96
+ """Test functionality of ensure spice with SPICE_METAKERNEL set"""
97
+ assert func(577365941.184, "ISOC", 3) == "2018-04-18T23:24:31.998"
98
+
99
+
100
+ @pytest.mark.xfail(reason="Fix this test once we add metakernel in the imap_cli")
101
+ @pytest.mark.usefixtures("_unset_metakernel_path")
102
+ def test_ensure_spice_time_kernels():
103
+ """Test functionality of ensure spice with timekernels set"""
104
+ wrapped = ensure_spice(spice.et2utc, time_kernels_only=True)
105
+ # TODO: Update/remove this test when a decision has been made about
106
+ # whether IMAP will use the time_kernels_only functionality and the
107
+ # ensure_spice decorator has been update.
108
+ with pytest.raises(NotImplementedError):
109
+ _ = wrapped(577365941.184, "ISOC", 3) == "2018-04-18T23:24:31.998"
110
+
111
+
112
+ @pytest.mark.xfail(reason="Fix this test once we add metakernel in the imap_cli")
113
+ @pytest.mark.usefixtures("_unset_metakernel_path")
114
+ def test_ensure_spice_key_error():
115
+ """Test functionality of ensure spice when all branches fail"""
116
+ wrapped = ensure_spice(spice.et2utc)
117
+ # The ensure_spice decorator should raise a SpiceyError when all attempts to
118
+ # furnish a set of kernels with sufficient coverage for the spiceypy
119
+ # functions that it decorates.
120
+ with pytest.raises(SpiceyError):
121
+ _ = wrapped(577365941.184, "ISOC", 3) == "2018-04-18T23:24:31.998"
122
+
123
+
124
+ def test_average_quaternions(et_times, pointing_frame_kernels):
125
+ """Tests average_quaternions function."""
126
+ spice.furnsh(pointing_frame_kernels)
127
+ q_avg = _average_quaternions(et_times)
128
+
129
+ # Generated from MATLAB code results
130
+ q_avg_expected = np.array([-0.6611, 0.4981, -0.5019, -0.2509])
131
+ np.testing.assert_allclose(q_avg, q_avg_expected, atol=1e-4)
132
+
133
+
134
+ def test_create_rotation_matrix(et_times, pointing_frame_kernels):
135
+ """Tests create_rotation_matrix function."""
136
+ spice.furnsh(pointing_frame_kernels)
137
+ rotation_matrix = _create_rotation_matrix(et_times)
138
+ q_avg = _average_quaternions(et_times)
139
+ z_avg = spice.q2m(list(q_avg))[:, 2]
140
+
141
+ rotation_matrix_expected = np.array(
142
+ [[0.0000, 0.0000, 1.0000], [0.9104, -0.4136, 0.0000], [0.4136, 0.9104, 0.0000]]
143
+ )
144
+ z_avg_expected = np.array([0.4136, 0.9104, 0.0000])
145
+
146
+ np.testing.assert_allclose(z_avg, z_avg_expected, atol=1e-4)
147
+ np.testing.assert_allclose(rotation_matrix, rotation_matrix_expected, atol=1e-4)
148
+
149
+
150
+ def test_create_pointing_frame(
151
+ spice_test_data_path, pointing_frame_kernels, tmp_path, et_times
152
+ ):
153
+ """Tests create_pointing_frame function."""
154
+ spice.kclear()
155
+ spice.furnsh(pointing_frame_kernels)
156
+ create_pointing_frame(
157
+ pointing_frame_path=tmp_path / "imap_dps.bc",
158
+ ck_path=spice_test_data_path / "imap_sim_ck_2hr_2secsampling_with_nutation.bc",
159
+ )
160
+
161
+ # After imap_dps.bc has been created.
162
+ dps_kernel = str(tmp_path / "imap_dps.bc")
163
+
164
+ spice.furnsh(dps_kernel)
165
+ rotation_matrix_1 = spice.pxform("ECLIPJ2000", "IMAP_DPS", et_times[0] + 100)
166
+ rotation_matrix_2 = spice.pxform("ECLIPJ2000", "IMAP_DPS", et_times[0] + 1000)
167
+
168
+ # All the rotation matrices should be the same.
169
+ assert np.array_equal(rotation_matrix_1, rotation_matrix_2)
170
+
171
+ # Nick Dutton's MATLAB code result
172
+ rotation_matrix_expected = np.array(
173
+ [[0.0000, 0.0000, 1.0000], [0.9104, -0.4136, 0.0000], [0.4136, 0.9104, 0.0000]]
174
+ )
175
+ np.testing.assert_allclose(rotation_matrix_1, rotation_matrix_expected, atol=1e-4)
176
+
177
+ # Verify imap_dps.bc has been created.
178
+ assert (tmp_path / "imap_dps.bc").exists()
179
+
180
+ # Tests error handling when incorrect kernel is loaded.
181
+ spice.furnsh(pointing_frame_kernels)
182
+ with pytest.raises(
183
+ ValueError, match="Error: Expected CK kernel badname_kernel.bc"
184
+ ): # Replace match string with expected error message
185
+ create_pointing_frame(
186
+ pointing_frame_path=tmp_path / "imap_dps.bc", ck_path="badname_kernel.bc"
187
+ )
188
+
189
+
190
+ def test_et_times(pointing_frame_kernels):
191
+ """Tests get_et_times function."""
192
+ spice.furnsh(pointing_frame_kernels)
193
+
194
+ ck_kernel, _, _, _ = spice.kdata(0, "ck")
195
+ ck_cover = spice.ckcov(ck_kernel, -43000, True, "INTERVAL", 0, "TDB")
196
+ et_start, et_end = spice.wnfetd(ck_cover, 0)
197
+ et_times = _get_et_times(et_start, et_end)
198
+
199
+ assert et_times[0] == et_start
200
+ assert et_times[-1] == et_end
201
+
202
+ return et_times
203
+
204
+
205
+ def test_multiple_attempts(pointing_frame_kernels, tmp_path, spice_test_data_path):
206
+ """Tests create_pointing_frame function with multiple pointing kernels."""
207
+ spice.furnsh(pointing_frame_kernels)
208
+
209
+ # Check that a single segment is added regardless of how many times
210
+ # create_pointing_frame is called.
211
+ create_pointing_frame(
212
+ pointing_frame_path=tmp_path / "imap_dps.bc",
213
+ ck_path=spice_test_data_path / "imap_sim_ck_2hr_2secsampling_with_nutation.bc",
214
+ )
215
+ ck_cover = spice.ckcov(
216
+ str(tmp_path / "imap_dps.bc"), -43901, True, "INTERVAL", 0, "TDB"
217
+ )
218
+ num_intervals = spice.wncard(ck_cover)
219
+ assert num_intervals == 1
220
+
221
+ create_pointing_frame(
222
+ pointing_frame_path=tmp_path / "imap_dps.bc",
223
+ ck_path=spice_test_data_path / "imap_sim_ck_2hr_2secsampling_with_nutation.bc",
224
+ )
225
+ ck_cover = spice.ckcov(
226
+ str(tmp_path / "imap_dps.bc"), -43901, True, "INTERVAL", 0, "TDB"
227
+ )
228
+ num_intervals = spice.wncard(ck_cover)
229
+ assert num_intervals == 1
230
+
231
+
232
+ def test_multiple_pointings(pointing_frame_kernels, spice_test_data_path, tmp_path):
233
+ """Tests create_pointing_frame function with multiple pointing kernels."""
234
+ spice.furnsh(pointing_frame_kernels)
235
+
236
+ create_pointing_frame(
237
+ pointing_frame_path=tmp_path / "imap_pointing_frame.bc",
238
+ ck_path=spice_test_data_path / "imap_sim_ck_2hr_2secsampling_with_nutation.bc",
239
+ )
240
+ ck_cover_pointing = spice.ckcov(
241
+ str(tmp_path / "imap_pointing_frame.bc"),
242
+ -43901,
243
+ True,
244
+ "INTERVAL",
245
+ 0,
246
+ "TDB",
247
+ )
248
+ num_intervals = spice.wncard(ck_cover_pointing)
249
+ et_start_pointing, et_end_pointing = spice.wnfetd(ck_cover_pointing, 0)
250
+
251
+ ck_cover = spice.ckcov(
252
+ str(spice_test_data_path / "imap_sim_ck_2hr_2secsampling_with_nutation.bc"),
253
+ -43000,
254
+ True,
255
+ "INTERVAL",
256
+ 0,
257
+ "TDB",
258
+ )
259
+ num_intervals_expected = spice.wncard(ck_cover)
260
+ et_start_expected, et_end_expected = spice.wnfetd(ck_cover, 0)
261
+
262
+ assert num_intervals == num_intervals_expected
263
+ assert et_start_pointing == et_start_expected
264
+ assert et_end_pointing == et_end_expected
265
+
266
+ et_times = _get_et_times(et_start_pointing, et_end_pointing)
267
+
268
+ spice.furnsh(str(tmp_path / "imap_pointing_frame.bc"))
269
+ rotation_matrix_1 = spice.pxform("ECLIPJ2000", "IMAP_DPS", et_times[100])
270
+ rotation_matrix_2 = spice.pxform("ECLIPJ2000", "IMAP_DPS", et_times[1000])
271
+
272
+ assert np.array_equal(rotation_matrix_1, rotation_matrix_2)
@@ -0,0 +1,35 @@
1
+ """Tests coverage for imap_processing/spice/time.py"""
2
+
3
+ import numpy as np
4
+ import pytest
5
+ import spiceypy as spice
6
+
7
+ from imap_processing.spice import IMAP_SC_ID
8
+ from imap_processing.spice.time import _sct2e_wrapper, met_to_j2000ns
9
+
10
+
11
+ def test_met_to_j2000ns(furnish_time_kernels):
12
+ """Test coverage for met_to_j2000ns function."""
13
+ utc = "2026-01-01T00:00:00.125"
14
+ et = spice.str2et(utc)
15
+ sclk_str = spice.sce2s(IMAP_SC_ID, et)
16
+ seconds, ticks = sclk_str.split("/")[1].split(":")
17
+ # There is some floating point error calculating tick duration from 1 clock
18
+ # tick so average over many clock ticks for better accuracy
19
+ spice_tick_duration = (
20
+ spice.sct2e(IMAP_SC_ID, 1e12) - spice.sct2e(IMAP_SC_ID, 0)
21
+ ) / 1e12
22
+ met = float(seconds) + float(ticks) * spice_tick_duration
23
+ j2000ns = met_to_j2000ns(met)
24
+ assert j2000ns.dtype == np.int64
25
+ np.testing.assert_array_equal(j2000ns, np.array(et * 1e9))
26
+
27
+
28
+ @pytest.mark.parametrize("sclk_ticks", [0.0, np.arange(10)])
29
+ def test_sct2e_wrapper(sclk_ticks):
30
+ """Test for `_sct2e_wrapper` function."""
31
+ et = _sct2e_wrapper(sclk_ticks)
32
+ if isinstance(sclk_ticks, float):
33
+ assert isinstance(et, float)
34
+ else:
35
+ assert len(et) == len(sclk_ticks)
File without changes
@@ -0,0 +1,16 @@
1
+ import pytest
2
+
3
+
4
+ @pytest.fixture(scope="session")
5
+ def swapi_test_data_path(imap_tests_path):
6
+ return imap_tests_path / "swapi/"
7
+
8
+
9
+ @pytest.fixture(scope="session")
10
+ def swapi_l0_test_data_path(swapi_test_data_path):
11
+ return swapi_test_data_path / "l0_data/"
12
+
13
+
14
+ @pytest.fixture(scope="session")
15
+ def swapi_l0_validation_data_path(swapi_test_data_path):
16
+ return swapi_test_data_path / "l0_validation_data/"
File without changes