imap-processing 0.11.0__py3-none-any.whl → 0.12.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 (288) hide show
  1. imap_processing/__init__.py +10 -11
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/excel_to_xtce.py +65 -16
  4. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -28
  5. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +365 -42
  6. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
  7. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
  8. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
  9. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +26 -13
  10. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
  11. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
  12. imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
  13. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +6 -9
  14. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +1 -1
  15. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
  16. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
  17. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +9 -21
  18. imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
  19. imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
  20. imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
  21. imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
  22. imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
  23. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
  24. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
  25. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
  26. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +48 -52
  27. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
  28. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +2 -14
  29. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +51 -2
  30. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +29 -14
  31. imap_processing/cdf/utils.py +13 -7
  32. imap_processing/cli.py +23 -8
  33. imap_processing/codice/codice_l1a.py +207 -85
  34. imap_processing/codice/constants.py +1322 -568
  35. imap_processing/codice/decompress.py +2 -6
  36. imap_processing/ena_maps/ena_maps.py +480 -116
  37. imap_processing/ena_maps/utils/coordinates.py +19 -0
  38. imap_processing/ena_maps/utils/map_utils.py +14 -17
  39. imap_processing/ena_maps/utils/spatial_utils.py +45 -47
  40. imap_processing/hi/l1a/hi_l1a.py +24 -18
  41. imap_processing/hi/l1a/histogram.py +0 -1
  42. imap_processing/hi/l1a/science_direct_event.py +6 -8
  43. imap_processing/hi/l1b/hi_l1b.py +31 -39
  44. imap_processing/hi/l1c/hi_l1c.py +405 -17
  45. imap_processing/hi/utils.py +58 -12
  46. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
  47. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
  48. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
  49. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
  50. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
  51. imap_processing/hit/hit_utils.py +173 -1
  52. imap_processing/hit/l0/constants.py +20 -11
  53. imap_processing/hit/l0/decom_hit.py +18 -4
  54. imap_processing/hit/l1a/hit_l1a.py +45 -54
  55. imap_processing/hit/l1b/constants.py +317 -0
  56. imap_processing/hit/l1b/hit_l1b.py +367 -18
  57. imap_processing/hit/l2/constants.py +281 -0
  58. imap_processing/hit/l2/hit_l2.py +614 -0
  59. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
  60. imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
  61. imap_processing/ialirt/l0/parse_mag.py +246 -0
  62. imap_processing/ialirt/l0/process_swe.py +252 -0
  63. imap_processing/ialirt/packet_definitions/ialirt.xml +7 -3
  64. imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
  65. imap_processing/ialirt/utils/grouping.py +114 -0
  66. imap_processing/ialirt/utils/time.py +29 -0
  67. imap_processing/idex/atomic_masses.csv +22 -0
  68. imap_processing/idex/decode.py +2 -2
  69. imap_processing/idex/idex_constants.py +25 -0
  70. imap_processing/idex/idex_l1a.py +6 -7
  71. imap_processing/idex/idex_l1b.py +4 -31
  72. imap_processing/idex/idex_l2a.py +789 -0
  73. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +39 -33
  74. imap_processing/lo/l0/lo_science.py +6 -0
  75. imap_processing/lo/l1a/lo_l1a.py +0 -1
  76. imap_processing/lo/l1b/lo_l1b.py +177 -25
  77. imap_processing/mag/constants.py +8 -0
  78. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +6 -0
  79. imap_processing/mag/l0/decom_mag.py +10 -3
  80. imap_processing/mag/l1a/mag_l1a.py +22 -11
  81. imap_processing/mag/l1a/mag_l1a_data.py +28 -3
  82. imap_processing/mag/l1b/mag_l1b.py +190 -48
  83. imap_processing/mag/l1c/interpolation_methods.py +211 -0
  84. imap_processing/mag/l1c/mag_l1c.py +447 -9
  85. imap_processing/quality_flags.py +1 -0
  86. imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
  87. imap_processing/spacecraft/quaternions.py +123 -0
  88. imap_processing/spice/geometry.py +16 -19
  89. imap_processing/spice/repoint.py +120 -0
  90. imap_processing/swapi/l1/swapi_l1.py +4 -0
  91. imap_processing/swapi/l2/swapi_l2.py +0 -1
  92. imap_processing/swe/l1a/swe_l1a.py +47 -8
  93. imap_processing/swe/l1a/swe_science.py +5 -2
  94. imap_processing/swe/l1b/swe_l1b_science.py +103 -56
  95. imap_processing/swe/l2/swe_l2.py +60 -65
  96. imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
  97. imap_processing/swe/utils/swe_constants.py +63 -0
  98. imap_processing/swe/utils/swe_utils.py +85 -28
  99. imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
  100. imap_processing/tests/ccsds/test_excel_to_xtce.py +23 -20
  101. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
  102. imap_processing/tests/codice/conftest.py +1 -1
  103. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  104. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  105. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
  106. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
  107. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  108. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
  109. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
  110. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  111. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  112. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  113. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  114. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  115. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  116. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  117. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  118. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  119. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  120. imap_processing/tests/codice/test_codice_l1a.py +110 -46
  121. imap_processing/tests/codice/test_decompress.py +4 -4
  122. imap_processing/tests/conftest.py +166 -10
  123. imap_processing/tests/ena_maps/conftest.py +51 -0
  124. imap_processing/tests/ena_maps/test_ena_maps.py +638 -109
  125. imap_processing/tests/ena_maps/test_map_utils.py +66 -43
  126. imap_processing/tests/ena_maps/test_spatial_utils.py +16 -20
  127. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
  128. imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
  129. imap_processing/tests/hi/test_hi_l1b.py +12 -15
  130. imap_processing/tests/hi/test_hi_l1c.py +234 -6
  131. imap_processing/tests/hi/test_l1a.py +30 -0
  132. imap_processing/tests/hi/test_science_direct_event.py +1 -1
  133. imap_processing/tests/hi/test_utils.py +24 -2
  134. imap_processing/tests/hit/helpers/l1_validation.py +39 -39
  135. imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
  136. imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
  137. imap_processing/tests/hit/test_decom_hit.py +4 -0
  138. imap_processing/tests/hit/test_hit_l1a.py +24 -28
  139. imap_processing/tests/hit/test_hit_l1b.py +304 -40
  140. imap_processing/tests/hit/test_hit_l2.py +454 -0
  141. imap_processing/tests/hit/test_hit_utils.py +112 -2
  142. imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
  143. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
  144. imap_processing/tests/ialirt/test_data/l0/461971383-404.bin +0 -0
  145. imap_processing/tests/ialirt/test_data/l0/461971384-405.bin +0 -0
  146. imap_processing/tests/ialirt/test_data/l0/461971385-406.bin +0 -0
  147. imap_processing/tests/ialirt/test_data/l0/461971386-407.bin +0 -0
  148. imap_processing/tests/ialirt/test_data/l0/461971387-408.bin +0 -0
  149. imap_processing/tests/ialirt/test_data/l0/461971388-409.bin +0 -0
  150. imap_processing/tests/ialirt/test_data/l0/461971389-410.bin +0 -0
  151. imap_processing/tests/ialirt/test_data/l0/461971390-411.bin +0 -0
  152. imap_processing/tests/ialirt/test_data/l0/461971391-412.bin +0 -0
  153. imap_processing/tests/ialirt/test_data/l0/sample_decoded_i-alirt_data.csv +383 -0
  154. imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
  155. imap_processing/tests/ialirt/unit/test_parse_mag.py +168 -0
  156. imap_processing/tests/ialirt/unit/test_process_swe.py +208 -3
  157. imap_processing/tests/ialirt/unit/test_time.py +16 -0
  158. imap_processing/tests/idex/conftest.py +62 -6
  159. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
  160. imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
  161. imap_processing/tests/idex/test_idex_l1a.py +48 -4
  162. imap_processing/tests/idex/test_idex_l1b.py +3 -3
  163. imap_processing/tests/idex/test_idex_l2a.py +383 -0
  164. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
  165. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
  166. imap_processing/tests/lo/test_lo_l1b.py +148 -4
  167. imap_processing/tests/lo/test_lo_science.py +1 -0
  168. imap_processing/tests/mag/conftest.py +69 -0
  169. imap_processing/tests/mag/test_mag_decom.py +1 -1
  170. imap_processing/tests/mag/test_mag_l1a.py +38 -0
  171. imap_processing/tests/mag/test_mag_l1b.py +34 -53
  172. imap_processing/tests/mag/test_mag_l1c.py +251 -20
  173. imap_processing/tests/mag/test_mag_validation.py +109 -25
  174. imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
  175. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
  176. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
  177. imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
  178. imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  179. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
  180. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
  181. imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
  182. imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
  183. imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
  184. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
  185. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
  186. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
  187. imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
  188. imap_processing/tests/mag/validation/imap_calibration_mag_20240229_v01.cdf +0 -0
  189. imap_processing/tests/spacecraft/__init__.py +0 -0
  190. imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
  191. imap_processing/tests/spacecraft/test_quaternions.py +71 -0
  192. imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
  193. imap_processing/tests/spice/test_geometry.py +6 -9
  194. imap_processing/tests/spice/test_repoint.py +111 -0
  195. imap_processing/tests/swapi/test_swapi_l1.py +7 -3
  196. imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
  197. imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
  198. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
  199. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
  200. imap_processing/tests/swe/test_swe_l1a.py +18 -0
  201. imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
  202. imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
  203. imap_processing/tests/swe/test_swe_l1b_science.py +23 -4
  204. imap_processing/tests/swe/test_swe_l2.py +112 -30
  205. imap_processing/tests/test_cli.py +2 -2
  206. imap_processing/tests/test_utils.py +138 -16
  207. imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
  208. imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
  209. 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
  210. imap_processing/tests/ultra/data/mock_data.py +341 -0
  211. imap_processing/tests/ultra/unit/conftest.py +69 -26
  212. imap_processing/tests/ultra/unit/test_badtimes.py +2 -0
  213. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -0
  214. imap_processing/tests/ultra/unit/test_de.py +12 -4
  215. imap_processing/tests/ultra/unit/test_decom_apid_881.py +44 -0
  216. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +78 -0
  217. imap_processing/tests/ultra/unit/test_ultra_l1a.py +28 -12
  218. imap_processing/tests/ultra/unit/test_ultra_l1b.py +34 -6
  219. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +22 -26
  220. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -51
  221. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +94 -52
  222. imap_processing/ultra/l0/decom_tools.py +6 -5
  223. imap_processing/ultra/l1a/ultra_l1a.py +28 -56
  224. imap_processing/ultra/l1b/de.py +72 -28
  225. imap_processing/ultra/l1b/extendedspin.py +12 -14
  226. imap_processing/ultra/l1b/ultra_l1b.py +34 -9
  227. imap_processing/ultra/l1b/ultra_l1b_culling.py +65 -29
  228. imap_processing/ultra/l1b/ultra_l1b_extended.py +64 -19
  229. imap_processing/ultra/l1c/spacecraft_pset.py +86 -0
  230. imap_processing/ultra/l1c/ultra_l1c.py +7 -4
  231. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +112 -61
  232. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  233. imap_processing/ultra/utils/ultra_l1_utils.py +20 -2
  234. imap_processing/utils.py +68 -28
  235. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/METADATA +8 -5
  236. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/RECORD +250 -199
  237. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
  238. imap_processing/hi/l1a/housekeeping.py +0 -27
  239. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  240. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  241. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  242. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  243. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  244. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  245. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  246. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  247. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  248. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  249. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  250. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  251. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  252. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  253. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  254. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  255. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  256. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  257. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  258. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  259. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  260. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  261. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  262. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  263. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  264. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  265. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  266. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  267. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  268. imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
  269. imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
  270. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
  271. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  272. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  273. imap_processing/tests/ultra/test_data/mock_data.py +0 -161
  274. imap_processing/ultra/l1c/pset.py +0 -40
  275. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  276. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  277. /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  278. /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  279. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  280. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
  281. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
  282. /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
  283. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
  284. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
  285. /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
  286. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/LICENSE +0 -0
  287. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/WHEEL +0 -0
  288. {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,9 @@
1
1
  "Tests pointing sets"
2
2
 
3
+ import astropy_healpix.healpy as hp
3
4
  import cdflib
4
5
  import numpy as np
6
+ import pandas as pd
5
7
  import pytest
6
8
  from cdflib import CDF
7
9
 
@@ -9,13 +11,15 @@ from imap_processing import imap_module_directory
9
11
  from imap_processing.ena_maps.utils.spatial_utils import build_spatial_bins
10
12
  from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
11
13
  build_energy_bins,
14
+ get_background_rates,
12
15
  get_helio_exposure_times,
13
- get_histogram,
14
- get_pointing_frame_exposure_times,
15
- get_pointing_frame_sensitivity,
16
+ get_spacecraft_exposure_times,
17
+ get_spacecraft_histogram,
18
+ get_spacecraft_sensitivity,
16
19
  )
