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
@@ -8,8 +8,11 @@ import pandas as pd
8
8
  import xarray as xr
9
9
 
10
10
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
11
+ from imap_processing.spice.time import met_to_ttj2000ns
12
+ from imap_processing.swe.utils import swe_constants
11
13
  from imap_processing.swe.utils.swe_utils import (
12
- ESA_VOLTAGE_ROW_INDEX_DICT,
14
+ calculate_data_acquisition_time,
15
+ combine_acquisition_time,
13
16
  read_lookup_table,
14
17
  )
15
18
 
@@ -157,18 +160,19 @@ def calculate_calibration_factor(
157
160
  Parameters
158
161
  ----------
159
162
  acquisition_times : numpy.ndarray
160
- Data points to interpolate. Shape is (24, 30).
163
+ Data points to interpolate. Shape is (N_ESA_STEPS, N_ANGLE_SECTORS).
161
164
  cal_times : numpy.ndarray
162
165
  X-coordinates data points. Calibration times. Shape is (n,).
163
166
  cal_data : numpy.ndarray
164
167
  Y-coordinates data points. Calibration data of corresponding cal_times.
165
- Shape is (n, 7).
168
+ Shape is (n, N_CEMS).
166
169
 
167
170
  Returns
168
171
  -------
169
172
  calibration_factor : numpy.ndarray
170
- Calibration factor for each CEM detector. Shape is (24, 30, 7)
171
- where last 7 dimension contains calibration factor for each CEM detector.
173
+ Calibration factor for each CEM detector. Shape is
174
+ (N_ESA_STEPS, N_ANGLE_SECTORS, N_CEMS) where last 7 dimension
175
+ contains calibration factor for each CEM detector.
172
176
  """
173
177
  # Raise error if there is no pre or post time in cal_times. SWE does not
174
178
  # want to extrapolate calibration data.
@@ -220,20 +224,23 @@ def apply_in_flight_calibration(
220
224
  Parameters
221
225
  ----------
222
226
  corrected_counts : numpy.ndarray
223
- Corrected count of full cycle data. Data shape is (24, 30, 7).
227
+ Corrected count of full cycle data. Data shape is
228
+ (N_ESA_STEPS, N_ANGLE_SECTORS, N_CEMS).
224
229
  acquisition_time : numpy.ndarray
225
- Acquisition time of full cycle data. Data shape is (24, 30).
230
+ Acquisition time of full cycle data. Data shape is
231
+ (N_ESA_STEPS, N_ANGLE_SECTORS).
226
232
 
227
233
  Returns
228
234
  -------
229
235
  corrected_counts : numpy.ndarray
230
236
  Corrected count of full cycle data after applying in-flight calibration.
231
- Array shape is (24, 30, 7).
237
+ Array shape is (N_ESA_STEPS, N_ANGLE_SECTORS, N_CEMS).
232
238
  """
233
239
  # Read in in-flight calibration data
234
240
  in_flight_cal_df = read_in_flight_cal_data()
235
241
  # calculate calibration factor.
236
- # return shape of calculate_calibration_factor is (24, 30, 7) where
242
+ # return shape of calculate_calibration_factor is
243
+ # (N_ESA_STEPS, N_ANGLE_SECTORS, N_CEMS) where
237
244
  # last 7 dimension contains calibration factor for each CEM detector.
238
245
  cal_factor = calculate_calibration_factor(
239
246
  acquisition_time,
@@ -270,31 +277,38 @@ def populate_full_cycle_data(
270
277
  # with information that esa step ramps up in even column and ramps down
271
278
  # in odd column every six steps.
272
279
  if esa_table_num == 0:
273
- energy_steps = 24
274
- angle = 30
275
- cem_detectors = 7
276
280
  # create new full cycle data array
277
- full_cycle_data = np.zeros((energy_steps, angle, cem_detectors))
281
+ full_cycle_data = np.zeros(
282
+ (
283
+ swe_constants.N_ESA_STEPS,
284
+ swe_constants.N_ANGLE_SECTORS,
285
+ swe_constants.N_CEMS,
286
+ )
287
+ )
278
288
  # SWE needs to store acquisition time of each count data point
279
289
  # to use in level 2 processing to calculate
280
290
  # spin phase. This is done below by using information from
281
291
  # science packet.
282
- acquisition_times = np.zeros((energy_steps, angle))
292
+ acquisition_times = np.zeros(
293
+ (swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS)
294
+ )
283
295
 
284
296
  # Store acquisition duration for later calculation in this function
285
- acq_duration_arr = np.zeros((energy_steps, angle))
297
+ acq_duration_arr = np.zeros(
298
+ (swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS)
299
+ )
286
300
 
287
301
  # Initialize esa_step_number and column_index.
288
302
  # esa_step_number goes from 0 to 719 range where
289
- # 720 came from 24 x 30. full_cycle_data array has (24, 30)
290
- # dimension.
303
+ # 720 came from 24 x 30. full_cycle_data array has
304
+ # (N_ESA_STEPS, N_ANGLE_SECTORS) dimension.
291
305
  esa_step_number = 0
292
306
  # column_index goes from 0 to 29 range where
293
307
  # 30 came from 30 column in full_cycle_data array
294
308
  column_index = -1
295
309
 
296
310
  # Go through four quarter cycle data packets
297
- for index in range(4):
311
+ for index in range(swe_constants.N_QUARTER_CYCLES):
298
312
  decompressed_counts = l1a_data["science_data"].data[packet_index + index]
299
313
  # Do deadtime correction
300
314
  acq_duration = l1a_data["acq_duration"].data[packet_index + index]
@@ -304,11 +318,9 @@ def populate_full_cycle_data(
304
318
  # Each quarter cycle data should have same acquisition start time coarse
305
319
  # and fine value. We will use that as base time to calculate each
306
320
  # acquisition time for each count data.
307
- # base_quarter_cycle_acq_time = acq_start_coarse +
308
- # acq_start_fine / 1000000
309
- base_quarter_cycle_acq_time = (
310
- l1a_data["acq_start_coarse"].data[packet_index + index]
311
- + l1a_data["acq_start_fine"].data[packet_index + index] / 1000000
321
+ base_quarter_cycle_acq_time = combine_acquisition_time(
322
+ l1a_data["acq_start_coarse"].data[packet_index + index],
323
+ l1a_data["acq_start_fine"].data[packet_index + index],
312
324
  )
313
325
 
314
326
  # Go through each quarter cycle's 180 ESA measurements
@@ -317,7 +329,9 @@ def populate_full_cycle_data(
317
329
  # Get esa voltage value from esa lookup table and
318
330
  # use that to get row index in full data array
319
331
  esa_voltage_value = esa_lookup_table.loc[esa_step_number]["esa_v"]
320
- esa_voltage_row_index = ESA_VOLTAGE_ROW_INDEX_DICT[esa_voltage_value]
332
+ esa_voltage_row_index = swe_constants.ESA_VOLTAGE_ROW_INDEX_DICT[
333
+ esa_voltage_value
334
+ ]
321
335
 
322
336
  # every six steps, increment column index
323
337
  if esa_step_number % 6 == 0:
@@ -326,15 +340,14 @@ def populate_full_cycle_data(
326
340
  full_cycle_data[esa_voltage_row_index][column_index] = corrected_counts[
327
341
  step
328
342
  ]
329
- # Acquisition time (in seconds) of each count data point will be
330
- # using this formula:
331
- # each_count_acq_time = base_quarter_cycle_acq_time +
332
- # (step * ( acq_duration + settle_duration) / 1000000 )
333
- # where step goes from 0 to 179, acq_start_coarse is in seconds and
334
- # acq_start_fine is in microseconds and acq_duration is in microseconds.
343
+ # Acquisition time (in seconds) of each count data point
335
344
  acquisition_times[esa_voltage_row_index][column_index] = (
336
- base_quarter_cycle_acq_time
337
- + (step * (acq_duration + settle_duration) / 1000000)
345
+ calculate_data_acquisition_time(
346
+ base_quarter_cycle_acq_time,
347
+ esa_step_number,
348
+ acq_duration,
349
+ settle_duration,
350
+ )
338
351
  )
339
352
  # Store acquisition duration for later calculation
340
353
  acq_duration_arr[esa_voltage_row_index][column_index] = acq_duration
@@ -352,13 +365,16 @@ def populate_full_cycle_data(
352
365
  calibrated_counts = apply_in_flight_calibration(full_cycle_data, acquisition_times)
353
366
 
354
367
  # Convert counts to rate
355
- counts_rate = convert_counts_to_rate(calibrated_counts, acq_duration)
368
+ counts_rate = convert_counts_to_rate(
369
+ calibrated_counts, acq_duration_arr[:, :, np.newaxis]
370
+ )
356
371
 
357
- # Store count data and acquisition times of full cycle data in xr.Dataset
372
+ # Store full cycle data in xr.Dataset for later use.
358
373
  full_cycle_ds = xr.Dataset(
359
374
  {
360
375
  "full_cycle_data": (["esa_step", "spin_sector", "cem_id"], counts_rate),
361
376
  "acquisition_time": (["esa_step", "spin_sector"], acquisition_times),
377
+ "acq_duration": (["esa_step", "spin_sector"], acq_duration_arr),
362
378
  }
363
379
  )
364
380
 
@@ -381,7 +397,7 @@ def find_cycle_starts(cycles: np.ndarray) -> npt.NDArray:
381
397
  first_quarter_indices : numpy.ndarray
382
398
  Array of indices of start cycle.
383
399
  """
384
- if cycles.size < 4:
400
+ if cycles.size < swe_constants.N_QUARTER_CYCLES:
385
401
  return np.array([], np.int64)
386
402
 
387
403
  # calculate difference between consecutive cycles
@@ -422,7 +438,10 @@ def get_indices_of_full_cycles(quarter_cycle: np.ndarray) -> npt.NDArray:
422
438
  # Eg. [[0, 1, 2, 3]]
423
439
  # then we add both of them together to get an array of shape(n, 4)
424
440
  # Eg. [[3, 4, 5, 6], [8, 9, 10, 11]]
425
- full_cycles_indices = indices_of_start[..., None] + np.arange(4)[None, ...]
441
+ full_cycles_indices = (
442
+ indices_of_start[..., None]
443
+ + np.arange(swe_constants.N_QUARTER_CYCLES)[None, ...]
444
+ )
426
445
  return full_cycles_indices.reshape(-1)
427
446
 
428
447
 
@@ -470,7 +489,9 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
470
489
  # Array to store list of table populated with data
471
490
  # of full cycles
472
491
  full_cycle_science_data = []
492
+ # These two are carried in l1b for level 2 and 3 processing
473
493
  full_cycle_acq_times = []
494
+ full_cycle_acq_duration = []
474
495
  packet_index = 0
475
496
  l1a_data_copy = l1a_data.copy(deep=True)
476
497
 
@@ -505,7 +526,7 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
505
526
  )
506
527
 
507
528
  # Go through each cycle and populate full cycle data
508
- for packet_index in range(0, total_packets, 4):
529
+ for packet_index in range(0, total_packets, swe_constants.N_QUARTER_CYCLES):
509
530
  # get ESA lookup table information
510
531
  esa_table_num = l1a_data["esa_table_num"].data[packet_index]
511
532
 
@@ -524,6 +545,7 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
524
545
  # save full data array to file
525
546
  full_cycle_science_data.append(full_cycle_ds["full_cycle_data"].data)
526
547
  full_cycle_acq_times.append(full_cycle_ds["acquisition_time"].data)
548
+ full_cycle_acq_duration.append(full_cycle_ds["acq_duration"].data)
527
549
 
528
550
  # ------------------------------------------------------------------
529
551
  # Save data to dataset.
@@ -534,22 +556,32 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
534
556
  cdf_attrs.add_instrument_variable_attrs("swe", "l1b")
535
557
  cdf_attrs.add_global_attribute("Data_version", data_version)
536
558
 
537
- # Get epoch time of full cycle data and then reshape it to
538
- # (n, 4) where n = total number of full cycles and 4 = four
539
- # quarter cycle data metadata. For epoch's data, we take the first element
540
- # of each quarter cycle data metadata.
559
+ # One full cycle data combines four quarter cycles data.
560
+ # Epoch will store center of each science meansurement using
561
+ # third acquisition start time coarse and fine value
562
+ # of four quarter cycle data packets. For example, we want to
563
+ # get indices of 3rd quarter cycle data packet in each full cycle
564
+ # and use that to calculate center time of data acquisition time.
565
+ # Quarter cycle indices: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, ...
566
+ indices_of_center_time = np.arange(2, total_packets, swe_constants.N_QUARTER_CYCLES)
567
+
568
+ center_time = combine_acquisition_time(
569
+ full_cycle_l1a_data["acq_start_coarse"].data[indices_of_center_time],
570
+ full_cycle_l1a_data["acq_start_fine"].data[indices_of_center_time],
571
+ )
572
+
541
573
  epoch_time = xr.DataArray(
542
- l1a_data["epoch"].data[full_cycle_data_indices].reshape(-1, 4)[:, 0],
574
+ met_to_ttj2000ns(center_time),
543
575
  name="epoch",
544
576
  dims=["epoch"],
545
- attrs=cdf_attrs.get_variable_attributes("epoch"),
577
+ attrs=cdf_attrs.get_variable_attributes("epoch", check_schema=False),
546
578
  )
547
579
 
548
580
  esa_step = xr.DataArray(
549
- np.arange(24),
581
+ np.arange(swe_constants.N_ESA_STEPS),
550
582
  name="esa_step",
551
583
  dims=["esa_step"],
552
- attrs=cdf_attrs.get_variable_attributes("esa_step"),
584
+ attrs=cdf_attrs.get_variable_attributes("esa_step", check_schema=False),
553
585
  )
554
586
 
555
587
  # NOTE: LABL_PTR_1 should be CDF_CHAR.
@@ -557,14 +589,14 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
557
589
  esa_step.values.astype(str),
558
590
  name="esa_step_label",
559
591
  dims=["esa_step"],
560
- attrs=cdf_attrs.get_variable_attributes("esa_step_label"),
592
+ attrs=cdf_attrs.get_variable_attributes("esa_step_label", check_schema=False),
561
593
  )
562
594
 
563
595
  spin_sector = xr.DataArray(
564
- np.arange(30),
596
+ np.arange(swe_constants.N_ANGLE_SECTORS),
565
597
  name="spin_sector",
566
598
  dims=["spin_sector"],
567
- attrs=cdf_attrs.get_variable_attributes("spin_sector"),
599
+ attrs=cdf_attrs.get_variable_attributes("spin_sector", check_schema=False),
568
600
  )
569
601
 
570
602
  # NOTE: LABL_PTR_2 should be CDF_CHAR.
@@ -572,21 +604,30 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
572
604
  spin_sector.values.astype(str),
573
605
  name="spin_sector_label",
574
606
  dims=["spin_sector"],
575
- attrs=cdf_attrs.get_variable_attributes("spin_sector_label"),
607
+ attrs=cdf_attrs.get_variable_attributes(
608
+ "spin_sector_label", check_schema=False
609
+ ),
576
610
  )
577
611
 
578
612
  cycle = xr.DataArray(
579
- np.arange(4),
613
+ np.arange(swe_constants.N_QUARTER_CYCLES),
580
614
  name="cycle",
581
615
  dims=["cycle"],
582
- attrs=cdf_attrs.get_variable_attributes("cycle"),
616
+ attrs=cdf_attrs.get_variable_attributes("cycle", check_schema=False),
617
+ )
618
+
619
+ cycle_label = xr.DataArray(
620
+ cycle.values.astype(str),
621
+ name="cycle_label",
622
+ dims=["cycle"],
623
+ attrs=cdf_attrs.get_variable_attributes("cycle_label", check_schema=False),
583
624
  )
584
625
 
585
626
  cem_id = xr.DataArray(
586
- np.arange(7, dtype=np.float64),
627
+ np.arange(swe_constants.N_CEMS, dtype=np.int8),
587
628
  name="cem_id",
588
629
  dims=["cem_id"],
589
- attrs=cdf_attrs.get_variable_attributes("cem_id"),
630
+ attrs=cdf_attrs.get_variable_attributes("cem_id", check_schema=False),
590
631
  )
591
632
 
592
633
  # NOTE: LABL_PTR_3 should be CDF_CHAR.
@@ -594,7 +635,7 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
594
635
  cem_id.values.astype(str),
595
636
  name="cem_id_label",
596
637
  dims=["cem_id"],
597
- attrs=cdf_attrs.get_variable_attributes("cem_id_label"),
638
+ attrs=cdf_attrs.get_variable_attributes("cem_id_label", check_schema=False),
598
639
  )
599
640
 
600
641
  # Add science data and it's associated metadata into dataset.
@@ -622,6 +663,7 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
622
663
  "esa_step_label": esa_step_label,
623
664
  "spin_sector_label": spin_sector_label,
624
665
  "cem_id_label": cem_id_label,
666
+ "cycle_label": cycle_label,
625
667
  },
626
668
  attrs=cdf_attrs.get_global_attributes("imap_swe_l1b_sci"),
627
669
  )
@@ -636,14 +678,19 @@ def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
636
678
  dims=["epoch", "esa_step", "spin_sector"],
637
679
  attrs=cdf_attrs.get_variable_attributes("acquisition_time"),
638
680
  )
681
+ dataset["acq_duration"] = xr.DataArray(
682
+ full_cycle_acq_duration,
683
+ dims=["epoch", "esa_step", "spin_sector"],
684
+ attrs=cdf_attrs.get_variable_attributes("acq_duration"),
685
+ )
639
686
 
640
687
  # create xarray dataset for each metadata field
641
688
  for key, value in full_cycle_l1a_data.items():
642
- if key == "science_data":
689
+ if key in ["science_data", "acq_duration"]:
643
690
  continue
644
691
  metadata_field = key.lower()
645
692
  dataset[metadata_field] = xr.DataArray(
646
- value.data.reshape(-1, 4),
693
+ value.data.reshape(-1, swe_constants.N_QUARTER_CYCLES),
647
694
  dims=["epoch", "cycle"],
648
695
  attrs=cdf_attrs.get_variable_attributes(metadata_field),
649
696
  )
@@ -11,34 +11,11 @@ import xarray as xr
11
11
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
12
12
  from imap_processing.spice.geometry import SpiceFrame
13
13
  from imap_processing.spice.spin import get_instrument_spin_phase, get_spin_angle
14
+ from imap_processing.swe.utils import swe_constants
14
15
  from imap_processing.swe.utils.swe_utils import (
15
- ESA_VOLTAGE_ROW_INDEX_DICT,
16
16
  read_lookup_table,
17
17
  )
18
18
 
19
- # TODO: add these to instrument status summary
20
- ENERGY_CONVERSION_FACTOR = 4.75
21
- # 7 CEMs geometric factors in cm^2 sr eV/eV units.
22
- GEOMETRIC_FACTORS = np.array(
23
- [
24
- 435e-6,
25
- 599e-6,
26
- 808e-6,
27
- 781e-6,
28
- 876e-6,
29
- 548e-6,
30
- 432e-6,
31
- ]
32
- )
33
- ELECTRON_MASS = 9.10938356e-31 # kg
34
-
35
- # See doc string of calculate_phase_space_density() for more details.
36
- VELOCITY_CONVERSION_FACTOR = 1.237e31
37
- # See doc string of calculate_flux() for more details.
38
- FLUX_CONVERSION_FACTOR = 6.187e30
39
-
40
- CEM_DETECTORS_ANGLE = np.array([-63, -42, -21, 0, 21, 42, 63])
41
-
42
19
 
43
20
  def get_particle_energy() -> npt.NDArray:
44
21
  """
@@ -57,7 +34,9 @@ def get_particle_energy() -> npt.NDArray:
57
34
  lookup_table = read_lookup_table()
58
35
 
59
36
  # Convert voltage to electron energy in eV by apply conversion factor.
60
- lookup_table["energy"] = lookup_table["esa_v"].values * ENERGY_CONVERSION_FACTOR
37
+ lookup_table["energy"] = (
38
+ lookup_table["esa_v"].values * swe_constants.ENERGY_CONVERSION_FACTOR
39
+ )
61
40
  return lookup_table
62
41
 
63
42
 
@@ -117,14 +96,16 @@ def calculate_phase_space_density(l1b_dataset: xr.Dataset) -> xr.Dataset:
117
96
  for val in esa_table_nums
118
97
  ]
119
98
  )
120
- particle_energy_data = particle_energy_data.reshape(-1, 24, 30)
99
+ particle_energy_data = particle_energy_data.reshape(
100
+ -1, swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS
101
+ )
121
102
 
122
103
  # Calculate phase space density using formula:
123
104
  # 2 * (C/tau) / (G * 1.237e31 * eV^2)
124
105
  # See doc string for more details.
125
106
  density = (2 * l1b_dataset["science_data"]) / (
126
- GEOMETRIC_FACTORS[np.newaxis, np.newaxis, np.newaxis, :]
127
- * VELOCITY_CONVERSION_FACTOR
107
+ swe_constants.GEOMETRIC_FACTORS[np.newaxis, np.newaxis, np.newaxis, :]
108
+ * swe_constants.VELOCITY_CONVERSION_FACTOR
128
109
  * particle_energy_data[:, :, :, np.newaxis] ** 2
129
110
  )
130
111
 
@@ -194,7 +175,7 @@ def calculate_flux(l1b_dataset: xr.Dataset) -> npt.NDArray:
194
175
  """
195
176
  phase_space_density_ds = calculate_phase_space_density(l1b_dataset)
196
177
  flux = (
197
- FLUX_CONVERSION_FACTOR
178
+ swe_constants.FLUX_CONVERSION_FACTOR
198
179
  * phase_space_density_ds["energy_in_eV"].data[:, :, :, np.newaxis]
199
180
  * phase_space_density_ds["phase_space_density"].data
200
181
  )
@@ -220,22 +201,32 @@ def put_data_into_angle_bins(
220
201
  Parameters
221
202
  ----------
222
203
  data : numpy.ndarray
223
- Data to put in bins. Shape: (full_cycle_data, energy_step, angle_bin, 7).
204
+ Data to put in bins. Shape:
205
+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS, N_CEMS).
224
206
  angle_bin_indices : numpy.ndarray
225
207
  Indices of angle bins to put data in. Shape:
226
- (full_cycle_data, energy_step, angle_bin).
208
+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS).
227
209
 
228
210
  Returns
229
211
  -------
230
212
  numpy.ndarray
231
- Data in bins. Shape: (full_cycle_data, 24, 30, 7).
213
+ Data in bins. Shape:
214
+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS, N_CEMS).
232
215
  """
233
216
  # Initialize with zeros instead of NaN because np.add.at() does not
234
217
  # work with nan values. It results in nan + value = nan
235
- binned_data = np.zeros((data.shape[0], 24, 30, 7), dtype=np.float64)
218
+ binned_data = np.zeros(
219
+ (
220
+ data.shape[0],
221
+ swe_constants.N_ESA_STEPS,
222
+ swe_constants.N_ANGLE_BINS,
223
+ swe_constants.N_CEMS,
224
+ ),
225
+ dtype=np.float64,
226
+ )
236
227
 
237
228
  time_indices = np.arange(data.shape[0])[:, None, None]
238
- energy_indices = np.arange(24)[None, :, None]
229
+ energy_indices = np.arange(swe_constants.N_ESA_STEPS)[None, :, None]
239
230
 
240
231
  # Use np.add.at() to accumulate values into bins
241
232
  np.add.at(binned_data, (time_indices, energy_indices, angle_bin_indices), data)
@@ -335,45 +326,52 @@ def swe_l2(l1b_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
335
326
 
336
327
  # Energy values in eV.
337
328
  energy_xr = xr.DataArray(
338
- np.array(list(ESA_VOLTAGE_ROW_INDEX_DICT.keys())) * ENERGY_CONVERSION_FACTOR,
329
+ np.array(list(swe_constants.ESA_VOLTAGE_ROW_INDEX_DICT.keys()))
330
+ * swe_constants.ENERGY_CONVERSION_FACTOR,
339
331
  name="energy",
340
332
  dims=["energy"],
341
- attrs=cdf_attributes.get_variable_attributes("energy"),
333
+ attrs=cdf_attributes.get_variable_attributes("energy", check_schema=False),
342
334
  )
343
335
 
344
336
  energy_label = xr.DataArray(
345
- np.array(list(ESA_VOLTAGE_ROW_INDEX_DICT.keys())).astype(str),
337
+ np.array(list(swe_constants.ESA_VOLTAGE_ROW_INDEX_DICT.keys())).astype(str),
346
338
  name="energy_label",
347
339
  dims=["energy"],
348
- attrs=cdf_attributes.get_variable_attributes("energy_label"),
340
+ attrs=cdf_attributes.get_variable_attributes(
341
+ "energy_label", check_schema=False
342
+ ),
349
343
  )
350
344
 
351
345
  # Angle of each CEM detectors.
352
346
  inst_el_xr = xr.DataArray(
353
- CEM_DETECTORS_ANGLE,
347
+ swe_constants.CEM_DETECTORS_ANGLE,
354
348
  name="inst_el",
355
349
  dims=["inst_el"],
356
- attrs=cdf_attributes.get_variable_attributes("inst_el"),
350
+ attrs=cdf_attributes.get_variable_attributes("inst_el", check_schema=False),
357
351
  )
358
352
  inst_el_label = xr.DataArray(
359
- CEM_DETECTORS_ANGLE.astype(str),
353
+ swe_constants.CEM_DETECTORS_ANGLE.astype(str),
360
354
  name="inst_el_label",
361
355
  dims=["inst_el"],
362
- attrs=cdf_attributes.get_variable_attributes("inst_el_label"),
356
+ attrs=cdf_attributes.get_variable_attributes(
357
+ "inst_el_label", check_schema=False
358
+ ),
363
359
  )
364
360
 
365
361
  # Spin Angle bins storing bin center values.
366
362
  inst_az_xr = xr.DataArray(
367
- np.arange(0, 360, 12) + 6,
363
+ np.arange(0, 360, 12, dtype=np.float32) + 6,
368
364
  name="inst_az",
369
365
  dims=["inst_az"],
370
- attrs=cdf_attributes.get_variable_attributes("inst_az"),
366
+ attrs=cdf_attributes.get_variable_attributes("inst_az", check_schema=False),
371
367
  )
372
368
  inst_az_label = xr.DataArray(
373
369
  inst_az_xr.values.astype(str),
374
370
  name="inst_az_label",
375
371
  dims=["inst_az"],
376
- attrs=cdf_attributes.get_variable_attributes("inst_az_label"),
372
+ attrs=cdf_attributes.get_variable_attributes(
373
+ "inst_az_label", check_schema=False
374
+ ),
377
375
  )
378
376
 
379
377
  dataset = xr.Dataset(
@@ -419,36 +417,33 @@ def swe_l2(l1b_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
419
417
 
420
418
  # Carry over acquisition times for L3 purposes.
421
419
  dataset["acquisition_time"] = l1b_dataset["acquisition_time"]
420
+ # Update the acquisition_time variable attributes.
421
+ dataset["acquisition_time"].attrs = cdf_attributes.get_variable_attributes(
422
+ "acquisition_time"
423
+ )
424
+ # Carry over acq_duration for L3 purposes.
425
+ dataset["acq_duration"] = l1b_dataset["acq_duration"]
426
+ # Update the acq_duration variable attributes.
427
+ dataset["acq_duration"].attrs = cdf_attributes.get_variable_attributes(
428
+ "acq_duration"
429
+ )
422
430
 
423
431
  # Calculate spin phase using SWE acquisition_time from the
424
432
  # L1B dataset. The L1B dataset stores acquisition_time with
425
- # dimensions (epoch, esa_step, spin_sector). Use center time
426
- # to calculate spin phase. This center time calculation is
427
- # necessary to accurately determine the center angle of the data.
428
- #
429
- # To determine the center acquisition time, we adjust the
430
- # recorded acquisition_time as follows:
431
- # acquisition_time + (acq_duration / 1000000) / 2
432
- #
433
- # Here, acq_duration is given in microseconds and is stored
434
- # in the L1B dataset with dimensions (epoch, cycle). Since acq_duration
435
- # remains the same for all quarter cycles within a full sweep,
436
- # we use the first acq_duration value for each full sweep to perform
437
- # this adjustment.
438
-
439
- acq_duration = l1b_dataset["acq_duration"].data[:, 0] / 2000000
440
- data_acq_time = (
441
- l1b_dataset["acquisition_time"].data + acq_duration[:, np.newaxis, np.newaxis]
442
- )
433
+ # dimensions (epoch, esa_step, spin_sector). acquisition_time is
434
+ # center time of acquisition time of each science measurement which
435
+ # is necessary to accurately determine the center angle of the data.
443
436
 
444
437
  # Calculate spin phase
445
438
  inst_spin_phase = get_instrument_spin_phase(
446
- query_met_times=data_acq_time.ravel(),
439
+ query_met_times=l1b_dataset["acquisition_time"].data.ravel(),
447
440
  instrument=SpiceFrame.IMAP_SWE,
448
441
  )
449
442
 
450
443
  # Convert spin phase to spin angle in degrees.
451
- inst_spin_angle = get_spin_angle(inst_spin_phase, degrees=True).reshape(-1, 24, 30)
444
+ inst_spin_angle = get_spin_angle(inst_spin_phase, degrees=True).reshape(
445
+ -1, swe_constants.N_ESA_STEPS, swe_constants.N_ANGLE_SECTORS
446
+ )
452
447
 
453
448
  # Save spin angle in dataset per SWE request.
454
449
  dataset["inst_az_spin_sector"] = xr.DataArray(