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
@@ -6,9 +6,7 @@ import xarray as xr
6
6
  from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
7
7
 
8
8
 
9
- def calculate_histogram(
10
- histogram_dataset: xr.Dataset, name: str, data_version: str
11
- ) -> xr.Dataset:
9
+ def calculate_histogram(histogram_dataset: xr.Dataset, name: str) -> xr.Dataset:
12
10
  """
13
11
  Create dictionary with defined datatype for Histogram Data.
14
12
 
@@ -18,8 +16,6 @@ def calculate_histogram(
18
16
  Dataset containing histogram data.
19
17
  name : str
20
18
  Name of dataset.
21
- data_version : str
22
- Version of the data.
23
19
 
24
20
  Returns
25
21
  -------
@@ -35,6 +31,6 @@ def calculate_histogram(
35
31
  histogram_dict["epoch"] = epoch
36
32
  histogram_dict["sid"] = np.zeros(len(epoch), dtype=np.uint8)
37
33
 
38
- dataset = create_dataset(histogram_dict, name, "l1c", data_version)
34
+ dataset = create_dataset(histogram_dict, name, "l1c")
39
35
 
40
36
  return dataset
@@ -0,0 +1,84 @@
1
+ """Calculate Pointing Set Grids."""
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import xarray as xr
6
+
7
+ from imap_processing import imap_module_directory
8
+ from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
9
+ build_energy_bins,
10
+ get_background_rates,
11
+ get_spacecraft_exposure_times,
12
+ get_spacecraft_histogram,
13
+ )
14
+ from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
15
+
16
+ # TODO: This is a placeholder for the API lookup table directory.
17
+ TEST_PATH = imap_module_directory / "tests" / "ultra" / "data" / "l1"
18
+
19
+
20
+ def calculate_spacecraft_pset(
21
+ de_dataset: xr.Dataset,
22
+ extendedspin_dataset: xr.Dataset,
23
+ cullingmask_dataset: xr.Dataset,
24
+ name: str,
25
+ ) -> xr.Dataset:
26
+ """
27
+ Create dictionary with defined datatype for Pointing Set Grid Data.
28
+
29
+ Parameters
30
+ ----------
31
+ de_dataset : xarray.Dataset
32
+ Dataset containing de data.
33
+ extendedspin_dataset : xarray.Dataset
34
+ Dataset containing extendedspin data.
35
+ cullingmask_dataset : xarray.Dataset
36
+ Dataset containing cullingmask data.
37
+ name : str
38
+ Name of the dataset.
39
+
40
+ Returns
41
+ -------
42
+ dataset : xarray.Dataset
43
+ Dataset containing the data.
44
+ """
45
+ pset_dict: dict[str, np.ndarray] = {}
46
+
47
+ v_mag_dps_spacecraft = np.linalg.norm(de_dataset["velocity_dps_sc"].values, axis=1)
48
+ vhat_dps_spacecraft = (
49
+ de_dataset["velocity_dps_sc"].values / v_mag_dps_spacecraft[:, np.newaxis]
50
+ )
51
+
52
+ intervals, _, energy_bin_geometric_means = build_energy_bins()
53
+ counts, latitude, longitude, n_pix = get_spacecraft_histogram(
54
+ vhat_dps_spacecraft,
55
+ de_dataset["energy_spacecraft"].values,
56
+ intervals,
57
+ nside=128,
58
+ )
59
+ healpix = np.arange(n_pix)
60
+
61
+ # calculate background rates
62
+ background_rates = get_background_rates()
63
+
64
+ # TODO: calculate sensitivity and interpolate based on energy.
65
+
66
+ # Calculate exposure
67
+ constant_exposure = TEST_PATH / "ultra_90_dps_exposure.csv"
68
+ df_exposure = pd.read_csv(constant_exposure)
69
+ exposure_pointing = get_spacecraft_exposure_times(df_exposure)
70
+
71
+ # For ISTP, epoch should be the center of the time bin.
72
+ pset_dict["epoch"] = de_dataset.epoch.data[0].astype(np.int64)
73
+ pset_dict["counts"] = counts
74
+ pset_dict["latitude"] = latitude
75
+ pset_dict["longitude"] = longitude
76
+ pset_dict["energy_bin_geometric_mean"] = energy_bin_geometric_means
77
+ pset_dict["background_rates"] = background_rates
78
+ pset_dict["exposure_factor"] = exposure_pointing
79
+ pset_dict["healpix"] = healpix
80
+ pset_dict["energy_bin_delta"] = np.diff(intervals, axis=1).squeeze()
81
+
82
+ dataset = create_dataset(pset_dict, name, "l1c")
83
+
84
+ return dataset
@@ -3,10 +3,10 @@
3
3
  import xarray as xr
4
4
 
5
5
  from imap_processing.ultra.l1c.histogram import calculate_histogram
6
- from imap_processing.ultra.l1c.pset import calculate_pset
6
+ from imap_processing.ultra.l1c.spacecraft_pset import calculate_spacecraft_pset
7
7
 
8
8
 
9
- def ultra_l1c(data_dict: dict, data_version: str) -> list[xr.Dataset]:
9
+ def ultra_l1c(data_dict: dict) -> list[xr.Dataset]:
10
10
  """