17
20
 
18
21
  BASE_PATH = imap_module_directory / "ultra" / "lookup_tables"
22
+ TEST_PATH = imap_module_directory / "tests" / "ultra" / "data" / "l1"
19
23
 
20
24
 
21
25
  @pytest.fixture()
@@ -24,7 +28,7 @@ def test_data():
24
28
  vx_sc = np.array([-186.5575, 508.5697, 508.5697, 508.5697])
25
29
  vy_sc = np.array([-707.5707, -516.0282, -516.0282, -516.0282])
26
30
  vz_sc = np.array([618.0569, 892.6931, 892.6931, 892.6931])
27
- energy = np.array([3.384, 3.385, 200, 200])
31
+ energy = np.array([3.384, 3.385, 4.138, 4.138])
28
32
  v = np.column_stack((vx_sc, vy_sc, vz_sc))
29
33
 
30
34
  return v, energy
@@ -32,13 +36,13 @@ def test_data():
32
36
 
33
37
  def test_build_energy_bins():
34
38
  """Tests build_energy_bins function."""
35
- energy_bin_edges, energy_midpoints = build_energy_bins()
36
- energy_bin_start = [interval[0] for interval in energy_bin_edges]
37
- energy_bin_end = [interval[1] for interval in energy_bin_edges]
39
+ intervals, energy_midpoints, energy_bin_geometric_means = build_energy_bins()
40
+ energy_bin_start = [interval[0] for interval in intervals]
41
+ energy_bin_end = [interval[1] for interval in intervals]
38
42
 
