imap-processing 0.11.0__py3-none-any.whl → 0.13.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.

Potentially problematic release.


This version of imap-processing might be problematic. Click here for more details.

Files changed (415) hide show
  1. imap_processing/__init__.py +11 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +66 -18
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +24 -40
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +934 -42
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  9. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  10. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  11. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -14
  12. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  13. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  14. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  15. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +25 -9
  16. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  17. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  18. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  19. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  20. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +23 -20
  21. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  22. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  23. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  24. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  25. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  26. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  27. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  28. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  29. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  30. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +64 -52
  31. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  32. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +180 -19
  33. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  34. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +80 -17
  35. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +32 -57
  36. imap_processing/cdf/utils.py +52 -38
  37. imap_processing/cli.py +477 -233
  38. imap_processing/codice/codice_l1a.py +466 -131
  39. imap_processing/codice/codice_l1b.py +51 -152
  40. imap_processing/codice/constants.py +1360 -569
  41. imap_processing/codice/decompress.py +2 -6
  42. imap_processing/ena_maps/ena_maps.py +1103 -146
  43. imap_processing/ena_maps/utils/coordinates.py +19 -0
  44. imap_processing/ena_maps/utils/map_utils.py +14 -17
  45. imap_processing/ena_maps/utils/spatial_utils.py +55 -52
  46. imap_processing/glows/l1a/glows_l1a.py +28 -99
  47. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  48. imap_processing/glows/l1b/glows_l1b.py +1 -4
  49. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  50. imap_processing/glows/l2/glows_l2.py +2 -5
  51. imap_processing/hi/l1a/hi_l1a.py +54 -29
  52. imap_processing/hi/l1a/histogram.py +0 -1
  53. imap_processing/hi/l1a/science_direct_event.py +6 -8
  54. imap_processing/hi/l1b/hi_l1b.py +111 -82
  55. imap_processing/hi/l1c/hi_l1c.py +416 -32
  56. imap_processing/hi/utils.py +58 -12
  57. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  58. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  59. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  60. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  61. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  62. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  63. imap_processing/hit/hit_utils.py +235 -5
  64. imap_processing/hit/l0/constants.py +20 -11
  65. imap_processing/hit/l0/decom_hit.py +21 -5
  66. imap_processing/hit/l1a/hit_l1a.py +71 -75
  67. imap_processing/hit/l1b/constants.py +321 -0
  68. imap_processing/hit/l1b/hit_l1b.py +377 -67
  69. imap_processing/hit/l2/constants.py +318 -0
  70. imap_processing/hit/l2/hit_l2.py +723 -0
  71. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  72. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  73. imap_processing/ialirt/l0/parse_mag.py +374 -0
  74. imap_processing/ialirt/l0/process_swapi.py +69 -0
  75. imap_processing/ialirt/l0/process_swe.py +548 -0
  76. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -208
  77. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  78. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  79. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  80. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  81. imap_processing/ialirt/utils/grouping.py +114 -0
  82. imap_processing/ialirt/utils/time.py +29 -0
  83. imap_processing/idex/atomic_masses.csv +22 -0
  84. imap_processing/idex/decode.py +2 -2
  85. imap_processing/idex/idex_constants.py +33 -0
  86. imap_processing/idex/idex_l0.py +22 -8
  87. imap_processing/idex/idex_l1a.py +81 -51
  88. imap_processing/idex/idex_l1b.py +13 -39
  89. imap_processing/idex/idex_l2a.py +823 -0
  90. imap_processing/idex/idex_l2b.py +120 -0
  91. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +11 -11
  92. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  93. imap_processing/lo/l0/lo_science.py +7 -2
  94. imap_processing/lo/l1a/lo_l1a.py +1 -5
  95. imap_processing/lo/l1b/lo_l1b.py +702 -29
  96. imap_processing/lo/l1b/tof_conversions.py +11 -0
  97. imap_processing/lo/l1c/lo_l1c.py +1 -4
  98. imap_processing/mag/constants.py +51 -0
  99. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  100. imap_processing/mag/l0/decom_mag.py +10 -3
  101. imap_processing/mag/l1a/mag_l1a.py +23 -19
  102. imap_processing/mag/l1a/mag_l1a_data.py +35 -10
  103. imap_processing/mag/l1b/mag_l1b.py +259 -50
  104. imap_processing/mag/l1c/interpolation_methods.py +388 -0
  105. imap_processing/mag/l1c/mag_l1c.py +621 -17
  106. imap_processing/mag/l2/mag_l2.py +140 -0
  107. imap_processing/mag/l2/mag_l2_data.py +288 -0
  108. imap_processing/quality_flags.py +1 -0
  109. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  110. imap_processing/spacecraft/quaternions.py +121 -0
  111. imap_processing/spice/geometry.py +19 -22
  112. imap_processing/spice/kernels.py +0 -276
  113. imap_processing/spice/pointing_frame.py +257 -0
  114. imap_processing/spice/repoint.py +149 -0
  115. imap_processing/spice/spin.py +38 -33
  116. imap_processing/spice/time.py +24 -0
  117. imap_processing/swapi/l1/swapi_l1.py +20 -12
  118. imap_processing/swapi/l2/swapi_l2.py +116 -5
  119. imap_processing/swapi/swapi_utils.py +32 -0
  120. imap_processing/swe/l1a/swe_l1a.py +44 -12
  121. imap_processing/swe/l1a/swe_science.py +13 -13
  122. imap_processing/swe/l1b/swe_l1b.py +898 -23
  123. imap_processing/swe/l2/swe_l2.py +75 -136
  124. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  125. imap_processing/swe/utils/swe_constants.py +64 -0
  126. imap_processing/swe/utils/swe_utils.py +85 -28
  127. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  128. imap_processing/tests/ccsds/test_excel_to_xtce.py +24 -21
  129. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  130. imap_processing/tests/cdf/test_utils.py +14 -16
  131. imap_processing/tests/codice/conftest.py +44 -33
  132. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  133. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  134. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  135. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  136. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  137. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  138. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  139. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  140. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  141. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  142. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  143. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  144. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  145. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  146. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  147. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  148. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  149. imap_processing/tests/codice/test_codice_l1a.py +126 -53
  150. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  151. imap_processing/tests/codice/test_decompress.py +4 -4
  152. imap_processing/tests/conftest.py +239 -27
  153. imap_processing/tests/ena_maps/conftest.py +51 -0
  154. imap_processing/tests/ena_maps/test_ena_maps.py +1068 -110
  155. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  156. imap_processing/tests/ena_maps/test_spatial_utils.py +17 -21
  157. imap_processing/tests/glows/conftest.py +10 -14
  158. imap_processing/tests/glows/test_glows_decom.py +4 -4
  159. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  160. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  161. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  162. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  163. imap_processing/tests/glows/test_glows_l2.py +2 -8
  164. imap_processing/tests/hi/conftest.py +1 -1
  165. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  166. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  167. imap_processing/tests/hi/test_hi_l1b.py +22 -27
  168. imap_processing/tests/hi/test_hi_l1c.py +249 -18
  169. imap_processing/tests/hi/test_l1a.py +35 -7
  170. imap_processing/tests/hi/test_science_direct_event.py +3 -3
  171. imap_processing/tests/hi/test_utils.py +24 -2
  172. imap_processing/tests/hit/helpers/l1_validation.py +74 -73
  173. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  174. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  175. imap_processing/tests/hit/test_decom_hit.py +5 -1
  176. imap_processing/tests/hit/test_hit_l1a.py +32 -36
  177. imap_processing/tests/hit/test_hit_l1b.py +300 -81
  178. imap_processing/tests/hit/test_hit_l2.py +716 -0
  179. imap_processing/tests/hit/test_hit_utils.py +184 -7
  180. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  181. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  182. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  183. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  184. imap_processing/tests/ialirt/data/l0/461971383-404.bin +0 -0
  185. imap_processing/tests/ialirt/data/l0/461971384-405.bin +0 -0
  186. imap_processing/tests/ialirt/data/l0/461971385-406.bin +0 -0
  187. imap_processing/tests/ialirt/data/l0/461971386-407.bin +0 -0
  188. imap_processing/tests/ialirt/data/l0/461971387-408.bin +0 -0
  189. imap_processing/tests/ialirt/data/l0/461971388-409.bin +0 -0
  190. imap_processing/tests/ialirt/data/l0/461971389-410.bin +0 -0
  191. imap_processing/tests/ialirt/data/l0/461971390-411.bin +0 -0
  192. imap_processing/tests/ialirt/data/l0/461971391-412.bin +0 -0
  193. imap_processing/tests/ialirt/data/l0/sample_decoded_i-alirt_data.csv +383 -0
  194. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  195. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  196. imap_processing/tests/ialirt/unit/test_parse_mag.py +223 -0
  197. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  198. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  199. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  200. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  201. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  202. imap_processing/tests/ialirt/unit/test_process_swe.py +319 -6
  203. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  204. imap_processing/tests/idex/conftest.py +127 -6
  205. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  206. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  207. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  208. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  209. imap_processing/tests/idex/test_idex_l0.py +33 -11
  210. imap_processing/tests/idex/test_idex_l1a.py +92 -21
  211. imap_processing/tests/idex/test_idex_l1b.py +106 -27
  212. imap_processing/tests/idex/test_idex_l2a.py +399 -0
  213. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  214. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  215. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  216. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  217. imap_processing/tests/lo/test_lo_l1b.py +515 -6
  218. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  219. imap_processing/tests/lo/test_lo_science.py +7 -7
  220. imap_processing/tests/lo/test_star_sensor.py +1 -1
  221. imap_processing/tests/mag/conftest.py +120 -2
  222. imap_processing/tests/mag/test_mag_decom.py +5 -4
  223. imap_processing/tests/mag/test_mag_l1a.py +51 -7
  224. imap_processing/tests/mag/test_mag_l1b.py +40 -59
  225. imap_processing/tests/mag/test_mag_l1c.py +354 -19
  226. imap_processing/tests/mag/test_mag_l2.py +130 -0
  227. imap_processing/tests/mag/test_mag_validation.py +247 -26
  228. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  229. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  230. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  231. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  232. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  233. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  234. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  235. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  236. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  237. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  238. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  239. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  240. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  241. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  242. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  243. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  244. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  245. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  246. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  247. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  248. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  249. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  250. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  251. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  252. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  253. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  254. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  255. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  256. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  257. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  258. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  259. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  260. imap_processing/tests/mag/validation/calibration/imap_mag_l1b-calibration_20240229_v001.cdf +0 -0
  261. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  262. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  263. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  264. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  265. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  266. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  267. imap_processing/tests/spice/test_geometry.py +9 -12
  268. imap_processing/tests/spice/test_kernels.py +1 -200
  269. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  270. imap_processing/tests/spice/test_repoint.py +121 -0
  271. imap_processing/tests/spice/test_spin.py +50 -9
  272. imap_processing/tests/spice/test_time.py +14 -0
  273. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  274. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  275. imap_processing/tests/swapi/test_swapi_l1.py +13 -11
  276. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  277. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  278. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  279. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  280. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  281. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  282. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  283. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  284. imap_processing/tests/swe/test_swe_l1a.py +20 -2
  285. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  286. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  287. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  288. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  289. imap_processing/tests/swe/test_swe_l2.py +153 -91
  290. imap_processing/tests/test_cli.py +171 -88
  291. imap_processing/tests/test_utils.py +140 -17
  292. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  293. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  294. imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3243 -3243
  295. imap_processing/tests/ultra/data/mock_data.py +369 -0
  296. imap_processing/tests/ultra/unit/conftest.py +115 -89
  297. imap_processing/tests/ultra/unit/test_badtimes.py +4 -4
  298. imap_processing/tests/ultra/unit/test_cullingmask.py +8 -6
  299. imap_processing/tests/ultra/unit/test_de.py +14 -13
  300. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  301. imap_processing/tests/ultra/unit/test_decom_apid_881.py +54 -11
  302. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  303. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  304. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  305. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +77 -0
  306. imap_processing/tests/ultra/unit/test_ultra_l1a.py +98 -305
  307. imap_processing/tests/ultra/unit/test_ultra_l1b.py +60 -14
  308. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  309. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +26 -27
  310. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +239 -70
  311. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  312. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +114 -83
  313. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  314. imap_processing/ultra/constants.py +1 -1
  315. imap_processing/ultra/l0/decom_tools.py +27 -39
  316. imap_processing/ultra/l0/decom_ultra.py +168 -204
  317. imap_processing/ultra/l0/ultra_utils.py +152 -136
  318. imap_processing/ultra/l1a/ultra_l1a.py +55 -271
  319. imap_processing/ultra/l1b/badtimes.py +1 -4
  320. imap_processing/ultra/l1b/cullingmask.py +2 -6
  321. imap_processing/ultra/l1b/de.py +116 -57
  322. imap_processing/ultra/l1b/extendedspin.py +20 -18
  323. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  324. imap_processing/ultra/l1b/ultra_l1b.py +36 -16
  325. imap_processing/ultra/l1b/ultra_l1b_culling.py +66 -30
  326. imap_processing/ultra/l1b/ultra_l1b_extended.py +297 -94
  327. imap_processing/ultra/l1c/histogram.py +2 -6
  328. imap_processing/ultra/l1c/spacecraft_pset.py +84 -0
  329. imap_processing/ultra/l1c/ultra_l1c.py +8 -9
  330. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +206 -108
  331. imap_processing/ultra/l2/ultra_l2.py +299 -0
  332. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  333. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  334. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  335. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  336. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  337. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  338. imap_processing/ultra/packet_definitions/README.md +38 -0
  339. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  340. imap_processing/ultra/utils/ultra_l1_utils.py +31 -12
  341. imap_processing/utils.py +69 -29
  342. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +10 -6
  343. imap_processing-0.13.0.dist-info/RECORD +578 -0
  344. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  345. imap_processing/hi/l1a/housekeeping.py +0 -27
  346. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  347. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  348. imap_processing/swe/l1b/swe_l1b_science.py +0 -652
  349. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  350. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  351. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  352. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  353. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  354. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  355. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  356. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  357. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  358. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  359. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  360. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  361. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  362. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  363. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  364. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  365. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  366. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  367. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  368. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  369. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  370. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  371. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  372. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  373. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  374. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  375. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  376. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  377. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  378. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  379. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  380. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  381. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  382. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  383. imap_processing/tests/swe/test_swe_l1b_science.py +0 -84
  384. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  385. imap_processing/ultra/l1c/pset.py +0 -40
  386. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  387. imap_processing-0.11.0.dist-info/RECORD +0 -488
  388. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  389. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  390. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  391. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  392. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  393. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  394. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  395. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  396. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  397. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  398. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  399. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  400. /imap_processing/{mag/l1b → tests/spacecraft}/__init__.py +0 -0
  401. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  402. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  403. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  404. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  405. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  406. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  407. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  408. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  409. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  410. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  411. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  412. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  413. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  414. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  415. {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,121 @@
1
+ """Spacecraft quaternion processing."""
2
+
3
+ from pathlib import Path
4
+
5
+ import numpy as np
6
+ import xarray as xr
7
+
8
+ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
9
+ from imap_processing.spice.time import met_to_ttj2000ns
10
+ from imap_processing.utils import packet_file_to_datasets
11
+
12
+
13
+ def load_quaternion_packets(packet_file: Path | str) -> xr.Dataset:
14
+ """
15
+ Load the raw quaternion packets from the packet file.
16
+
17
+ Parameters
18
+ ----------
19
+ packet_file : Path
20
+ Path to the packet file containing the quaternions in apid 594.
21
+
22
+ Returns
23
+ -------
24
+ xarray.Dataset
25
+ Dataset containing the raw quaternion packets.
26
+ """
27
+ xtce_packet_definition = Path(__file__).parent / "packet_definitions/scid_x252.xml"
28
+ datasets_by_apid = packet_file_to_datasets(
29
+ packet_file=packet_file, xtce_packet_definition=xtce_packet_definition
30
+ )
31
+ return datasets_by_apid[0x252]
32
+
33
+
34
+ def assemble_quaternions(ds: xr.Dataset) -> xr.Dataset:
35
+ """
36
+ Assemble quaternions from the l1a dataset.
37
+
38
+ The quaternions are stored in separate variables for each component (x, y, z, s)
39
+ and for each 10 Hz sample of the 1s packet. i.e. there are 4 * 10 = 40 variables
40
+ in the initial dataset that we want to turn into 4 variables with a continuous
41
+ 10 Hz sampling period.
42
+
43
+ The output dataset will have a single dimension "epoch" that will be the time
44
+ associated with each of the 10 Hz samples. There are 4 data variables: "quat_x",
45
+ "quat_y", "quat_z", "quat_s".
46
+
47
+ Parameters
48
+ ----------
49
+ ds : xarray.Dataset
50
+ Input dataset containing the 10Hz quaternions from packet 0x252 (APID 594).
51
+
52
+ Returns
53
+ -------
54
+ xarray.Dataset
55
+ Output dataset with the quaternions assembled into 4 variables with a
56
+ continuous 10 Hz sampling period.
57
+ """
58
+ # Our time is only given for the first timestamp
59
+ # We then add to it 0.1 increments and ravel the array to associate a specific time
60
+ # with each of the 10 samples
61
+ time = (
62
+ ds["SCIENCEDATA1HZ_QUAT_10_HZ_TIME".lower()].values[:, np.newaxis]
63
+ + np.arange(0, 1, 0.1)
64
+ ).ravel()
65
+ output_ds = xr.Dataset(coords={"epoch": time})
66
+ base_name = "FSW_ACS_QUAT_10_HZ_BUFFERED".lower()
67
+ for quat_i, label in enumerate(["x", "y", "z", "s"]):
68
+ # 0, 1, 2, .. 9 // 10, 11, 12, .. 19 // 20, 21, 22, .. 29 // 30, 31, 32, .. 39
69
+ names = [f"{base_name}_{i + quat_i * 10}" for i in range(10)]
70
+ quat = np.stack([ds[name] for name in names], axis=1).ravel()
71
+ output_ds[f"quat_{label}"] = ("epoch", quat)
72
+ return output_ds
73
+
74
+
75
+ def process_quaternions(packet_file: Path | str) -> tuple[xr.Dataset, xr.Dataset]:
76
+ """
77
+ Generate l1a and l1b datasets from a packet file containing the raw quaternions.
78
+
79
+ This produces two CDF files: one for the l1a quaternions and one for the l1b
80
+ quaternions. The l1b quaternions are assembled into 4 variables: "quat_x",
81
+ "quat_y", "quat_z", "quat_s".
82
+
83
+ Parameters
84
+ ----------
85
+ packet_file : Path
86
+ Path to the packet file containing the quaternions in apid 594.
87
+
88
+ Returns
89
+ -------
90
+ xarray.Dataset
91
+ Dataset containing the l1a quaternions.
92
+ xarray.Dataset
93
+ Dataset containing the l1b quaternions.
94
+ """
95
+ l1a_ds = load_quaternion_packets(packet_file)
96
+
97
+ # Assemble the quaternions into the correct components
98
+ l1b_ds = assemble_quaternions(l1a_ds)
99
+
100
+ # Update dataset global attributes
101
+ attr_mgr = ImapCdfAttributes()
102
+ attr_mgr.add_instrument_global_attrs("spacecraft")
103
+ attr_mgr.add_instrument_variable_attrs(instrument="spacecraft", level=None)
104
+
105
+ l1a_ds.attrs.update(
106
+ attr_mgr.get_global_attributes("imap_spacecraft_l1a_quaternions")
107
+ )
108
+ l1b_ds.attrs.update(
109
+ attr_mgr.get_global_attributes("imap_spacecraft_l1b_quaternions")
110
+ )
111
+
112
+ # Update the epoch attribute
113
+ l1b_ds["epoch"] = met_to_ttj2000ns(l1b_ds["epoch"])
114
+ # check_schema=False keeps DEPEND_0 = '' from being auto added
115
+ epoch_attrs = attr_mgr.get_variable_attributes("epoch", check_schema=False)
116
+ l1b_ds["epoch"].attrs.update(epoch_attrs)
117
+
118
+ for var in ["quat_x", "quat_y", "quat_z", "quat_s"]:
119
+ l1b_ds[var].attrs.update(attr_mgr.get_variable_attributes(var))
120
+
121
+ return l1a_ds, l1b_ds
@@ -63,7 +63,7 @@ class SpiceFrame(IntEnum):
63
63
 
64
64
 
65
65
  BORESIGHT_LOOKUP = {
66
- SpiceFrame.IMAP_LO: np.array([0, -1, 0]),
66
+ SpiceFrame.IMAP_LO_BASE: np.array([0, -1, 0]),
67
67
  SpiceFrame.IMAP_HI_45: np.array([0, 1, 0]),
68
68
  SpiceFrame.IMAP_HI_90: np.array([0, 1, 0]),
69
69
  SpiceFrame.IMAP_ULTRA_45: np.array([0, 0, 1]),
@@ -136,7 +136,7 @@ def get_spacecraft_to_instrument_spin_phase_offset(instrument: SpiceFrame) -> fl
136
136
  """
137
137
  # TODO: Implement retrieval from SPICE?
138
138
  offset_lookup = {
139
- SpiceFrame.IMAP_LO: 330 / 360,
139
+ SpiceFrame.IMAP_LO_BASE: 330 / 360,
140
140
  SpiceFrame.IMAP_HI_45: 255 / 360,
141
141
  SpiceFrame.IMAP_HI_90: 285 / 360,
142
142
  SpiceFrame.IMAP_ULTRA_45: 33 / 360,
@@ -268,7 +268,7 @@ def frame_transform_az_el(
268
268
  spherical_coords_in = np.array(
269
269
  [np.ones_like(az_el[..., 0]), az_el[..., 0], az_el[..., 1]]
270
270
  ).T
271
- from_frame_cartesian = spherical_to_cartesian(spherical_coords_in, degrees=degrees)
271
+ from_frame_cartesian = spherical_to_cartesian(spherical_coords_in)
272
272
  # Transform to to_frame
273
273
  to_frame_cartesian = frame_transform(et, from_frame_cartesian, from_frame, to_frame)
274
274
  # Convert to spherical and extract azimuth/elevation
@@ -325,7 +325,7 @@ def instrument_pointing(
325
325
  """
326
326
  Compute the instrument pointing at the specified times.
327
327
 
328
- By default, the coordinates returned are Latitude/Longitude coordinates in
328
+ By default, the coordinates returned are (Longitude, Latitude) coordinates in
329
329
  the reference frame `to_frame`. Cartesian coordinates can be returned if
330
330
  desired by setting `cartesian=True`.
331
331
 
@@ -425,14 +425,14 @@ def cartesian_to_spherical(
425
425
  - r : Distance of the point from the origin.
426
426
  - azimuth : angle in the xy-plane
427
427
  In degrees if degrees parameter is True (by default):
428
- output range=[0, 360],
428
+ output range=[0, 360) degrees,
429
429
  otherwise in radians if degrees parameter is False:
430
- output range=[0, 2*pi].
430
+ output range=[0, 2*pi) radians.
431
431
  - elevation : angle from the xy-plane
432
432
  In degrees if degrees parameter is True (by default):
433
- output range=[0, 180],
433
+ output range=[-90, 90) degrees,
434
434
  otherwise in radians if degrees parameter is False:
435
- output range=[-pi/2, pi/2].
435
+ output range=[-pi/2, pi/2) radians.
436
436
  """
437
437
  # Magnitude of the velocity vector
438
438
  magnitude_v = np.linalg.norm(v, axis=-1, keepdims=True)
@@ -457,9 +457,9 @@ def cartesian_to_spherical(
457
457
  return spherical_coords
458
458
 
459
459
 
460
- def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) -> NDArray:
460
+ def spherical_to_cartesian(spherical_coords: NDArray) -> NDArray:
461
461
  """
462
- Convert spherical coordinates to Cartesian coordinates.
462
+ Convert spherical coordinates (angles in degrees) to Cartesian coordinates.
463
463
 
464
464
  Parameters
465
465
  ----------
@@ -468,11 +468,8 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
468
468
  the spherical coordinates (r, azimuth, elevation):
469
469
 
470
470
  - r : Distance of the point from the origin.
471
- - azimuth : angle in the xy-plane in radians [0, 2*pi].
472
- - elevation : angle from the xy-plane in radians [-pi/2, pi/2].
473
- degrees : bool
474
- Set to True if input azimuth and elevation angles are in degrees.
475
- Defaults to False.
471
+ - azimuth : angle in the xy-plane in degrees. Range is [0, 360) degrees.
472
+ - elevation : angle from the xy-plane in degrees. Range is [-90, 90) degrees.
476
473
 
477
474
  Returns
478
475
  -------
@@ -483,9 +480,9 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
483
480
  azimuth = spherical_coords[..., 1]
484
481
  elevation = spherical_coords[..., 2]
485
482
 
486
- if degrees:
487
- azimuth = np.radians(azimuth)
488
- elevation = np.radians(elevation)
483
+ # Convert to radians for numpy trigonometric operations
484
+ azimuth = np.deg2rad(azimuth)
485
+ elevation = np.deg2rad(elevation)
489
486
 
490
487
  x = r * np.cos(elevation) * np.cos(azimuth)
491
488
  y = r * np.cos(elevation) * np.sin(azimuth)
@@ -496,7 +493,7 @@ def spherical_to_cartesian(spherical_coords: NDArray, degrees: bool = False) ->
496
493
  return cartesian_coords
497
494
 
498
495
 
499
- def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
496
+ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = True) -> NDArray:
500
497
  """
501
498
  Convert cartesian coordinates to latitudinal coordinates in radians.
502
499
 
@@ -511,7 +508,7 @@ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
511
508
  with x, y, z-components.
512
509
  degrees : bool
513
510
  If True, the longitude and latitude coords are returned in degrees.
514
- Defaults to False.
511
+ Defaults to True.
515
512
 
516
513
  Returns
517
514
  -------
@@ -532,7 +529,7 @@ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = False) -> NDArray:
532
529
 
533
530
  def solar_longitude(
534
531
  et: Union[np.ndarray, float],
535
- degrees: bool = False,
532
+ degrees: bool = True,
536
533
  ) -> Union[float, npt.NDArray]:
537
534
  """
538
535
  Compute the solar longitude of the Imap Spacecraft.
@@ -543,7 +540,7 @@ def solar_longitude(
543
540
  Ephemeris time(s) to at which to compute solar longitude.
544
541
  degrees : bool
545
542
  If True, the longitude is returned in degrees.
546
- Defaults to False.
543
+ Defaults to True.
547
544
 
548
545
  Returns
549
546
  -------
@@ -3,14 +3,9 @@
3
3
  import functools
4
4
  import logging
5
5
  import os
6
- from collections.abc import Generator
7
- from contextlib import contextmanager
8
- from pathlib import Path
9
6
  from typing import Any, Callable, Optional, Union, overload
10
7
 
11
- import numpy as np
12
8
  import spiceypy
13
- from numpy.typing import NDArray
14
9
  from spiceypy.utils.exceptions import SpiceyError
15
10
 
16
11
  from imap_processing import imap_module_directory
@@ -181,277 +176,6 @@ def ensure_spice(
181
176
  return _decorator
182
177
 
183
178
 
184
- @contextmanager
185
- def open_spice_ck_file(pointing_frame_path: Path) -> Generator[int, None, None]:
186
- """
187
- Context manager for handling SPICE CK files.
188
-
189
- Parameters
190
- ----------
191
- pointing_frame_path : str
192
- Path to the CK file.
193
-
194
- Yields
195
- ------
196
- handle : int
197
- Handle to the opened CK file.
198
- """
199
- # TODO: We will need to figure out if ck kernel changes
200
- # and how that will affect appending to the pointing
201
- # frame kernel.
202
- if pointing_frame_path.exists():
203
- handle = spiceypy.dafopw(str(pointing_frame_path))
204
- else:
205
- handle = spiceypy.ckopn(str(pointing_frame_path), "CK", 0)
206
- try:
207
- yield handle
208
- finally:
209
- spiceypy.ckcls(handle)
210
-
211
-
212
- @ensure_spice
213
- def create_pointing_frame(pointing_frame_path: Path, ck_path: Path) -> None:
214
- """
215
- Create the pointing frame.
216
-
217
- Parameters
218
- ----------
219
- pointing_frame_path : pathlib.Path
220
- Location of pointing frame kernel.
221
- ck_path : pathlib.Path
222
- Location of the CK kernel.
223
-
224
- Notes
225
- -----
226
- Kernels required to be furnished:
227
- "imap_science_0001.tf",
228
- "imap_sclk_0000.tsc",
229
- "imap_sim_ck_2hr_2secsampling_with_nutation.bc" or
230
- "sim_1yr_imap_attitude.bc",
231
- "imap_wkcp.tf",
232
- "naif0012.tls"
233
-
234
- Assumptions:
235
- - The MOC has removed timeframe in which nutation/procession are present.
236
- TODO: We may come back and have a check for this.
237
- - We will continue to append to the pointing frame kernel.
238
- TODO: Figure out how we want to handle the file size becoming too large.
239
- - For now we can only furnish a single ck kernel.
240
- TODO: This will not be the case once we add the ability to query the .csv.
241
-
242
- References
243
- ----------
244
- https://numpydoc.readthedocs.io/en/latest/format.html#references
245
- """
246
- # Get IDs.
247
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.gipool
248
- id_imap_dps = spiceypy.gipool("FRAME_IMAP_DPS", 0, 1)
249
- id_imap_sclk = spiceypy.gipool("CK_-43000_SCLK", 0, 1)
250
-
251
- # Verify that only ck_path kernel is loaded.
252
- count = spiceypy.ktotal("ck")
253
- loaded_ck_kernel, _, _, _ = spiceypy.kdata(count - 1, "ck")
254
-
255
- if count != 1 or str(ck_path) != loaded_ck_kernel:
256
- raise ValueError(f"Error: Expected CK kernel {ck_path}")
257
-
258
- # If the pointing frame kernel already exists, find the last time.
259
- if pointing_frame_path.exists():
260
- # Get the last time in the pointing frame kernel.
261
- pointing_cover = spiceypy.ckcov(
262
- str(pointing_frame_path), int(id_imap_dps), True, "SEGMENT", 0, "TDB"
263
- )
264
- num_segments = spiceypy.wncard(pointing_cover)
265
- _, et_end_pointing_frame = spiceypy.wnfetd(pointing_cover, num_segments - 1)
266
- else:
267
- et_end_pointing_frame = None
268
-
269
- # TODO: Query for .csv file to get the pointing start and end times.
270
- # TODO: Remove next four lines once query is added.
271
- id_imap_spacecraft = spiceypy.gipool("FRAME_IMAP_SPACECRAFT", 0, 1)
272
- ck_cover = spiceypy.ckcov(
273
- str(ck_path), int(id_imap_spacecraft), True, "INTERVAL", 0, "TDB"
274
- )
275
- num_intervals = spiceypy.wncard(ck_cover)
276
-
277
- with open_spice_ck_file(pointing_frame_path) as handle:
278
- # TODO: this will change to the number of pointings.
279
- for i in range(num_intervals):
280
- # Get the coverage window
281
- # TODO: this will change to pointing start and end time.
282
- et_start, et_end = spiceypy.wnfetd(ck_cover, i)
283
- et_times = _get_et_times(et_start, et_end)
284
-
285
- # TODO: remove after query is added.
286
- if (
287
- et_end_pointing_frame is not None
288
- and et_times[0] < et_end_pointing_frame
289
- ):
290
- break
291
-
292
- # Create a rotation matrix
293
- rotation_matrix = _create_rotation_matrix(et_times)
294
-
295
- # Convert the rotation matrix to a quaternion.
296
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.m2q
297
- q_avg = spiceypy.m2q(rotation_matrix)
298
-
299
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.sce2c
300
- # Convert start and end times to SCLK.
301
- sclk_begtim = spiceypy.sce2c(int(id_imap_sclk), et_times[0])
302
- sclk_endtim = spiceypy.sce2c(int(id_imap_sclk), et_times[-1])
303
-
304
- # Create the pointing frame kernel.
305
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.ckw02
306
- spiceypy.ckw02(
307
- # Handle of an open CK file.
308
- handle,
309
- # Start time of the segment.
310
- sclk_begtim,
311
- # End time of the segment.
312
- sclk_endtim,
313
- # Pointing frame ID.
314
- int(id_imap_dps),
315
- # Reference frame.
316
- "ECLIPJ2000", # Reference frame
317
- # Identifier.
318
- "IMAP_DPS",
319
- # Number of pointing intervals.
320
- 1,
321
- # Start times of individual pointing records within segment.
322
- # Since there is only a single record this is equal to sclk_begtim.
323
- np.array([sclk_begtim]),
324
- # End times of individual pointing records within segment.
325
- # Since there is only a single record this is equal to sclk_endtim.
326
- np.array([sclk_endtim]), # Single stop time
327
- # Average quaternion.
328
- q_avg,
329
- # 0.0 Angular rotation terms.
330
- np.array([0.0, 0.0, 0.0]),
331
- # Rates (seconds per tick) at which the quaternion and
332
- # angular velocity change.
333
- np.array([1.0]),
334
- )
335
-
336
-
337
- def _get_et_times(et_start: float, et_end: float) -> NDArray[np.float64]:
338
- """
339
- Get times for pointing start and stop.
340
-
341
- Parameters
342
- ----------
343
- et_start : float
344
- Pointing start time.
345
- et_end : float
346
- Pointing end time.
347
-
348
- Returns
349
- -------
350
- et_times : numpy.ndarray
351
- Array of times between et_start and et_end.
352
- """
353
- # TODO: Queried pointing start and stop times here.
354
- # TODO removing the @ensure_spice decorator when using the repointing table.
355
-
356
- # 1 spin/15 seconds; 10 quaternions / spin.
357
- num_samples = (et_end - et_start) / 15 * 10
358
- # There were rounding errors when using spiceypy.pxform so np.ceil and np.floor
359
- # were used to ensure the start and end times were included in the array.
360
- et_times = np.linspace(
361
- np.ceil(et_start * 1e6) / 1e6, np.floor(et_end * 1e6) / 1e6, int(num_samples)
362
- )
363
-
364
- return et_times
365
-
366
-
367
- @ensure_spice
368
- def _average_quaternions(et_times: np.ndarray) -> NDArray:
369
- """
370
- Average the quaternions.
371
-
372
- Parameters
373
- ----------
374
- et_times : numpy.ndarray
375
- Array of times between et_start and et_end.
376
-
377
- Returns
378
- -------
379
- q_avg : np.ndarray
380
- Average quaternion.
381
- """
382
- aggregate = np.zeros((4, 4))
383
- for tdb in et_times:
384
- # we use a quick and dirty method here for grabbing the quaternions
385
- # from the attitude kernel. Depending on how well the kernel input
386
- # data is built and sampled, there may or may not be aliasing with this
387
- # approach. If it turns out that we need to pull the quaternions
388
- # directly from the CK there are several routines that exist to do this
389
- # but it's not straight forward. We'll revisit this if needed.
390
-
391
- # Rotation matrix from IMAP spacecraft frame to ECLIPJ2000.
392
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.pxform
393
- body_rots = spiceypy.pxform("IMAP_SPACECRAFT", "ECLIPJ2000", tdb)
394
- # Convert rotation matrix to quaternion.
395
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.m2q
396
- body_quat = spiceypy.m2q(body_rots)
397
-
398
- # Standardize the quaternion so that they may be compared.
399
- body_quat = body_quat * np.sign(body_quat[0])
400
- # Aggregate quaternions into a single matrix.
401
- aggregate += np.outer(body_quat, body_quat)
402
-
403
- # Reference: "On Averaging Rotations".
404
- # Link: https://link.springer.com/content/pdf/10.1023/A:1011129215388.pdf
405
- aggregate /= len(et_times)
406
-
407
- # Compute eigen values and vectors of the matrix A
408
- # Eigenvalues tell you how much "influence" each
409
- # direction (eigenvector) has.
410
- # The largest eigenvalue corresponds to the direction
411
- # that has the most influence.
412
- # The eigenvector corresponding to the largest
413
- # eigenvalue points in the direction that has the most
414
- # combined rotation influence.
415
- eigvals, eigvecs = np.linalg.eig(aggregate)
416
- # q0: The scalar part of the quaternion.
417
- # q1, q2, q3: The vector part of the quaternion.
418
- q_avg = eigvecs[:, np.argmax(eigvals)]
419
-
420
- return q_avg
421
-
422
-
423
- def _create_rotation_matrix(et_times: np.ndarray) -> NDArray:
424
- """
425
- Create a rotation matrix.
426
-
427
- Parameters
428
- ----------
429
- et_times : numpy.ndarray
430
- Array of times between et_start and et_end.
431
-
432
- Returns
433
- -------
434
- rotation_matrix : np.ndarray
435
- Rotation matrix.
436
- """
437
- # Averaged quaternions.
438
- q_avg = _average_quaternions(et_times)
439
-
440
- # Converts the averaged quaternion (q_avg) into a rotation matrix
441
- # and get inertial z axis.
442
- # https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.q2m
443
- z_avg = spiceypy.q2m(list(q_avg))[:, 2]
444
- # y_avg is perpendicular to both z_avg and the standard Z-axis.
445
- y_avg = np.cross(z_avg, [0, 0, 1])
446
- # x_avg is perpendicular to y_avg and z_avg.
447
- x_avg = np.cross(y_avg, z_avg)
448
-
449
- # Construct the rotation matrix from x_avg, y_avg, z_avg
450
- rotation_matrix = np.asarray([x_avg, y_avg, z_avg])
451
-
452
- return rotation_matrix
453
-
454
-
455
179
  def furnish_time_kernel() -> None:
456
180
  """Furnish the time kernels."""
457
181
  spice_test_data_path = imap_module_directory / "tests/spice/test_data"