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,369 @@
1
+ """Mock expected data for use in some tests."""
2
+
3
+ import astropy_healpix.healpy as hp
4
+ import numpy as np
5
+ import spiceypy as spice
6
+ import xarray as xr
7
+
8
+ from imap_processing.ena_maps.utils.coordinates import CoordNames
9
+ from imap_processing.spice.kernels import ensure_spice
10
+ from imap_processing.spice.time import str_to_et
11
+ from imap_processing.ultra.l1c.ultra_l1c_pset_bins import build_energy_bins
12
+
13
+ DEFAULT_RECT_SPACING_DEG_L1C = 0.5
14
+ DEFAULT_HEALPIX_NSIDE_L1C = 128
15
+
16
+
17
+ def mock_l1c_pset_product_rectangular(
18
+ spacing_deg: float = DEFAULT_RECT_SPACING_DEG_L1C,
19
+ stripe_center_lat: int = 0,
20
+ width_scale: float = 10.0,
21
+ counts_scaling_params: tuple[int, float] = (100, 0.01),
22
+ peak_exposure: float = 1000.0,
23
+ timestr: str = "2025-01-01T00:00:00",
24
+ head: str = "45",
25
+ ) -> xr.Dataset:
26
+ """
27
+ Mock the L1C PSET product with recognizable but unrealistic counts.
28
+
29
+ This is not meant to perfectly mimic the real data, but to provide a
30
+ recognizable structure for L2 testing purposes.
31
+ Function will produce an xarray.Dataset with at least the variables and shapes:
32
+ counts: (1 epoch, num_energy_bins, num_lon_bins, num_lat_bins)
33
+ exposure_time: (num_lon_bins, num_lat_bins)
34
+ sensitivity: (1 epoch, num_energy_bins, num_lon_bins, num_lat_bins)
35
+
36
+ and the coordinate variables:
37
+ the epoch (assumed to be a single time for each product).
38
+ energy: (determined by build_energy_bins function)
39
+ longitude: (num_lon_bins)
40
+ latitude: (num_lat_bins)
41
+
42
+ While not a coordinate, PSETs can also be distinguished by the 'head' attribute.
43
+ head: Either '45' or '90'. Default is '45'.
44
+
45
+ The counts are generated along a stripe, centered at a given latitude.
46
+ This stripe can be thought of as a 'horizontal' line if the lon/az axis is plotted
47
+ as the x-axis and the lat/el axis is plotted as the y-axis. See the figure below.
48
+
49
+ ^ Elevation/Latitude
50
+ |
51
+ | 000000000000000000000000000000000000000000000000000 |
52
+ | 000000000000000000000000000000000000000000000000000 |
53
+ | 000000000000000000000000000000000000000000000000000 |
54
+ | 000000000000000000000000000000000000000000000000000 |
55
+ | 000000000000000000000000000000000000000000000000000 \
56
+ | 222222222222222222222222222222222222222222222222222 \
57
+ | 444444444444444444444444444444444444444444444444444 \
58
+ | 666666666666666666666666666666666666666666666666666 |
59
+ | 444444444444444444444444444444444444444444444444444 /
60
+ | 222222222222222222222222222222222222222222222222222 /
61
+ | 000000000000000000000000000000000000000000000000000 /
62
+ | 000000000000000000000000000000000000000000000000000 |
63
+ --------------------------------------------------------->
64
+ Azimuth/Longitude ->
65
+
66
+ Fig. 1: Example of the '90' sensor head stripe
67
+
68
+ Parameters
69
+ ----------
70
+ spacing_deg : float, optional
71
+ The bin spacing in degrees (default is 0.5 degrees).
72
+ stripe_center_lat : int, optional
73
+ The center latitude of the stripe in degrees (default is 0).
74
+ width_scale : float, optional
75
+ The width of the stripe in degrees (default is 20 degrees).
76
+ counts_scaling_params : tuple[int, float], optional
77
+ The parameters for the binomial distribution of counts (default is (100, 0.01)).
78
+ The 0th element is the number of trials to draw,
79
+ the 1st element scales the probability of success for each trial.
80
+ peak_exposure : float, optional
81
+ The peak exposure time (default is 1000.0).
82
+ timestr : str, optional
83
+ The time string for the epoch (default is "2025-01-01T00:00:00").
84
+ head : str, optional
85
+ The sensor head (either '45' or '90') (default is '45').
86
+ """
87
+ num_lat_bins = int(180 / spacing_deg)
88
+ num_lon_bins = int(360 / spacing_deg)
89
+ stripe_center_lat_bin = int((stripe_center_lat + 90) / spacing_deg)
90
+
91
+ _, energy_bin_midpoints, _ = build_energy_bins()
92
+ num_energy_bins = len(energy_bin_midpoints)
93
+
94
+ # 1 epoch x num_energy_bins x num_lon_bins x num_lat_bins
95
+ grid_shape = (1, num_energy_bins, num_lon_bins, num_lat_bins)
96
+
97
+ def get_binomial_counts(distance_scaling, lat_bin, central_lat_bin):
98
+ # Note, this is not quite correct, as it won't wrap around at 360 degrees
99
+ # but it's all meant to provide a recognizable pattern for testing
100
+ distance_lat_bin = np.abs(lat_bin - central_lat_bin)
101
+
102
+ rng = np.random.default_rng(seed=42)
103
+ return rng.binomial(
104
+ n=counts_scaling_params[0],
105
+ p=np.maximum(
106
+ 1 - (distance_lat_bin / distance_scaling), counts_scaling_params[1]
107
+ ),
108
+ )
109
+
110
+ counts = np.fromfunction(
111
+ lambda epoch, energy_bin, lon_bin, lat_bin: get_binomial_counts(
112
+ distance_scaling=width_scale,
113
+ lat_bin=lat_bin,
114
+ central_lat_bin=stripe_center_lat_bin,
115
+ ),
116
+ shape=grid_shape,
117
+ )
118
+
119
+ # exposure_time should be a gaussian distribution centered on the stripe
120
+ # with a width of 20 degrees
121
+ exposure_time = np.zeros(grid_shape[2:])
122
+ exposure_time = np.fromfunction(
123
+ lambda lon_bin, lat_bin: np.exp(
124
+ -((lat_bin - stripe_center_lat_bin) ** 2) / (2 * width_scale**2)
125
+ ),
126
+ shape=grid_shape[2:],
127
+ )
128
+ exposure_time /= exposure_time.max()
129
+ exposure_time *= peak_exposure
130
+ counts = counts.astype(int)
131
+ sensitivity = np.ones(grid_shape)
132
+
133
+ # Determine the epoch, which is TT time in nanoseconds since J2000 epoch
134
+ tdb_et = str_to_et(timestr)
135
+ tt_j2000ns = (
136
+ ensure_spice(spice.unitim, time_kernels_only=True)(tdb_et, "ET", "TT") * 1e9
137
+ )
138
+
139
+ logical_source = f"imap_ultra_l1c_{head}sensor-spacecraftpset"
140
+ logical_file_id = (
141
+ f"{logical_source}_{timestr[:4]}{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
142
+ )
143
+
144
+ pset_product = xr.Dataset(
145
+ {
146
+ "counts": (
147
+ [
148
+ CoordNames.TIME.value,
149
+ CoordNames.ENERGY_ULTRA.value,
150
+ CoordNames.AZIMUTH_L1C.value,
151
+ CoordNames.ELEVATION_L1C.value,
152
+ ],
153
+ counts,
154
+ ),
155
+ "exposure_factor": (
156
+ [
157
+ CoordNames.TIME.value,
158
+ CoordNames.AZIMUTH_L1C.value,
159
+ CoordNames.ELEVATION_L1C.value,
160
+ ],
161
+ np.expand_dims(exposure_time, axis=0),
162
+ ),
163
+ "sensitivity": (
164
+ [
165
+ CoordNames.TIME.value,
166
+ CoordNames.ENERGY_ULTRA.value,
167
+ CoordNames.AZIMUTH_L1C.value,
168
+ CoordNames.ELEVATION_L1C.value,
169
+ ],
170
+ sensitivity,
171
+ ),
172
+ },
173
+ coords={
174
+ CoordNames.TIME.value: [
175
+ tt_j2000ns,
176
+ ],
177
+ CoordNames.ENERGY_ULTRA.value: energy_bin_midpoints,
178
+ CoordNames.AZIMUTH_L1C.value: np.arange(
179
+ 0 + spacing_deg / 2, 360, spacing_deg
180
+ ),
181
+ CoordNames.ELEVATION_L1C.value: np.arange(
182
+ -90 + spacing_deg / 2, 90, spacing_deg
183
+ ),
184
+ },
185
+ attrs={
186
+ "Logical_file_id": logical_file_id,
187
+ "Logical_source": logical_source,
188
+ "Data_version": "001",
189
+ },
190
+ )
191
+
192
+ return pset_product
193
+
194
+
195
+ def mock_l1c_pset_product_healpix(
196
+ nside: int = DEFAULT_HEALPIX_NSIDE_L1C,
197
+ stripe_center_lat: int = 0,
198
+ width_scale: float = 10.0,
199
+ counts_scaling_params: tuple[int, float] = (100, 0.01),
200
+ peak_exposure: float = 1000.0,
201
+ timestr: str = "2025-01-01T00:00:00",
202
+ head: str = "45",
203
+ ) -> xr.Dataset:
204
+ """
205
+ Mock the L1C PSET product with recognizable but unrealistic counts.
206
+
207
+ See the docstring for mock_l1c_pset_product_rectangular for more details about
208
+ the structure of the dataset.
209
+ The rectangular and Healpix mocked datasets are very similar in structure, though
210
+ the actual values at a given latitude and longitude may be different. This is only
211
+ meant to provide a recognizable structure for L2 testing purposes.
212
+
213
+ The counts are generated along a stripe, centered at a given latitude.
214
+ This stripe can be thought of as a 'vertical' line if the lon/az axis is plotted
215
+ as the x-axis and the lat/el axis is plotted as the y-axis. See the figure below.
216
+
217
+ ^ Elevation/Latitude
218
+ |
219
+ | 00000000000000000000 |
220
+ | 0000000000000000000000000000 |
221
+ | 0000000000000000000000000000000000000 |
222
+ | 0000000000000000000000000000000000000000000 |
223
+ | 00000000000000000000000000000000000000000000000 |
224
+ | 0000000000000000000000000000000000000000000000000 \
225
+ | 222222222222222222222222222222222222222222222222222 \
226
+ | 444444444444444444444444444444444444444444444444444 \
227
+ | 666666666666666666666666666666666666666666666666666 |
228
+ | 4444444444444444444444444444444444444444444444444 /
229
+ | 22222222222222222222222222222222222222222222222 /
230
+ | 0000000000000000000000000000000000000000000 /
231
+ | 0000000000000000000000000000000000000 |
232
+ | 0000000000000000000000000000 |
233
+ | 00000000000000000000 |
234
+ --------------------------------------------------------->
235
+ Azimuth/Longitude ->
236
+
237
+ Fig. 1: Example of the '90' sensor head stripe on a HEALPix grid
238
+
239
+ Parameters
240
+ ----------
241
+ nside : int, optional
242
+ The HEALPix nside parameter (default is 128).
243
+ stripe_center_lat : int, optional
244
+ The center latitude of the stripe in degrees (default is 0).
245
+ width_scale : float, optional
246
+ The width of the stripe in degrees (default is 10 degrees).
247
+ counts_scaling_params : tuple[int, float], optional
248
+ The parameters for the binomial distribution of counts (default is (100, 0.01)).
249
+ The 0th element is the number of trials to draw,
250
+ the 1st element scales the probability of success for each trial.
251
+ peak_exposure : float, optional
252
+ The peak exposure time (default is 1000.0).
253
+ timestr : str, optional
254
+ The time string for the epoch (default is "2025-01-01T00:00:00").
255
+ head : str, optional
256
+ The sensor head (either '45' or '90') (default is '45').
257
+ """
258
+ energy_intervals, energy_bin_midpoints, _ = build_energy_bins()
259
+ energy_bin_delta = np.diff(energy_intervals, axis=1).squeeze()
260
+ num_energy_bins = len(energy_bin_midpoints)
261
+ npix = hp.nside2npix(nside)
262
+ counts = np.zeros(npix)
263
+ exposure_time = np.zeros(npix)
264
+
265
+ # Get latitude for each healpix pixel
266
+ pix_indices = np.arange(npix)
267
+ lon_pix, lat_pix = hp.pix2ang(nside, pix_indices, lonlat=True)
268
+
269
+ counts = np.zeros(shape=(num_energy_bins, npix))
270
+
271
+ # Calculate probability based on distance from target latitude
272
+ lat_diff = np.abs(lat_pix - stripe_center_lat)
273
+ prob_scaling_factor = counts_scaling_params[1] * np.exp(
274
+ -(lat_diff**2) / (2 * width_scale**2)
275
+ )
276
+ # Generate counts using binomial distribution
277
+ rng = np.random.default_rng(seed=42)
278
+ counts = np.array(
279
+ [
280
+ rng.binomial(n=counts_scaling_params[0], p=prob_scaling_factor)
281
+ for _ in range(num_energy_bins)
282
+ ]
283
+ )
284
+
285
+ # Generate exposure times using gaussian distribution, but wider
286
+ prob_scaling_factor_exptime = counts_scaling_params[1] * np.exp(
287
+ -(lat_diff**2) / (2 * (3 * width_scale) ** 2)
288
+ )
289
+ exposure_time = peak_exposure * (
290
+ prob_scaling_factor_exptime / prob_scaling_factor_exptime.max()
291
+ )
292
+
293
+ # Ensure counts are integers
294
+ counts = counts.astype(int)
295
+ # add an epoch dimension
296
+ counts = np.expand_dims(counts, axis=0)
297
+ sensitivity = np.ones_like(counts)
298
+
299
+ # Determine the epoch, which is TT time in nanoseconds since J2000 epoch
300
+ tdb_et = str_to_et(timestr)
301
+ tt_j2000ns = (
302
+ ensure_spice(spice.unitim, time_kernels_only=True)(tdb_et, "ET", "TT") * 1e9
303
+ )
304
+
305
+ logical_source = f"imap_ultra_l1c_{head}sensor-spacecraftpset"
306
+ logical_file_id = (
307
+ f"{logical_source}_{timestr[:4]}{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
308
+ )
309
+
310
+ pset_product = xr.Dataset(
311
+ {
312
+ "counts": (
313
+ [
314
+ CoordNames.TIME.value,
315
+ CoordNames.ENERGY_ULTRA.value,
316
+ CoordNames.HEALPIX_INDEX.value,
317
+ ],
318
+ counts,
319
+ ),
320
+ "background_rates": (
321
+ [
322
+ CoordNames.TIME.value,
323
+ CoordNames.ENERGY_ULTRA.value,
324
+ CoordNames.HEALPIX_INDEX.value,
325
+ ],
326
+ np.full_like(counts, 0.05, dtype=float),
327
+ ),
328
+ "exposure_factor": (
329
+ [CoordNames.HEALPIX_INDEX.value],
330
+ exposure_time,
331
+ ),
332
+ "sensitivity": (
333
+ [
334
+ CoordNames.TIME.value,
335
+ CoordNames.ENERGY_ULTRA.value,
336
+ CoordNames.HEALPIX_INDEX.value,
337
+ ],
338
+ sensitivity,
339
+ ),
340
+ CoordNames.AZIMUTH_L1C.value: (
341
+ [CoordNames.HEALPIX_INDEX.value],
342
+ lon_pix,
343
+ ),
344
+ CoordNames.ELEVATION_L1C.value: (
345
+ [CoordNames.HEALPIX_INDEX.value],
346
+ lat_pix,
347
+ ),
348
+ "energy_bin_delta": (
349
+ [CoordNames.ENERGY_ULTRA.value],
350
+ energy_bin_delta,
351
+ ),
352
+ },
353
+ coords={
354
+ CoordNames.TIME.value: [
355
+ tt_j2000ns,
356
+ ],
357
+ CoordNames.ENERGY_ULTRA.value: xr.DataArray(
358
+ energy_bin_midpoints, dims=(CoordNames.ENERGY_ULTRA.value,)
359
+ ),
360
+ CoordNames.HEALPIX_INDEX.value: pix_indices,
361
+ },
362
+ attrs={
363
+ "Logical_file_id": logical_file_id,
364
+ "Logical_source": logical_source,
365
+ "Data_version": "v001",
366
+ },
367
+ )
368
+
369
+ return pset_product