39
43
  assert energy_bin_start[0] == 0
40
44
  assert energy_bin_start[1] == 3.385
41
- assert len(energy_bin_edges) == 24
45
+ assert len(intervals) == 24
42
46
  assert energy_midpoints[0] == (energy_bin_start[0] + energy_bin_end[0]) / 2
43
47
 
44
48
  # Comparison to expected values.
@@ -46,42 +50,67 @@ def test_build_energy_bins():
46
50
  np.testing.assert_allclose(energy_bin_start[-1], 279.810, atol=1e-4)
47
51
  np.testing.assert_allclose(energy_bin_end[-1], 341.989, atol=1e-4)
48
52
 
53
+ expected_geometric_means = np.sqrt(
54
+ np.array(energy_bin_start) * np.array(energy_bin_end)
55
+ )
56
+ np.testing.assert_allclose(
57
+ energy_bin_geometric_means, expected_geometric_means, atol=1e-4
58
+ )
59
+
49
60
 
50
- def test_get_histogram(test_data):
61
+ def test_get_spacecraft_histogram(test_data):
51
62
  """Tests get_histogram function."""
52
63
  v, energy = test_data
53
64
 
54
- az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
55
- np.rad2deg(angle_radians) for angle_radians in (build_spatial_bins())
56
- )
57
- energy_bin_edges, _ = build_energy_bins()
58
-
59
- hist = get_histogram(v, energy, az_bin_edges, el_bin_edges, energy_bin_edges)
65
+ energy_bin_edges, _, _ = build_energy_bins()
66
+ subset_energy_bin_edges = energy_bin_edges[:3]
60
67
 