11
11
  Will process ULTRA L1A and L1B data into L1C CDF files at output_filepath.
12
12
 
@@ -14,8 +14,6 @@ def ultra_l1c(data_dict: dict, data_version: str) -> list[xr.Dataset]:
14
14
  ----------
15
15
  data_dict : dict
16
16
  The data itself and its dependent data.
17
- data_version : str
18
- Version of the data product being created.
19
17
 
20
18
  Returns
21
19
  -------
@@ -31,7 +29,6 @@ def ultra_l1c(data_dict: dict, data_version: str) -> list[xr.Dataset]:
31
29
  histogram_dataset = calculate_histogram(
32
30
  data_dict[f"imap_ultra_l1a_{instrument_id}sensor-histogram"],
33
31
  f"imap_ultra_l1c_{instrument_id}sensor-histogram",
34
- data_version,
35
32
  )
36
33
  output_datasets = [histogram_dataset]
37
34
  elif (
@@ -39,12 +36,14 @@ def ultra_l1c(data_dict: dict, data_version: str) -> list[xr.Dataset]:
39
36
  and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
40
37
  and f"imap_ultra_l1b_{instrument_id}sensor-extendedspin" in data_dict
41
38
  ):
42
- pset_dataset = calculate_pset(
39
+ spacecraft_pset = calculate_spacecraft_pset(
43
40
  data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
44
- f"imap_ultra_l1c_{instrument_id}sensor-pset",
45
- data_version,
41
+ data_dict[f"imap_ultra_l1b_{instrument_id}sensor-extendedspin"],
42
+ data_dict[f"imap_ultra_l1b_{instrument_id}sensor-cullingmask"],
43
+ f"imap_ultra_l1c_{instrument_id}sensor-spacecraftpset",
46
44
  )
47
- output_datasets = [pset_dataset]
45
+ # TODO: add calculate_helio_pset here
46
+ output_datasets = [spacecraft_pset]
48
47
  else:
49
48
  raise ValueError("Data dictionary does not contain the expected keys.")
50
49
 
@@ -1,24 +1,23 @@
1
1
  """Module to create pointing sets."""
2
2
 
3
- from pathlib import Path
4
-
5
- import cdflib
3
+ import astropy_healpix.healpy as hp
6
4
  import numpy as np
5
+ import pandas
6
+ import pandas as pd
7
7
  from numpy.typing import NDArray
8
+ from scipy.interpolate import interp1d
8
9
 
9
- from imap_processing.ena_maps.utils.spatial_utils import build_spatial_bins
10
10
  from imap_processing.spice.geometry import (
11
11
  SpiceFrame,
12
12
  cartesian_to_spherical,
13
13
  imap_state,
14
- spherical_to_cartesian,
15
14
  )
16
15
  from imap_processing.ultra.constants import UltraConstants
17
16
 
18
17
  # TODO: add species binning.
19
18
 
20
19
 
21
- def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray]:
20
+ def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray, np.ndarray]:
22
21
  """
23
22
  Build energy bin boundaries.
24
23
 
@@ -28,6 +27,8 @@ def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray]:
28
27
  Energy bins.
29
28
  energy_midpoints : np.ndarray
30
29
  Array of energy bin midpoints.
30
+ energy_bin_geometric_means : np.ndarray
31
+ Array of geometric means of energy bins.
31
32
  """
32
33
  # Calculate energy step
33
34
  energy_step = (1 + UltraConstants.ALPHA / 2) / (1 - UltraConstants.ALPHA / 2)
@@ -44,19 +45,20 @@ def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray]:
44
45
  (float(energy_bin_edges[i]), float(energy_bin_edges[i + 1]))