61
- assert hist.shape == (
62
- len(az_bin_edges) - 1,
63
- len(el_bin_edges) - 1,
64
- len(energy_bin_edges),
68
+ hist, latitude, longitude, n_pix = get_spacecraft_histogram(
69
+ v, energy, subset_energy_bin_edges, nside=1
65
70
  )
66
-
67
-
68
- def test_get_pointing_frame_exposure_times():
69
- """Tests get_pointing_frame_exposure_times function."""
70
-
71
- constant_exposure = BASE_PATH / "dps_grid45_compressed.cdf"
72
- spins_per_pointing = 5760
73
- exposure = get_pointing_frame_exposure_times(
74
- constant_exposure, spins_per_pointing, "45"
71
+ assert hist.shape == (len(subset_energy_bin_edges), hp.nside2npix(1))
72
+ assert n_pix == hp.nside2npix(1)
73
+ assert latitude.shape == (n_pix,)
74
+ assert longitude.shape == (n_pix,)
75
+
76
+ # Spot check that 2 counts are in the third energy bin
77
+ assert np.sum(hist[2, :]) == 2
78
+
79
+ # Test overlapping energy bins
80
+ overlapping_bins = [
81
+ (0.0, 3.385),
82
+ (2.5, 4.137),
83
+ (3.385, 5.057),
84
+ ]
85
+ hist, latitude, longitude, n_pix = get_spacecraft_histogram(
86
+ v, energy, overlapping_bins, nside=1
75
87
  )
76
-
77
- assert exposure.shape == (720, 360)
78
- # Assert that the exposure time at the highest azimuth is
79
- # 15s x spins per pointing.
80
- assert np.array_equal(
81
- exposure[:, 359], np.full_like(exposure[:, 359], spins_per_pointing * 15)
88
+ # Spot check that 3 counts are in the third energy bin
89
+ assert np.sum(hist[2, :]) == 3
90
+ assert n_pix == hp.nside2npix(1)
91
+ assert latitude.shape == (n_pix,)
92
+ assert longitude.shape == (n_pix,)
93
+
94
+
95
+ def test_get_background_rates():
96
+ """Tests get_background_rates function."""
97
+ background_rates = get_background_rates(nside=128)
98
+ assert background_rates.shape == hp.nside2npix(128)
99
+
100
+
101
+ @pytest.mark.external_test_data()
102
+ def test_get_spacecraft_exposure_times():
103
+ """Test get_spacecraft_exposure_times function."""
104
+ constant_exposure = TEST_PATH / "ultra_90_dps_exposure.csv"
105
+ df_exposure = pd.read_csv(constant_exposure)
106
+ exposure_pointing = get_spacecraft_exposure_times(df_exposure)
107
+ assert exposure_pointing.shape == (196608,)
108
+
109
+ np.testing.assert_allclose(
110
+ exposure_pointing.values[22684:22686],
111
+ np.array([1.035, 1.035]) * 5760,
112
+ atol=1e-6,
82
113
  )
83
- # Assert that the exposure time at the lowest azimuth is 0 (no exposure).
84
- assert np.array_equal(exposure[:, 0], np.full_like(exposure[:, 359], 0.0))
85
114
 
86
115
 
87
116
  @pytest.mark.external_kernel()
@@ -99,9 +128,9 @@ def test_get_helio_exposure_times():
99
128
 
100
129
  exposure_3d = get_helio_exposure_times(mid_time, sc_exposure)
101
130
 
102
- energy_bin_edges, energy_midpoints = build_energy_bins()
131
+ energy_bin_edges, energy_midpoints, _ = build_energy_bins()
103
132
  az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
104
- np.rad2deg(angle_radians) for angle_radians in (build_spatial_bins())
133
+ build_spatial_bins()
105
134
  )
106
135
 
107
136
  assert exposure_3d.shape == (
@@ -116,7 +145,7 @@ def test_get_helio_exposure_times():
116
145
  ("dps_exposure_helio_45_E24.cdf", "dps_exposure_helio_45_E24"),
117
146
  ]
118
147
 
119
- cdf_directory = imap_module_directory / "tests" / "ultra" / "test_data" / "l1"
148
+ cdf_directory = imap_module_directory / "tests" / "ultra" / "data" / "l1"
120
149
 
121
150
  exposures = []
122
151
 
@@ -132,21 +161,34 @@ def test_get_helio_exposure_times():
132
161
  assert np.array_equal(np.squeeze(exposures[2]), exposure_3d[:, :, 23])
133
162
 
134
163
 
135
- def test_get_pointing_frame_sensitivity():
136
- """Tests get_pointing_frame_sensitivity function."""
164
+ @pytest.mark.external_test_data()
165
+ def test_get_spacecraft_sensitivity():
166
+ """Tests get_spacecraft_sensitivity function."""
167
+ # TODO: remove below here with lookup table aux api
168
+ efficiences = TEST_PATH / "Ultra_90_DPS_efficiencies_all.csv"
169
+ geometric_function = TEST_PATH / "ultra_90_dps_gf.csv"
170
+
171
+ df_efficiencies = pd.read_csv(efficiences)
172
+ df_geometric_function = pd.read_csv(geometric_function)
173
+
174
+ sensitivity = get_spacecraft_sensitivity(df_efficiencies, df_geometric_function)
175
+
176
+ assert sensitivity.shape == df_efficiencies.shape
137
177
 
138
- # TODO: energy bins need to be modified from N=90 to N=24.
139
- constant_sensitivity = BASE_PATH / "dps_sensitivity45.cdf"
140
- spins_per_pointing = 5760
141
- sensitivity = get_pointing_frame_sensitivity(
142
- constant_sensitivity,
143
- spins_per_pointing,
144
- "45",
178
+ df_efficiencies_test = pd.DataFrame(
179
+ {"3.0keV": [1.0, 2.0], "3.5keV": [3.0, 4.0], "4.0keV": [5.0, 6.0]}
145
180
  )
146
181
 
147
- assert sensitivity.shape == (90, 720, 360)
182
+ df_geometric_function_test = pd.DataFrame({"Response": [0.1, 0.2]})
148
183
 
149
- with cdflib.CDF(constant_sensitivity) as cdf_file:
150
- expected_sensitivity = cdf_file.varget("dps_sensitivity45") * spins_per_pointing
184
+ df_sensitivity_test = df_efficiencies_test.mul(
185
+ df_geometric_function_test["Response"], axis=0
186
+ )
187
+
188
+ expected_sensitivity = pd.DataFrame(
189
+ {"3.0keV": [0.1, 0.4], "3.5keV": [0.3, 0.8], "4.0keV": [0.5, 1.2]}
190
+ )
151
191
 
152
- assert np.array_equal(sensitivity, expected_sensitivity)
192
+ assert np.allclose(
193
+ df_sensitivity_test.to_numpy(), expected_sensitivity.to_numpy(), atol=1e-6
194
+ )
@@ -130,14 +130,15 @@ def decompress_binary(
130
130
  current_position = 0
131
131
  decompressed_values: list = []
132
132
 
133
- while current_position < len(binary):
133
+ while current_position < len(binary) and len(decompressed_values) < array_length:
134
134
  # Read the width of the block
135
135
  width, current_position = read_and_advance(binary, width_bit, current_position)
136
- # If width is 0 or None, we don't have enough bits left
137
- if width is None or len(decompressed_values) >= array_length:
138
- break
136
+ # If width is 0, add 'block' number of zeroes and continue
137
+ if width == 0:
138
+ decompressed_values.extend([0] * block)
139
+ continue
139
140
 
140
- # For each block, read 16 values of the given width
141
+ # For each block, read 'block' values of the given width
141
142
  for _ in range(block):
142
143
  # Ensure there are enough bits left to read the width
143
144
  if len(binary) - current_position < width:
@@ -44,7 +44,7 @@ def initiate_data_arrays(decom_ultra: dict, apid: int) -> xr.Dataset:
44
44
  index = ULTRA_EVENTS.apid.index(apid)
45
45
  logical_source = ULTRA_EVENTS.logical_source[index]
46
46
  addition_to_logical_desc = ULTRA_EVENTS.addition_to_logical_desc
47
- raw_time = decom_ultra["EVENTTIMES"]
47
+ raw_time = decom_ultra["SHCOARSE"]
48
48
  elif apid in ULTRA_TOF.apid:
49
49
  index = ULTRA_TOF.apid.index(apid)
50
50
  logical_source = ULTRA_TOF.logical_source[index]
@@ -120,59 +120,43 @@ def initiate_data_arrays(decom_ultra: dict, apid: int) -> xr.Dataset:
120
120
  return dataset
121
121
 
122
122
 
123
- def get_event_time(decom_ultra_dict: dict) -> dict:
123
+ def get_event_id(decom_ultra_dict: dict) -> dict:
124
124
  """
125
- Get event times using data from events and aux packets.
125
+ Get unique event IDs using data from events packets.
126
126
 
127
127
  Parameters
128
128
  ----------
129
129
  decom_ultra_dict : dict
130
- Events and aux data.
130
+ Events data.
131
131
 
132
132
  Returns
133
133
  -------
134
134
  decom_events : dict
135
- Ultra events data with calculated events timestamps.
136
-
137
- Notes
138
- -----
139
- Equation for event time:
140
- t = t_(spin start) + t_(spin start sub)/1000 +
141
- t_(spin duration)/1000 * phase_angle/720
135
+ Ultra events data with calculated unique event IDs as 64-bit integers.
142
136
  """
143
- event_times, durations, spin_starts = ([] for _ in range(3))
144
- decom_aux = decom_ultra_dict[ULTRA_AUX.apid[0]]
145
137
  decom_events: dict = decom_ultra_dict[ULTRA_EVENTS.apid[0]]
146
138
 
147
- timespinstart_array = np.array(decom_aux["TIMESPINSTART"])
148
- timespinstartsub_array = np.array(decom_aux["TIMESPINSTARTSUB"]) / 1000
149
-
150
- # spin start according to aux data
151
- aux_spin_starts = timespinstart_array + timespinstartsub_array
152
-
153
- for time in np.unique(decom_events["SHCOARSE"]):
154
- # Get the nearest spin start and duration prior to the event
155
- spin_start = aux_spin_starts[aux_spin_starts <= time][-1]
156
- duration = np.array(decom_aux["DURATION"])[aux_spin_starts <= time][-1]
139
+ event_ids = []
140
+ packet_counters = {}
157
141
 
158
- # Find the events
159
- event_indices = np.where(np.array(decom_events["SHCOARSE"]) == time)
160
-
161
- for event_index in event_indices[0]:
162
- phase_angle = decom_events["PHASE_ANGLE"][event_index]
163
-
164
- durations.append(duration)
165
- spin_starts.append(spin_start)
142
+ for met in decom_events["SHCOARSE"]:
143
+ # Initialize the counter for a new packet (MET value)
144
+ if met not in packet_counters:
145
+ packet_counters[met] = 0
146
+ else:
147
+ packet_counters[met] += 1
166
148
 
167
- # If there were no events, the time is set to 'SHCOARSE'
168
- if decom_events["COUNT"][event_index] == 0:
169
- event_times.append(decom_events["SHCOARSE"][event_index])
170
- else:
171
- event_times.append(spin_start + (duration / 1000) * (phase_angle / 720))
149
+ # Left shift SHCOARSE (u32) by 31 bits, to make room for our event counters
150
+ # (31 rather than 32 to keep it positive in the int64 representation)
151
+ # Append the current number of events in this packet to the right-most bits
152
+ # This makes each event a unique value including the MET and event number
153
+ # in the packet
154
+ # NOTE: CDF does not allow for uint64 values,
155
+ # so we use int64 representation here
156
+ event_id = (np.int64(met) << np.int64(31)) | np.int64(packet_counters[met])
157
+ event_ids.append(event_id)
172
158
 
173
- decom_events["DURATION"] = durations
174
- decom_events["TIMESPINSTART"] = spin_starts
175
- decom_events["EVENTTIMES"] = event_times
159
+ decom_events["EVENTID"] = event_ids
176
160
 
177
161
  return decom_events
178
162
 
@@ -194,7 +178,7 @@ def create_dataset(decom_ultra_dict: dict) -> xr.Dataset:
194
178
  # Combine events and aux datasets so we can have proper event timestamps
195
179
  if ULTRA_EVENTS.apid[0] in decom_ultra_dict.keys():
196
180
  apid = ULTRA_EVENTS.apid[0]
197
- decom_ultra = get_event_time(decom_ultra_dict)
181
+ decom_ultra = get_event_id(decom_ultra_dict)
198
182
  else:
199
183
  apid = next(iter(decom_ultra_dict.keys()))
200
184
  decom_ultra = decom_ultra_dict[apid]
@@ -286,31 +270,19 @@ def ultra_l1a(
286
270
  output_datasets = []
287
271
 
288
272
  # This is used for two purposes currently:
289
- # 1. For testing purposes to only generate a dataset for a single apid.
273
+ # For testing purposes to only generate a dataset for a single apid.
290
274
  # Each test dataset is only for a single apid while the rest of the apids
291
275
  # contain zeros. Ideally we would have
292
276
  # test data for all apids and remove this parameter.
293
- # 2. When we are generating the l1a dataset for the events packet since
294
- # right now we need to combine the events and aux packets to get the
295
- # correct event timestamps (get_event_time). This part will change
296
- # when we begin using the spin table in the database instead of the aux packet.
297
277
  if apid is not None:
298
278
  apids = [apid]
299
279
  else:
300
280
  apids = list(grouped_data.keys())
301
281
 
302
282
  for apid in apids:
303
- if apid == ULTRA_EVENTS.apid[0]:
304
- decom_ultra_dict = {
305
- apid: process_ultra_apids(grouped_data[apid], apid),
306
- ULTRA_AUX.apid[0]: process_ultra_apids(
307
- grouped_data[ULTRA_AUX.apid[0]], ULTRA_AUX.apid[0]
308
- ),
309
- }
310
- else:
311
- decom_ultra_dict = {
312
- apid: process_ultra_apids(grouped_data[apid], apid),
313
- }
283
+ decom_ultra_dict = {
284
+ apid: process_ultra_apids(grouped_data[apid], apid),
285
+ }
314
286
  dataset = create_dataset(decom_ultra_dict)
315
287
  # TODO: move this to use ImapCdfAttributes().add_global_attribute()
316
288
  dataset.attrs["Data_version"] = data_version
@@ -13,15 +13,16 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
13
13
  determine_species,
14
14
  get_coincidence_positions,
15
15
  get_ctof,
16
- get_de_az_el,
17
16
  get_de_energy_kev,
18
17
  get_de_velocity,
19
18
  get_energy_pulse_height,
20
19
  get_energy_ssd,
20
+ get_eventtimes,
21
21
  get_front_x_position,
22
22
  get_front_y_position,
23
23
  get_path_length,
24
24
  get_ph_tof_and_back_positions,
25
+ get_phi_theta,
25
26
  get_ssd_back_position_and_tof_offset,
26
27
  get_ssd_tof,
27
28
  )
@@ -49,18 +50,52 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
49
50
  de_dict = {}
50
51
  sensor = parse_filename_like(name)["sensor"][0:2]
51
52
 
52
- # Drop events with invalid start type.
53
- de_dataset = de_dataset.where(
54
- de_dataset["START_TYPE"] != np.iinfo(np.int64).min, drop=True
53
+ # Define epoch and spin.
54
+ de_dict["epoch"] = de_dataset["epoch"].data
55
+ de_dict["spin"] = de_dataset["SPIN"].data
56
+
57
+ # Add already populated fields.
58
+ keys = [
59
+ "coincidence_type",
60
+ "start_type",
61
+ "event_type",
62
+ "de_event_met",
63
+ "phase_angle",
64
+ "spin",
65
+ ]
66
+ dataset_keys = [
67
+ "COIN_TYPE",
68
+ "START_TYPE",
69
+ "STOP_TYPE",
70
+ "SHCOARSE",
71
+ "PHASE_ANGLE",
72
+ "SPIN",
73
+ ]
74
+
75
+ de_dict.update(
76
+ {key: de_dataset[dataset_key] for key, dataset_key in zip(keys, dataset_keys)}
55
77
  )
56
78
 
79
+ valid_mask = de_dataset["START_TYPE"].data != np.iinfo(np.int64).min
80
+ ph_mask = np.isin(
81
+ de_dataset["STOP_TYPE"].data, [StopType.Top.value, StopType.Bottom.value]
82
+ )
83
+ ssd_mask = np.isin(de_dataset["STOP_TYPE"].data, [StopType.SSD.value])
84
+
85
+ valid_indices = np.nonzero(valid_mask)[0]
86
+ ph_indices = np.nonzero(valid_mask & ph_mask)[0]
87
+ ssd_indices = np.nonzero(valid_mask & ssd_mask)[0]
88
+
57
89
  # Instantiate arrays
90
+ xf = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
58
91
  yf = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
59
92
  xb = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
60
93
  yb = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
61
94
  xc = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
62
95
  d = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float64)
63
96
  r = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
97
+ phi = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
98
+ theta = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
64
99
  tof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
65
100
  etof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
66
101
  ctof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
@@ -68,19 +103,25 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
68
103
  energy = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
69
104
  species_bin = np.full(len(de_dataset["epoch"]), "UNKNOWN", dtype="U10")
70
105
  t2 = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
106
+ event_times = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float64)
107
+ spin_starts = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float64)
108
+ spin_period_sec = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float64)
71
109
 
72
- # Define epoch.
73
- de_dict["epoch"] = de_dataset["epoch"].data
110
+ xf[valid_indices] = get_front_x_position(
111
+ de_dataset["START_TYPE"].data[valid_indices],
112
+ de_dataset["START_POS_TDC"].data[valid_indices],
113
+ )
74
114
 
75
- xf = get_front_x_position(
76
- de_dataset["START_TYPE"].data,
77
- de_dataset["START_POS_TDC"].data,
115
+ (
116
+ event_times[valid_indices],
117
+ spin_starts[valid_indices],
118
+ spin_period_sec[valid_indices],
119
+ ) = get_eventtimes(
120
+ de_dataset["SPIN"].data[valid_indices],
121
+ de_dataset["PHASE_ANGLE"].data[valid_indices],
78
122
  )
79
123
 
80
124
  # Pulse height
81
- ph_indices = np.nonzero(
82
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
83
- )[0]
84
125
  tof[ph_indices], t2[ph_indices], xb[ph_indices], yb[ph_indices] = (
85
126
  get_ph_tof_and_back_positions(de_dataset, xf, f"ultra{sensor}")
86
127
  )
@@ -98,6 +139,11 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
98
139
  (xb[ph_indices], yb[ph_indices]),
99
140
  d[ph_indices],
100
141
  )
142
+ phi[ph_indices], theta[ph_indices] = get_phi_theta(
143
+ (xf[ph_indices], yf[ph_indices]),
144
+ (xb[ph_indices], yb[ph_indices]),
145
+ d[ph_indices],
146
+ )
101
147
  species_bin[ph_indices] = determine_species(tof[ph_indices], r[ph_indices], "PH")
102
148
  etof[ph_indices], xc[ph_indices] = get_coincidence_positions(
103
149
  de_dataset.isel(epoch=ph_indices), t2[ph_indices], f"ultra{sensor}"
@@ -107,7 +153,6 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
107
153
  )
108
154
 
109
155
  # SSD
110
- ssd_indices = np.nonzero(np.isin(de_dataset["STOP_TYPE"], StopType.SSD.value))[0]
111
156
  tof[ssd_indices] = get_ssd_tof(de_dataset, xf)
112
157
  yb[ssd_indices], _, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
113
158
  xc[ssd_indices] = np.zeros(len(ssd_indices))
@@ -122,6 +167,11 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
122
167
  (xb[ssd_indices], yb[ssd_indices]),
123
168
  d[ssd_indices],
124
169
  )
170
+ phi[ssd_indices], theta[ssd_indices] = get_phi_theta(
171
+ (xf[ssd_indices], yf[ssd_indices]),
172
+ (xb[ssd_indices], yb[ssd_indices]),
173
+ d[ssd_indices],
174
+ )
125
175
  species_bin[ssd_indices] = determine_species(
126
176
  tof[ssd_indices], r[ssd_indices], "SSD"
127
177
  )
@@ -131,6 +181,9 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
131
181
 
132
182
  # Combine ph_yb and ssd_yb along with their indices
133
183
  de_dict["x_front"] = xf.astype(np.float32)
184
+ de_dict["event_times"] = event_times
185
+ de_dict["spin_starts"] = spin_starts
186
+ de_dict["spin_period"] = spin_period_sec
134
187
  de_dict["y_front"] = yf
135
188
  de_dict["x_back"] = xb
136
189
  de_dict["y_back"] = yb
@@ -141,19 +194,8 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
141
194
  de_dict["velocity_magnitude"] = magnitude_v
142
195
  de_dict["front_back_distance"] = d
143
196
  de_dict["path_length"] = r
144
-
145
- keys = [
146
- "coincidence_type",
147
- "start_type",
148
- "event_type",
149
- "de_event_met",
150
- "event_times",
151
- ]
152
- dataset_keys = ["COIN_TYPE", "START_TYPE", "STOP_TYPE", "SHCOARSE", "EVENTTIMES"]
153
-
154
- de_dict.update(
155
- {key: de_dataset[dataset_key] for key, dataset_key in zip(keys, dataset_keys)}
156
- )
197
+ de_dict["phi"] = phi
198
+ de_dict["theta"] = theta
157
199
 