45
46
  for i in range(len(energy_bin_edges) - 1)
46
47
  ]
48
+ energy_bin_geometric_means = np.sqrt(energy_bin_edges[:-1] * energy_bin_edges[1:])
47
49
 
48
- return intervals, energy_midpoints
50
+ return intervals, energy_midpoints, energy_bin_geometric_means
49
51
 
50
52
 
51
- def get_histogram(
53
+ def get_spacecraft_histogram(
52
54
  vhat: tuple[np.ndarray, np.ndarray, np.ndarray],
53
55
  energy: np.ndarray,
54
- az_bin_edges: np.ndarray,
55
- el_bin_edges: np.ndarray,
56
56
  energy_bin_edges: list[tuple[float, float]],
57
- ) -> NDArray:
57
+ nside: int = 128,
58
+ nested: bool = False,
59
+ ) -> tuple[NDArray, NDArray, NDArray, NDArray]:
58
60
  """
59
- Compute a 3D histogram of the particle data.
61
+ Compute a 3D histogram of the particle data using HEALPix binning.
60
62
 
61
63
  Parameters
62
64
  ----------
@@ -64,123 +66,165 @@ def get_histogram(
64
66
  The x,y,z-components of the unit velocity vector.
65
67
  energy : np.ndarray
66
68
  The particle energy.
67
- az_bin_edges : np.ndarray
68
- Array of azimuth bin boundary values.
69
- el_bin_edges : np.ndarray
70
- Array of elevation bin boundary values.
71
69
  energy_bin_edges : list[tuple[float, float]]
72
70
  Array of energy bin edges.
71
+ nside : int, optional
72
+ The nside parameter of the Healpix tessellation.
73
+ Default is 128.
74
+ nested : bool, optional
75
+ Whether the Healpix tessellation is nested. Default is False.
73
76
 
74
77
  Returns
75
78
  -------
76
79
  hist : np.ndarray
77
- A 3D histogram array.
80
+ A 3D histogram array with shape (n_pix, n_energy_bins).
81
+ latitude : np.ndarray
82
+ Array of latitude values.
83
+ longitude : np.ndarray
84
+ Array of longitude values.
85
+ n_pix : int
86
+ Number of healpix pixels.
78
87
 
79
88
  Notes
80
89
  -----
81
- The histogram will now work properly for overlapping energy bins, i.e.
90
+ The histogram will work properly for overlapping energy bins, i.e.
82
91
  the same energy value can fall into multiple bins if the intervals overlap.
92
+
93
+ azimuthal angle [0, 360], elevation angle [-90, 90]
83
94
  """
84
- spherical_coords = cartesian_to_spherical(vhat)
95
+ # vhat = direction in which particle is traveling
96
+ # Make negative to see where it came from
97
+ spherical_coords = cartesian_to_spherical(-np.array(vhat), degrees=True)
85
98
  az, el = (
86
99
  spherical_coords[..., 1],
87
100
  spherical_coords[..., 2],
88
101
  )
89
102
 
90
- # Initialize histogram
91
- hist_total = np.zeros(
92
- (len(az_bin_edges) - 1, len(el_bin_edges) - 1, len(energy_bin_edges))
93
- )
103
+ # Compute number of HEALPix pixels that cover the sphere
104
+ n_pix = hp.nside2npix(nside)
105
+
106
+ # Calculate the corresponding longitude (az) latitude (el)
107
+ # center coordinates
108
+ longitude, latitude = hp.pix2ang(nside, np.arange(n_pix), lonlat=True)
109
+
110
+ # Get HEALPix pixel indices for each event
111
+ # HEALPix expects latitude in [-90, 90] so we don't need to change elevation
112
+ hpix_idx = hp.ang2pix(nside, az, el, nest=nested, lonlat=True)
113
+
114
+ # Initialize histogram: (n_energy_bins, n_HEALPix pixels)
115
+ hist = np.zeros((len(energy_bin_edges), n_pix))
94
116
 
117
+ # Bin data in energy & HEALPix space
95
118
  for i, (e_min, e_max) in enumerate(energy_bin_edges):
96
- # Filter data for current energy bin.
97
119
  mask = (energy >= e_min) & (energy < e_max)
98
- hist, _ = np.histogramdd(
99
- sample=(az[mask], el[mask], energy[mask]),
100
- bins=[az_bin_edges, el_bin_edges, [e_min, e_max]],
101
- )
102
- # Assign 2D histogram to current energy bin.
103
- hist_total[:, :, i] = hist[:, :, 0]
120
+ # Only count the events that fall within the energy bin
121
+ hist[i, :] += np.bincount(hpix_idx[mask], minlength=n_pix).astype(np.float64)
104
122
 