158
200
  v = get_de_velocity(
159
201
  (de_dict["x_front"], de_dict["y_front"]),
@@ -164,14 +206,13 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
164
206
  de_dict["direct_event_velocity"] = v.astype(np.float32)
165
207
 
166
208
  de_dict["tof_energy"] = get_de_energy_kev(v, species_bin)
167
- de_dict["azimuth"], de_dict["elevation"] = get_de_az_el(v)
168
209
  de_dict["energy"] = energy
169
210
  de_dict["species"] = species_bin
170
211
 
171
212
  # Annotated Events.
172
213
  ultra_frame = getattr(SpiceFrame, f"IMAP_ULTRA_{sensor}")
173
214
  sc_velocity, sc_dps_velocity, helio_velocity = get_annotated_particle_velocity(
174
- de_dataset.data_vars["EVENTTIMES"].values,
215
+ event_times,
175
216
  de_dict["direct_event_velocity"],
176
217
  ultra_frame,
177
218
  SpiceFrame.IMAP_DPS,
@@ -182,6 +223,9 @@ def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dat
182
223
  de_dict["velocity_dps_sc"] = sc_dps_velocity
183
224
  de_dict["velocity_dps_helio"] = helio_velocity
184
225
 
226
+ de_dict["energy_spacecraft"] = get_de_energy_kev(sc_dps_velocity, species_bin)
227
+ de_dict["energy_heliosphere"] = get_de_energy_kev(helio_velocity, species_bin)
228
+
185
229
  # TODO: TBD.
186
230
  de_dict["event_efficiency"] = np.full(
187
231
  len(de_dataset["epoch"]), np.nan, dtype=np.float32
@@ -6,50 +6,48 @@ from imap_processing.ultra.l1b.ultra_l1b_culling import (
6
6
  flag_attitude,
7
7
  flag_spin,
8
8
  get_energy_histogram,
9
- get_spin,
10
9
  )
11
10
  from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
12
11
 
13
12
 
14
13
  def calculate_extendedspin(
15
- hk_dataset: xr.Dataset,
16
- rates_dataset: xr.Dataset,
17
- de_dataset: xr.Dataset,
14
+ dict_datasets: dict[str, xr.Dataset],
18
15
  name: str,
19
16
  data_version: str,
17
+ instrument_id: int,
20
18
  ) -> xr.Dataset:
21
19
  """
22
20
  Create dataset with defined datatypes for Extended Spin Data.
23
21
 
24
22
  Parameters
25
23
  ----------
26
- hk_dataset : xarray.Dataset
27
- Dataset containing l1a hk data.
28
- rates_dataset : xarray.Dataset
29
- Dataset containing l1a rates data.
30
- de_dataset : xarray.Dataset
31
- Dataset containing l1b de data.
24
+ dict_datasets : dict
25
+ Dictionary containing all the datasets.
32
26
  name : str
33
27
  Name of the dataset.
34
28
  data_version : str
35
29
  Version of the data.
30
+ instrument_id : int
31
+ Instrument ID.
36
32
 
37
33
  Returns
38
34
  -------
39
35
  extendedspin_dataset : xarray.Dataset
40
36
  Dataset containing the data.
41
37
  """
38
+ aux_dataset = dict_datasets[f"imap_ultra_l1a_{instrument_id}sensor-aux"]
39
+ de_dataset = dict_datasets[f"imap_ultra_l1b_{instrument_id}sensor-de"]
40
+
42
41
  extendedspin_dict = {}
43
42
  rates_qf, spin, energy_midpoints, n_sigma_per_energy = flag_spin(
44
- de_dataset["event_times"].values,
43
+ de_dataset["spin"].values,
45
44
  de_dataset["energy"].values,
46
45
  )
47
- spin_number = get_spin(de_dataset["event_times"].values)
48
46
  count_rates, _, counts, _ = get_energy_histogram(
49
- spin_number, de_dataset["energy"].values
47
+ de_dataset["spin"].values, de_dataset["energy"].values
50
48
  )
51
49
  attitude_qf, spin_rates, spin_period, spin_starttime = flag_attitude(
52
- de_dataset["event_times"].values
50
+ de_dataset["spin"].values, aux_dataset
53
51
  )
54
52
 
55
53
  # These will be the coordinates.