105
- return hist_total
123
+ return hist, latitude, longitude, n_pix
106
124
 
107
125
 
108
- def get_pointing_frame_exposure_times(
109
- constant_exposure: Path, n_spins: int, sensor: str
126
+ def get_background_rates(
127
+ nside: int = 128,
110
128
  ) -> NDArray:
111
129
  """
112
- Compute a 2D array of the exposure.
130
+ Calculate background rates.
113
131
 
114
132
  Parameters
115
133
  ----------
116
- constant_exposure : Path
117
- Path to file containing constant exposure data.
118
- n_spins : int
119
- Number of spins per pointing.
120
- sensor : str
121
- Sensor (45 or 90).
134
+ nside : int, optional
135
+ The nside parameter of the Healpix tessellation (default is 128).
122
136
 
123
137
  Returns
124
138
  -------
125
- exposure : np.ndarray
126
- A 2D array with dimensions (az, el).
139
+ background_rates : np.ndarray
140
+ Array of background rates.
141
+
142
+ Notes
143
+ -----
144
+ This is a placeholder.
127
145
  """
128
- with cdflib.CDF(constant_exposure) as cdf_file:
129
- exposure = cdf_file.varget(f"dps_grid{sensor}") * n_spins
146
+ n_pix = hp.nside2npix(nside)
147
+ return np.zeros(n_pix)
130
148
 
131
- return exposure
149
+
150
+ def get_spacecraft_exposure_times(constant_exposure: pandas.DataFrame) -> NDArray:
151
+ """
152
+ Compute exposure times for HEALPix pixels.
153
+
154
+ Parameters
155
+ ----------
156
+ constant_exposure : pandas.DataFrame
157
+ Exposure data.
158
+
159
+ Returns
160
+ -------
161
+ exposure_pointing : np.ndarray
162
+ Total exposure times of pixels in a
163
+ Healpix tessellation of the sky
164
+ in the pointing (dps) frame.
165
+ """
166
+ # TODO: use the universal spin table and
167
+ # universal pointing table here to determine actual number of spins
168
+ exposure_pointing = (
169
+ constant_exposure["Exposure Time"] * 5760
170
+ ) # 5760 spins per pointing (for now)
171
+
172
+ return exposure_pointing
132
173
 
133
174
 
134
175
  def get_helio_exposure_times(
135
176
  time: np.ndarray,
136
- sc_exposure: np.ndarray,
177
+ df_exposure: pd.DataFrame,
178
+ nside: int = 128,
179
+ nested: bool = False,
137
180
  ) -> NDArray:
138
181
  """
139
- Compute a 3D array of the exposure in the helio frame.
182
+ Compute a 2D (Healpix index, energy) array of exposure in the helio frame.
140
183
 
141
184
  Parameters
142
185
  ----------
143
186
  time : np.ndarray
144
- Median time of pointing in J2000 seconds.
145
- sc_exposure : np.ndarray
146
- Spacecraft exposure.
187
+ Median time of pointing in et.
188
+ df_exposure : pd.DataFrame
189
+ Spacecraft exposure in healpix coordinates.
190
+ nside : int, optional
191
+ The nside parameter of the Healpix tessellation (default is 128).
192
+ nested : bool, optional
193
+ Whether the Healpix tessellation is nested (default is False).
147
194
 
148
195
  Returns
149
196
  -------
150
- exposure_3d : np.ndarray
151
- A 3D array with dimensions (az, el, energy).
197
+ helio_exposure : np.ndarray
198
+ A 2D array of shape (npix, n_energy_bins).
152
199
 
153
200
  Notes
154
201
  -----
155
202
  These calculations are performed once per pointing.
156
203
  """
157
- # Get bins and midpoints, and convert from radians to degrees.
158
- _, energy_midpoints = build_energy_bins()
159
- az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
160
- np.rad2deg(angle_radians) for angle_radians in (build_spatial_bins())
161
- )
162
-
163
- # Initialize the exposure grid.
164
- exposure_3d = np.zeros(
165
- (len(el_bin_midpoints), len(az_bin_midpoints), len(energy_midpoints))
166
- )
167
-
168
- # Create a 3D Cartesian grid from spherical coordinates
169
- # using azimuth and elevation midpoints.
170
- az_grid, el_grid = np.meshgrid(az_bin_midpoints, el_bin_midpoints[::-1])
171
-
172
- # Radial distance.
173
- r = np.ones(el_grid.shape)
174
- spherical_coords = np.stack((r, np.radians(az_grid), np.radians(el_grid)), axis=-1)
175
- cartesian_coords = spherical_to_cartesian(spherical_coords)
176
- cartesian = cartesian_coords.reshape(-1, 3, order="F").T
177
-
178
- # Spacecraft velocity in the pointing (DPS) frame wrt heliosphere.
204
+ # Get energy midpoints.
205
+ _, energy_midpoints, _ = build_energy_bins()
206
+ # Extract (RA/Dec) and exposure from the spacecraft frame.
207
+ ra = df_exposure["Right Ascension (deg)"].values
208
+ dec = df_exposure["Declination (deg)"].values
209
+ exposure_flat = df_exposure["Exposure Time"].values
210
+
211
+ # The Cartesian state vector representing the position and velocity of the
212
+ # IMAP spacecraft.
179
213
  state = imap_state(time, ref_frame=SpiceFrame.IMAP_DPS)
180
214
 
181
215
  # Extract the velocity part of the state vector
182
216
  spacecraft_velocity = state[3:6]
217
+ # Convert (RA, Dec) angles into 3D unit vectors.
218
+ # Each unit vector represents a direction in the sky where the spacecraft observed
219
+ # and accumulated exposure time.
220
+ unit_dirs = hp.ang2vec(ra, dec, lonlat=True).T # Shape (N, 3)
221
+
222
+ # Initialize output array.
223
+ # Each row corresponds to a HEALPix pixel, and each column to an energy bin.
224
+ npix = hp.nside2npix(nside)
225
+ helio_exposure = np.zeros((npix, len(energy_midpoints)))
183
226
 
227
+ # Loop through energy bins and compute transformed exposure.
184
228
  for i, energy_midpoint in enumerate(energy_midpoints):
185
229
  # Convert the midpoint energy to a velocity (km/s).
186
230
  # Based on kinetic energy equation: E = 1/2 * m * v^2.
@@ -193,56 +237,110 @@ def get_helio_exposure_times(
193
237
  # to the velocity wrt heliosphere.
194
238
  # energy_velocity * cartesian -> apply the magnitude of the velocity
195
239
  # to every position on the grid in the despun grid.
196
- helio_velocity = spacecraft_velocity.reshape(3, 1) + energy_velocity * cartesian
240
+ helio_velocity = spacecraft_velocity.reshape(1, 3) + energy_velocity * unit_dirs
197
241
 
198
242
  # Normalized vectors representing the direction of the heliocentric velocity.
199
- helio_normalized = helio_velocity.T / np.linalg.norm(
200
- helio_velocity.T, axis=1, keepdims=True
243
+ helio_normalized = helio_velocity / np.linalg.norm(
244
+ helio_velocity, axis=1, keepdims=True
245
+ )
246
+
247
+ # Convert Cartesian heliocentric vectors into spherical coordinates.
248
+ # Result: azimuth (longitude) and elevation (latitude) in degrees.
249
+ helio_spherical = cartesian_to_spherical(helio_normalized)
250
+ az, el = helio_spherical[:, 1], helio_spherical[:, 2]
251
+
252
+ # Convert azimuth/elevation directions to HEALPix pixel indices.
253
+ hpix_idx = hp.ang2pix(nside, az, el, nest=nested, lonlat=True)
254
+
255
+ # Accumulate exposure values into HEALPix pixels for this energy bin.
256
+ helio_exposure[:, i] = np.bincount(
257
+ hpix_idx, weights=exposure_flat, minlength=npix
201
258
  )
202
- # Converts vectors from Cartesian coordinates (x, y, z)
203
- # into spherical coordinates.
204
- spherical_coords = cartesian_to_spherical(helio_normalized)
205
- az, el = spherical_coords[..., 1], spherical_coords[..., 2]
206
259
 
207
- # Assign values from sc_exposure directly to bins.
208
- az_idx = np.digitize(az, az_bin_edges) - 1
209
- el_idx = np.digitize(el, el_bin_edges[::-1]) - 1
260
+ return helio_exposure
261
+
262
+
263
+ def get_spacecraft_sensitivity(
264
+ efficiencies: pandas.DataFrame,
265
+ geometric_function: pandas.DataFrame,
266
+ ) -> tuple[pandas.DataFrame, NDArray, NDArray, NDArray]:
267
+ """
268
+ Compute sensitivity as efficiency * geometric factor.
269
+
270
+ Parameters
271
+ ----------
272
+ efficiencies : pandas.DataFrame
273
+ Efficiencies at different energy levels.
274
+ geometric_function : pandas.DataFrame
275
+ Geometric function.
276
+
277
+ Returns
278
+ -------
279
+ pointing_sensitivity : pandas.DataFrame
280
+ Sensitivity with dimensions (HEALPIX pixel_number, energy).
281
+ energy_vals : NDArray
282
+ Energy values of dataframe.
283
+ right_ascension : NDArray
284
+ Right ascension (longitude/azimuth) values of dataframe (0 - 360 degrees).
285
+ declination : NDArray
286
+ Declination (latitude/elevation) values of dataframe (-90 to 90 degrees).
287
+ """
288
+ # Exclude "Right Ascension (deg)" and "Declination (deg)" from the multiplication
289
+ energy_columns = [
290
+ col
291
+ for col in efficiencies.columns
292
+ if col not in ["Right Ascension (deg)", "Declination (deg)"]
293
+ ]
294
+ sensitivity = efficiencies[energy_columns].mul(
295
+ geometric_function["Response (cm2-sr)"].values, axis=0
296
+ )
210
297
 
211
- # Ensure az_idx and el_idx are within bounds.
212
- az_idx = np.clip(az_idx, 0, len(az_bin_edges) - 2)
213
- el_idx = np.clip(el_idx, 0, len(el_bin_edges) - 2)
298
+ right_ascension = efficiencies["Right Ascension (deg)"]
299
+ declination = efficiencies["Declination (deg)"]
214
300
 
215
- # A 1D array of linear indices used to track the bin_id.
216
- idx = el_idx + az_idx * az_grid.shape[0]
217
- # Bins the transposed sc_exposure array.
218
- binned_exposure = sc_exposure.T.flatten(order="F")[idx]
219
- # Reshape the binned exposure.
220
- exposure_3d[:, :, i] = binned_exposure.reshape(az_grid.shape, order="F")
301
+ energy_vals = np.array([float(col.replace("keV", "")) for col in energy_columns])
221
302
 
222
- return exposure_3d
303
+ return sensitivity, energy_vals, right_ascension, declination
223
304
 
224
305
 
225
- def get_pointing_frame_sensitivity(
226
- constant_sensitivity: Path, n_spins: int, sensor: str
306
+ def grid_sensitivity(
307
+ efficiencies: pandas.DataFrame,
308
+ geometric_function: pandas.DataFrame,
309
+ energy: float,
227
310
  ) -> NDArray:
228
311
  """
229
- Compute a 3D array of the sensitivity.
312
+ Grid the sensitivity.
230
313
 
231
314
  Parameters
232
315
  ----------
233
- constant_sensitivity : Path
234
- Path to file containing constant sensitivity data.
235
- n_spins : int
236
- Number of spins per pointing.
237
- sensor : str
238
- Sensor (45 or 90).
316
+ efficiencies : pandas.DataFrame
317
+ Efficiencies at different energy levels.
318
+ geometric_function : pandas.DataFrame
319
+ Geometric function.
320
+ energy : np.ndarray
321
+ The particle energy.
322
+ energy : float
323
+ Energy to which we are interpolating.
239
324
 
240
325
  Returns
241
326
  -------
242
- sensitivity : np.ndarray
243
- A 3D array with dimensions (az, el, energy).
327
+ interpolated_sensitivity : np.ndarray
328
+ Sensitivity with dimensions (HEALPIX pixel_number, 1).
244
329
  """
245
- with cdflib.CDF(constant_sensitivity) as cdf_file:
246
- sensitivity = cdf_file.varget(f"dps_sensitivity{sensor}") * n_spins
330
+ sensitivity, energy_vals, right_ascension, declination = get_spacecraft_sensitivity(
331
+ efficiencies, geometric_function
332
+ )
333
+
334
+ # Create interpolator over energy dimension for each pixel (axis=1)
335
+ interp_func = interp1d(
336
+ energy_vals,
337
+ sensitivity.values,
338
+ axis=1,
339
+ bounds_error=False,
340
+ fill_value=np.nan,
341
+ )
342
+
343
+ # Interpolate to energy
344
+ interpolated = interp_func(energy)
247
345
 
248
- return sensitivity
346
+ return interpolated