imap-processing 0.12.0__py3-none-any.whl → 0.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (272) hide show
  1. imap_processing/__init__.py +1 -0
  2. imap_processing/_version.py +2 -2
  3. imap_processing/ccsds/ccsds_data.py +1 -2
  4. imap_processing/ccsds/excel_to_xtce.py +1 -2
  5. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -12
  6. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +569 -0
  7. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +5 -5
  9. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +20 -1
  10. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
  11. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
  12. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -0
  13. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
  14. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +16 -0
  15. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +178 -5
  16. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -19
  18. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +8 -48
  19. imap_processing/cdf/utils.py +41 -33
  20. imap_processing/cli.py +463 -234
  21. imap_processing/codice/codice_l1a.py +260 -47
  22. imap_processing/codice/codice_l1b.py +51 -152
  23. imap_processing/codice/constants.py +38 -1
  24. imap_processing/ena_maps/ena_maps.py +658 -65
  25. imap_processing/ena_maps/utils/coordinates.py +1 -1
  26. imap_processing/ena_maps/utils/spatial_utils.py +10 -5
  27. imap_processing/glows/l1a/glows_l1a.py +28 -99
  28. imap_processing/glows/l1a/glows_l1a_data.py +2 -2
  29. imap_processing/glows/l1b/glows_l1b.py +1 -4
  30. imap_processing/glows/l1b/glows_l1b_data.py +1 -3
  31. imap_processing/glows/l2/glows_l2.py +2 -5
  32. imap_processing/hi/l1a/hi_l1a.py +31 -12
  33. imap_processing/hi/l1b/hi_l1b.py +80 -43
  34. imap_processing/hi/l1c/hi_l1c.py +12 -16
  35. imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
  36. imap_processing/hit/hit_utils.py +93 -35
  37. imap_processing/hit/l0/decom_hit.py +3 -1
  38. imap_processing/hit/l1a/hit_l1a.py +30 -25
  39. imap_processing/hit/l1b/constants.py +6 -2
  40. imap_processing/hit/l1b/hit_l1b.py +279 -318
  41. imap_processing/hit/l2/constants.py +37 -0
  42. imap_processing/hit/l2/hit_l2.py +373 -264
  43. imap_processing/ialirt/l0/parse_mag.py +138 -10
  44. imap_processing/ialirt/l0/process_swapi.py +69 -0
  45. imap_processing/ialirt/l0/process_swe.py +318 -22
  46. imap_processing/ialirt/packet_definitions/ialirt.xml +216 -212
  47. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
  48. imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
  49. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
  50. imap_processing/ialirt/utils/grouping.py +1 -1
  51. imap_processing/idex/idex_constants.py +9 -1
  52. imap_processing/idex/idex_l0.py +22 -8
  53. imap_processing/idex/idex_l1a.py +75 -44
  54. imap_processing/idex/idex_l1b.py +9 -8
  55. imap_processing/idex/idex_l2a.py +79 -45
  56. imap_processing/idex/idex_l2b.py +120 -0
  57. imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -39
  58. imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
  59. imap_processing/lo/l0/lo_science.py +1 -2
  60. imap_processing/lo/l1a/lo_l1a.py +1 -4
  61. imap_processing/lo/l1b/lo_l1b.py +527 -6
  62. imap_processing/lo/l1b/tof_conversions.py +11 -0
  63. imap_processing/lo/l1c/lo_l1c.py +1 -4
  64. imap_processing/mag/constants.py +43 -0
  65. imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
  66. imap_processing/mag/l1a/mag_l1a.py +2 -9
  67. imap_processing/mag/l1a/mag_l1a_data.py +10 -10
  68. imap_processing/mag/l1b/mag_l1b.py +84 -17
  69. imap_processing/mag/l1c/interpolation_methods.py +180 -3
  70. imap_processing/mag/l1c/mag_l1c.py +236 -70
  71. imap_processing/mag/l2/mag_l2.py +140 -0
  72. imap_processing/mag/l2/mag_l2_data.py +288 -0
  73. imap_processing/spacecraft/quaternions.py +1 -3
  74. imap_processing/spice/geometry.py +3 -3
  75. imap_processing/spice/kernels.py +0 -276
  76. imap_processing/spice/pointing_frame.py +257 -0
  77. imap_processing/spice/repoint.py +48 -19
  78. imap_processing/spice/spin.py +38 -33
  79. imap_processing/spice/time.py +24 -0
  80. imap_processing/swapi/l1/swapi_l1.py +16 -12
  81. imap_processing/swapi/l2/swapi_l2.py +116 -4
  82. imap_processing/swapi/swapi_utils.py +32 -0
  83. imap_processing/swe/l1a/swe_l1a.py +2 -9
  84. imap_processing/swe/l1a/swe_science.py +8 -11
  85. imap_processing/swe/l1b/swe_l1b.py +898 -23
  86. imap_processing/swe/l2/swe_l2.py +21 -77
  87. imap_processing/swe/utils/swe_constants.py +1 -0
  88. imap_processing/tests/ccsds/test_excel_to_xtce.py +1 -1
  89. imap_processing/tests/cdf/test_utils.py +14 -16
  90. imap_processing/tests/codice/conftest.py +44 -33
  91. imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
  92. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
  93. imap_processing/tests/codice/test_codice_l1a.py +20 -11
  94. imap_processing/tests/codice/test_codice_l1b.py +6 -7
  95. imap_processing/tests/conftest.py +78 -22
  96. imap_processing/tests/ena_maps/test_ena_maps.py +462 -33
  97. imap_processing/tests/ena_maps/test_spatial_utils.py +1 -1
  98. imap_processing/tests/glows/conftest.py +10 -14
  99. imap_processing/tests/glows/test_glows_decom.py +4 -4
  100. imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
  101. imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
  102. imap_processing/tests/glows/test_glows_l1b.py +11 -11
  103. imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
  104. imap_processing/tests/glows/test_glows_l2.py +2 -8
  105. imap_processing/tests/hi/conftest.py +1 -1
  106. imap_processing/tests/hi/test_hi_l1b.py +10 -12
  107. imap_processing/tests/hi/test_hi_l1c.py +27 -24
  108. imap_processing/tests/hi/test_l1a.py +7 -9
  109. imap_processing/tests/hi/test_science_direct_event.py +2 -2
  110. imap_processing/tests/hit/helpers/l1_validation.py +44 -43
  111. imap_processing/tests/hit/test_decom_hit.py +1 -1
  112. imap_processing/tests/hit/test_hit_l1a.py +9 -9
  113. imap_processing/tests/hit/test_hit_l1b.py +172 -217
  114. imap_processing/tests/hit/test_hit_l2.py +380 -118
  115. imap_processing/tests/hit/test_hit_utils.py +122 -55
  116. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
  117. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
  118. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
  119. imap_processing/tests/ialirt/unit/test_grouping.py +2 -2
  120. imap_processing/tests/ialirt/unit/test_parse_mag.py +71 -16
  121. imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
  122. imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
  123. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
  124. imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
  125. imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
  126. imap_processing/tests/ialirt/unit/test_process_swe.py +115 -7
  127. imap_processing/tests/idex/conftest.py +72 -7
  128. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
  129. imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
  130. imap_processing/tests/idex/test_idex_l0.py +33 -11
  131. imap_processing/tests/idex/test_idex_l1a.py +50 -23
  132. imap_processing/tests/idex/test_idex_l1b.py +104 -25
  133. imap_processing/tests/idex/test_idex_l2a.py +48 -32
  134. imap_processing/tests/idex/test_idex_l2b.py +93 -0
  135. imap_processing/tests/lo/test_lo_l1a.py +3 -3
  136. imap_processing/tests/lo/test_lo_l1b.py +371 -6
  137. imap_processing/tests/lo/test_lo_l1c.py +1 -1
  138. imap_processing/tests/lo/test_lo_science.py +6 -7
  139. imap_processing/tests/lo/test_star_sensor.py +1 -1
  140. imap_processing/tests/mag/conftest.py +58 -9
  141. imap_processing/tests/mag/test_mag_decom.py +4 -3
  142. imap_processing/tests/mag/test_mag_l1a.py +13 -7
  143. imap_processing/tests/mag/test_mag_l1b.py +9 -9
  144. imap_processing/tests/mag/test_mag_l1c.py +151 -47
  145. imap_processing/tests/mag/test_mag_l2.py +130 -0
  146. imap_processing/tests/mag/test_mag_validation.py +144 -7
  147. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
  148. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
  149. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
  150. imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
  151. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
  152. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
  153. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
  154. imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
  155. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
  156. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
  157. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
  158. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
  159. imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
  160. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
  161. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
  162. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
  163. imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
  164. imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
  165. imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
  166. imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
  167. imap_processing/tests/spacecraft/test_quaternions.py +1 -1
  168. imap_processing/tests/spice/test_data/fake_repoint_data.csv +4 -4
  169. imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
  170. imap_processing/tests/spice/test_geometry.py +3 -3
  171. imap_processing/tests/spice/test_kernels.py +1 -200
  172. imap_processing/tests/spice/test_pointing_frame.py +185 -0
  173. imap_processing/tests/spice/test_repoint.py +20 -10
  174. imap_processing/tests/spice/test_spin.py +50 -9
  175. imap_processing/tests/spice/test_time.py +14 -0
  176. imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
  177. imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
  178. imap_processing/tests/swapi/test_swapi_l1.py +7 -9
  179. imap_processing/tests/swapi/test_swapi_l2.py +180 -8
  180. imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
  181. imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
  182. imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
  183. imap_processing/tests/swe/test_swe_l1a.py +6 -6
  184. imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
  185. imap_processing/tests/swe/test_swe_l1b.py +162 -24
  186. imap_processing/tests/swe/test_swe_l2.py +82 -102
  187. imap_processing/tests/test_cli.py +171 -88
  188. imap_processing/tests/test_utils.py +2 -1
  189. imap_processing/tests/ultra/data/mock_data.py +49 -21
  190. imap_processing/tests/ultra/unit/conftest.py +53 -70
  191. imap_processing/tests/ultra/unit/test_badtimes.py +2 -4
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +4 -6
  193. imap_processing/tests/ultra/unit/test_de.py +3 -10
  194. imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
  195. imap_processing/tests/ultra/unit/test_decom_apid_881.py +15 -16
  196. imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
  197. imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
  198. imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
  199. imap_processing/tests/ultra/unit/test_spacecraft_pset.py +3 -4
  200. imap_processing/tests/ultra/unit/test_ultra_l1a.py +84 -307
  201. imap_processing/tests/ultra/unit/test_ultra_l1b.py +30 -12
  202. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
  203. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +4 -1
  204. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +163 -29
  205. imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
  206. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +32 -43
  207. imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
  208. imap_processing/ultra/constants.py +1 -1
  209. imap_processing/ultra/l0/decom_tools.py +21 -34
  210. imap_processing/ultra/l0/decom_ultra.py +168 -204
  211. imap_processing/ultra/l0/ultra_utils.py +152 -136
  212. imap_processing/ultra/l1a/ultra_l1a.py +55 -243
  213. imap_processing/ultra/l1b/badtimes.py +1 -4
  214. imap_processing/ultra/l1b/cullingmask.py +2 -6
  215. imap_processing/ultra/l1b/de.py +62 -47
  216. imap_processing/ultra/l1b/extendedspin.py +8 -4
  217. imap_processing/ultra/l1b/lookup_utils.py +72 -9
  218. imap_processing/ultra/l1b/ultra_l1b.py +3 -8
  219. imap_processing/ultra/l1b/ultra_l1b_culling.py +4 -4
  220. imap_processing/ultra/l1b/ultra_l1b_extended.py +236 -78
  221. imap_processing/ultra/l1c/histogram.py +2 -6
  222. imap_processing/ultra/l1c/spacecraft_pset.py +2 -4
  223. imap_processing/ultra/l1c/ultra_l1c.py +1 -5
  224. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +107 -60
  225. imap_processing/ultra/l2/ultra_l2.py +299 -0
  226. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
  227. imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
  228. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
  229. imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
  230. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
  231. imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  232. imap_processing/ultra/packet_definitions/README.md +38 -0
  233. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
  234. imap_processing/ultra/utils/ultra_l1_utils.py +13 -12
  235. imap_processing/utils.py +1 -1
  236. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +3 -2
  237. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/RECORD +264 -225
  238. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
  239. imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +0 -6
  240. imap_processing/mag/l1b/__init__.py +0 -0
  241. imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
  242. imap_processing/swe/l1b/swe_l1b_science.py +0 -699
  243. imap_processing/tests/swe/test_swe_l1b_science.py +0 -103
  244. imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
  245. imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
  246. /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
  247. /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  248. /imap_processing/tests/ialirt/{test_data → data}/l0/461971383-404.bin +0 -0
  249. /imap_processing/tests/ialirt/{test_data → data}/l0/461971384-405.bin +0 -0
  250. /imap_processing/tests/ialirt/{test_data → data}/l0/461971385-406.bin +0 -0
  251. /imap_processing/tests/ialirt/{test_data → data}/l0/461971386-407.bin +0 -0
  252. /imap_processing/tests/ialirt/{test_data → data}/l0/461971387-408.bin +0 -0
  253. /imap_processing/tests/ialirt/{test_data → data}/l0/461971388-409.bin +0 -0
  254. /imap_processing/tests/ialirt/{test_data → data}/l0/461971389-410.bin +0 -0
  255. /imap_processing/tests/ialirt/{test_data → data}/l0/461971390-411.bin +0 -0
  256. /imap_processing/tests/ialirt/{test_data → data}/l0/461971391-412.bin +0 -0
  257. /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  258. /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
  259. /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
  260. /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
  261. /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
  262. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
  263. /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
  264. /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
  265. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  266. /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
  267. /imap_processing/tests/ialirt/{test_data → data}/l0/sample_decoded_i-alirt_data.csv +0 -0
  268. /imap_processing/tests/mag/validation/{imap_calibration_mag_20240229_v01.cdf → calibration/imap_mag_l1b-calibration_20240229_v001.cdf} +0 -0
  269. /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
  270. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
  271. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
  272. {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -5,11 +5,25 @@ from unittest import mock
5
5
 
6
6
  import pytest
7
7
  import xarray as xr
8
+ from imap_data_access.processing_input import (
9
+ ProcessingInputCollection,
10
+ ScienceInput,
11
+ )
8
12
 
9
- from imap_processing.cli import Codice, Hi, Hit, Swe, Ultra, _validate_args, main
13
+ from imap_processing.cli import (
14
+ Codice,
15
+ Glows,
16
+ Hi,
17
+ Hit,
18
+ Spacecraft,
19
+ Swe,
20
+ Ultra,
21
+ _validate_args,
22
+ main,
23
+ )
10
24
 
11
25
 
12
- @pytest.fixture()
26
+ @pytest.fixture
13
27
  def mock_instrument_dependencies():
14
28
  with (
15
29
  mock.patch("imap_processing.cli.imap_data_access.query") as mock_query,
@@ -17,6 +31,9 @@ def mock_instrument_dependencies():
17
31
  mock.patch("imap_processing.cli.imap_data_access.upload") as mock_upload,
18
32
  mock.patch("imap_processing.cli.write_cdf") as mock_write_cdf,
19
33
  mock.patch("imap_processing.cli.load_cdf") as mock_load_cdf,
34
+ mock.patch(
35
+ "imap_processing.cli.ProcessInstrument.pre_processing"
36
+ ) as mock_pre_processing,
20
37
  ):
21
38
  mocks = {
22
39
  "mock_query": mock_query,
@@ -24,6 +41,7 @@ def mock_instrument_dependencies():
24
41
  "mock_upload": mock_upload,
25
42
  "mock_write_cdf": mock_write_cdf,
26
43
  "mock_load_cdf": mock_load_cdf,
44
+ "mock_pre_processing": mock_pre_processing,
27
45
  }
28
46
  yield mocks
29
47
 
@@ -37,18 +55,28 @@ def test_main(mock_instrument):
37
55
  "mag",
38
56
  "--dependency",
39
57
  (
40
- '[{"instrument": "mag", '
41
- '"data_level": "l0", '
42
- '"descriptor": "sci", '
43
- '"version": "v001", '
44
- '"start_date": "20240430"}]'
58
+ "["
59
+ "{"
60
+ '"type": "ancillary",'
61
+ '"files": ['
62
+ '"imap_mag_l1b-cal_20250101_v001.cdf",'
63
+ '"imap_mag_l1b-cal_20250103-20250104_v002.cdf"'
64
+ "]"
65
+ "},"
66
+ "{"
67
+ '"type": "science",'
68
+ '"files": ['
69
+ '"imap_mag_l0_raw_20240430_v001.cdf",'
70
+ "]"
71
+ "}"
72
+ "]"
45
73
  ),
46
74
  "--data-level",
47
75
  "l1a",
48
76
  "--start-date",
49
77
  "20240430",
50
- "--end-date",
51
- "20240501",
78
+ "--repointing",
79
+ "repoint12345",
52
80
  "--version",
53
81
  "v001",
54
82
  "--upload-to-sdc",
@@ -60,18 +88,25 @@ def test_main(mock_instrument):
60
88
 
61
89
 
62
90
  @pytest.mark.parametrize(
63
- "instrument, data_level, raises_value_error",
91
+ "instrument, data_level, start_date, repointing, raises_value_error",
64
92
  [
65
- ("mag", "l1a", ""),
66
- ("foo", "l1a", "foo is not in the supported .*"),
67
- ("codice", "l1z", "l1z is not a supported .*"),
93
+ ("mag", "l1a", "20250101", None, ""),
94
+ ("foo", "l1a", None, None, "foo is not in the supported .*"),
95
+ ("codice", "l1z", None, None, "l1z is not a supported .*"),
96
+ ("glows", "l1a", None, "repoint12345", ""),
97
+ ("glows", "l1a", None, "12345", ".* not a valid repointing.*"),
98
+ ("glows", "l1a", "2000001", None, ".* not a valid date.*"),
68
99
  ],
69
100
  )
70
- def test_validate_args(instrument, data_level, raises_value_error):
101
+ def test_validate_args(
102
+ instrument, data_level, start_date, repointing, raises_value_error
103
+ ):
71
104
  """Test coverage for imap_processing.cli._validate_args()"""
72
105
  args = mock.Mock
73
106
  args.instrument = instrument
74
107
  args.data_level = data_level
108
+ args.start_date = start_date
109
+ args.repointing = repointing
75
110
 
76
111
  if raises_value_error:
77
112
  with pytest.raises(ValueError, match=raises_value_error):
@@ -85,90 +120,139 @@ def test_codice(mock_codice_l1a, mock_instrument_dependencies):
85
120
  """Test coverage for cli.CoDICE class"""
86
121
 
87
122
  test_dataset = xr.Dataset({}, attrs={"cdf_filename": "file0"})
88
-
123
+ input_collection = ProcessingInputCollection(
124
+ ScienceInput("imap_codice_l0_raw_20230822_v001.pkts")
125
+ )
89
126
  mocks = mock_instrument_dependencies
90
127
  mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
91
128
  mocks["mock_download"].return_value = "file0"
92
- mock_codice_l1a.return_value = test_dataset
129
+ mock_codice_l1a.return_value = [test_dataset]
93
130
  mocks["mock_write_cdf"].side_effect = ["/path/to/file0"]
131
+ mocks["mock_pre_processing"].return_value = input_collection
94
132
 
95
133
  dependency_str = (
96
- "[{"
97
- "'instrument': 'codice',"
98
- "'data_level': 'l0',"
99
- "'descriptor': 'hskp',"
100
- "'version': 'v001',"
101
- "'start_date': '20230822'"
102
- "}]"
103
- )
104
- instrument = Codice(
105
- "l1a", "hskp", dependency_str, "20230822", "20230822", "v001", True
134
+ '[{"type": "science","files": ["imap_codice_l0_raw_20230822_v001.pkts"]}]'
106
135
  )
136
+
137
+ instrument = Codice("l1a", "hskp", dependency_str, "20230822", None, "v001", True)
138
+
107
139
  instrument.process()
108
- assert mocks["mock_query"].call_count == 1
109
- assert mocks["mock_download"].call_count == 1
110
140
  assert mock_codice_l1a.call_count == 1
111
141
  assert mocks["mock_upload"].call_count == 1
112
142
 
113
143
 
114
- @pytest.mark.parametrize("data_level, n_prods", [("l1a", 2), ("l1b", 1), ("l1c", 1)])
115
- def test_hi_l1(mock_instrument_dependencies, data_level, n_prods):
144
+ def test_repointing_file_creation(mock_instrument_dependencies):
145
+ test_datasets = [xr.Dataset({}, attrs={"cdf_filename": "file0"})]
146
+ input_collection = ProcessingInputCollection(
147
+ ScienceInput("imap_glows_l0_raw_20230822-repoint00001_v001.pkts")
148
+ )
149
+ dependency_str = (
150
+ '[{"type": "science","files": '
151
+ '["imap_glows_l0_raw_20230822-repoint00001_v001.pkts"]}]'
152
+ )
153
+ instrument = Glows(
154
+ "l1a", "hist", dependency_str, None, "repoint00002", "v001", False
155
+ )
156
+
157
+ mock_instrument_dependencies["mock_write_cdf"].side_effect = ["/path/to/file0"]
158
+
159
+ # Call the method that uses write_cdf
160
+ instrument.post_processing(test_datasets, input_collection)
161
+
162
+ # Assert that write_cdf was called with the expected arguments
163
+ assert mock_instrument_dependencies["mock_write_cdf"].call_count == 1
164
+ assert (
165
+ mock_instrument_dependencies["mock_write_cdf"]
166
+ .call_args[0][0]
167
+ .attrs.get("Repointing", None)
168
+ == "repoint00002"
169
+ )
170
+
171
+
172
+ @pytest.mark.parametrize(
173
+ "data_level, science_input, n_prods",
174
+ [
175
+ ("l1a", ["imap_hi_l0_raw_20231212_v001.pkts"], 2),
176
+ ("l1b", ["imap_hi_l1a_90sensor-de_20241105_v001.cdf"], 1),
177
+ ("l1b", ["imap_hi_l0_raw_20231212_v001.pkts"], 2),
178
+ ("l1c", ["imap_hi_l1b_45sensor-de_20250415_v001.cdf"], 1),
179
+ ],
180
+ )
181
+ def test_hi_l1(mock_instrument_dependencies, data_level, science_input, n_prods):
116
182
  """Test coverage for cli.Hi class"""
117
183
  mocks = mock_instrument_dependencies
118
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
119
- mocks["mock_download"].return_value = "file0"
120
- mocks["mock_write_cdf"].side_effect = ["/path/to/file0", "/path/to/file1"]
184
+ mocks["mock_write_cdf"].side_effect = ["/path/to/file0"] * n_prods
121
185
  mocks["mock_load_cdf"].return_value = xr.Dataset()
186
+ input_collection = ProcessingInputCollection(
187
+ *[ScienceInput(file) for file in science_input]
188
+ )
189
+ mocks["mock_pre_processing"].return_value = input_collection
122
190
 
123
191
  # patch autospec=True makes this test confirm that the function call in cli.py
124
192
  # matches the mocked function signature.
125
193
  with mock.patch(
126
194
  f"imap_processing.cli.hi_{data_level}.hi_{data_level}", autospec=True
127
195
  ) as mock_hi:
128
- mock_hi.return_value = [f"{data_level}_file{n}" for n in range(n_prods)]
196
+ mock_hi.return_value = [xr.Dataset()] * n_prods
129
197
  dependency_str = (
130
- "[{"
131
- "'instrument': 'lo',"
132
- "'data_level': 'l0',"
133
- "'descriptor': 'sci',"
134
- "'version': 'v00-01',"
135
- "'start_date': '20231212'"
136
- "}]"
198
+ '[{"type": "science","files": ["imap_hi_l0_raw_20231212_v001.pkts"]}]'
137
199
  )
138
200
  instrument = Hi(
139
201
  data_level, "sci", dependency_str, "20231212", "20231213", "v005", True
140
202
  )
203
+
141
204
  instrument.process()
142
- assert mocks["mock_query"].call_count == 1
143
- assert mocks["mock_download"].call_count == 1
144
205
  assert mock_hi.call_count == 1
145
206
  assert mocks["mock_upload"].call_count == n_prods
146
207
 
147
208
 
209
+ @mock.patch("imap_processing.cli.quaternions.process_quaternions", autospec=True)
210
+ def test_spacecraft(mock_spacecraft_l1a, mock_instrument_dependencies):
211
+ """Test coverage for cli.Spacecraft class"""
212
+
213
+ test_dataset = xr.Dataset({}, attrs={"cdf_filename": "file0"})
214
+ input_collection = ProcessingInputCollection(
215
+ ScienceInput("imap_spacecraft_l0_raw_20230822_v001.pkts")
216
+ )
217
+ mocks = mock_instrument_dependencies
218
+ mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
219
+ mocks["mock_download"].return_value = "file0"
220
+ mock_spacecraft_l1a.return_value = [test_dataset]
221
+ mocks["mock_write_cdf"].side_effect = ["/path/to/file0"]
222
+ mocks["mock_pre_processing"].return_value = input_collection
223
+
224
+ dependency_str = (
225
+ '[{"type": "science","files": ["imap_spacecraft_l0_raw_20230822_v001.pkts"]}]'
226
+ )
227
+
228
+ instrument = Spacecraft(
229
+ "l1a", "quaternions", dependency_str, "20230822", "20230822", "v001", True
230
+ )
231
+
232
+ instrument.process()
233
+ assert mock_spacecraft_l1a.call_count == 1
234
+ assert mocks["mock_upload"].call_count == 1
235
+
236
+
148
237
  @mock.patch("imap_processing.cli.ultra_l1a.ultra_l1a")
149
238
  def test_ultra_l1a(mock_ultra_l1a, mock_instrument_dependencies):
150
239
  """Test coverage for cli.Ultra class with l1a data level"""
151
240
  mocks = mock_instrument_dependencies
152
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
153
- mocks["mock_download"].return_value = "dependency0"
154
- mock_ultra_l1a.return_value = ["l1a_dataset0", "l1a_dataset1"]
241
+ mock_ultra_l1a.return_value = [xr.Dataset(), xr.Dataset()]
155
242
  mocks["mock_write_cdf"].side_effect = ["/path/to/product0", "/path/to/product1"]
243
+ input_collection = ProcessingInputCollection(
244
+ ScienceInput("imap_ultra_l0_raw_20240207_v001.pkts")
245
+ )
246
+ mocks["mock_pre_processing"].return_value = input_collection
156
247
 
157
248
  dependency_str = (
158
- "[{"
159
- "'instrument': 'ultra',"
160
- "'data_level': 'l0',"
161
- "'descriptor': 'raw',"
162
- "'version': 'v001',"
163
- "'start_date': '20240207'"
164
- "}]"
249
+ '[{"type": "science","files": ["imap_ultra_l0_raw_20240207_v001.pkts"]}]'
165
250
  )
166
251
  instrument = Ultra(
167
252
  "l1a", "raw", dependency_str, "20240207", "20240208", "v001", True
168
253
  )
254
+
169
255
  instrument.process()
170
- assert mocks["mock_query"].call_count == 1
171
- assert mocks["mock_download"].call_count == 1
172
256
  assert mock_ultra_l1a.call_count == 1
173
257
  assert mocks["mock_upload"].call_count == 2
174
258
 
@@ -177,14 +261,17 @@ def test_ultra_l1a(mock_ultra_l1a, mock_instrument_dependencies):
177
261
  def test_ultra_l1b(mock_ultra_l1b, mock_instrument_dependencies):
178
262
  """Test coverage for cli.Ultra class with l1b data level"""
179
263
  mocks = mock_instrument_dependencies
180
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
181
264
  mocks["mock_download"].return_value = "dependency0"
182
- mock_ultra_l1b.return_value = ["l1b_dataset0", "l1b_dataset1"]
265
+ mock_ultra_l1b.return_value = [xr.Dataset(), xr.Dataset()]
183
266
  mocks["mock_write_cdf"].side_effect = ["/path/to/product0", "/path/to/product1"]
267
+ input_collection = ProcessingInputCollection(
268
+ ScienceInput("imap_ultra_l1a_de_20240207_v001.cdf")
269
+ )
270
+ mocks["mock_pre_processing"].return_value = input_collection
184
271
 
185
272
  instrument = Ultra("l1b", "de", "[]", "20240207", "20240208", "v001", True)
273
+
186
274
  instrument.process()
187
- assert mocks["mock_query"].call_count == 0
188
275
  assert mocks["mock_download"].call_count == 0
189
276
  assert mock_ultra_l1b.call_count == 1
190
277
  assert mocks["mock_upload"].call_count == 2
@@ -194,15 +281,16 @@ def test_ultra_l1b(mock_ultra_l1b, mock_instrument_dependencies):
194
281
  def test_ultra_l1c(mock_ultra_l1c, mock_instrument_dependencies):
195
282
  """Test coverage for cli.Ultra class with l1c data level"""
196
283
  mocks = mock_instrument_dependencies
197
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
198
- mocks["mock_download"].return_value = "dependency0"
199
- mock_ultra_l1c.return_value = ["l1c_dataset0", "l1c_dataset1"]
284
+ mock_ultra_l1c.return_value = [xr.Dataset(), xr.Dataset()]
200
285
  mocks["mock_write_cdf"].side_effect = ["/path/to/product0", "/path/to/product1"]
286
+ input_collection = ProcessingInputCollection(
287
+ ScienceInput("imap_ultra_l1b_de_20240207_v001.cdf")
288
+ )
289
+ mocks["mock_pre_processing"].return_value = input_collection
201
290
 
202
291
  instrument = Ultra("l1c", "pset", "[]", "20240207", "20240208", "v001", True)
292
+
203
293
  instrument.process()
204
- assert mocks["mock_query"].call_count == 0
205
- assert mocks["mock_download"].call_count == 0
206
294
  assert mock_ultra_l1c.call_count == 1
207
295
  assert mocks["mock_upload"].call_count == 2
208
296
 
@@ -211,24 +299,19 @@ def test_ultra_l1c(mock_ultra_l1c, mock_instrument_dependencies):
211
299
  def test_hit_l1a(mock_hit_l1a, mock_instrument_dependencies):
212
300
  """Test coverage for cli.Hit class with l1a data level"""
213
301
  mocks = mock_instrument_dependencies
214
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
215
- mocks["mock_download"].return_value = "dependency0"
216
- mock_hit_l1a.return_value = ["l1a_dataset0", "l1a_dataset1"]
302
+ mock_hit_l1a.return_value = [xr.Dataset(), xr.Dataset()]
217
303
  mocks["mock_write_cdf"].side_effect = ["/path/to/product0", "/path/to/product1"]
304
+ input_collection = ProcessingInputCollection(
305
+ ScienceInput("imap_hit_l0_raw_20100105_v001.pkts")
306
+ )
307
+ mocks["mock_pre_processing"].return_value = input_collection
218
308
 
219
309
  dependency_str = (
220
- "[{"
221
- "'instrument': 'hit',"
222
- "'data_level': 'l0',"
223
- "'descriptor': 'raw',"
224
- "'version': 'v001',"
225
- "'start_date': '20100105'"
226
- "}]"
310
+ '[{"type": "science","files": ["imap_hit_l0_raw_20100105_v001.pkts"]}]'
227
311
  )
228
312
  instrument = Hit("l1a", "raw", dependency_str, "20100105", "20100101", "v001", True)
313
+
229
314
  instrument.process()
230
- assert mocks["mock_query"].call_count == 1
231
- assert mocks["mock_download"].call_count == 1
232
315
  assert mock_hit_l1a.call_count == 1
233
316
  assert mocks["mock_upload"].call_count == 2
234
317
 
@@ -237,25 +320,25 @@ def test_hit_l1a(mock_hit_l1a, mock_instrument_dependencies):
237
320
  def test_post_processing(mock_swe_l1a, mock_instrument_dependencies):
238
321
  """Test coverage for post processing"""
239
322
  mocks = mock_instrument_dependencies
240
- mocks["mock_query"].return_value = [{"file_path": "/path/to/file0"}]
241
323
  mocks["mock_download"].return_value = "dependency0"
242
- # Return empty list to simulate no data to write
243
- mock_swe_l1a.return_value = []
324
+ test_ds = xr.Dataset()
325
+ mock_swe_l1a.return_value = [test_ds]
326
+ input_collection = ProcessingInputCollection(
327
+ ScienceInput("imap_swe_l0_raw_20100105_v001.pkts")
328
+ )
329
+ mocks["mock_pre_processing"].return_value = input_collection
244
330
 
245
331
  dependency_str = (
246
- "[{"
247
- "'instrument': 'hit',"
248
- "'data_level': 'l0',"
249
- "'descriptor': 'raw',"
250
- "'version': 'v001',"
251
- "'start_date': '20100105'"
252
- "}]"
332
+ '[{"type": "science","files": ["imap_swe_l0_raw_20100105_v001.pkts"]}]'
253
333
  )
254
- instrument = Swe("l1a", "raw", dependency_str, "20100105", "20100101", "v001", True)
334
+ instrument = Swe("l1a", "raw", dependency_str, "20100105", None, "v001", True)
255
335
 
256
336
  # This function calls both the instrument.do_processing() and
257
337
  # instrument.post_processing()
258
338
  instrument.process()
259
339
  assert mock_swe_l1a.call_count == 1
260
- # This test is testing that no upload happened
261
- assert mocks["mock_upload"].call_count == 0
340
+ # This test is testing that one file was uploaded
341
+ assert mocks["mock_upload"].call_count == 1
342
+
343
+ # Test parent injection
344
+ assert test_ds.attrs["Parents"] == ["imap_swe_l0_raw_20100105_v001.pkts"]
@@ -225,7 +225,8 @@ def test_packet_file_to_datasets_flat_definition():
225
225
  test_file = "tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts"
226
226
  packet_files = imap_module_directory / test_file
227
227
  packet_definition = (
228
- imap_module_directory / "idex/packet_definitions/idex_packet_definition.xml"
228
+ imap_module_directory
229
+ / "idex/packet_definitions/idex_science_packet_definition.xml"
229
230
  )
230
231
  with pytest.raises(ValueError, match="Packet fields do not match"):
231
232
  utils.packet_file_to_datasets(packet_files, packet_definition)
@@ -14,7 +14,7 @@ DEFAULT_RECT_SPACING_DEG_L1C = 0.5
14
14
  DEFAULT_HEALPIX_NSIDE_L1C = 128
15
15
 
16
16
 
17
- def mock_l1c_pset_product_rectangular( # noqa: PLR0913
17
+ def mock_l1c_pset_product_rectangular(
18
18
  spacing_deg: float = DEFAULT_RECT_SPACING_DEG_L1C,
19
19
  stripe_center_lat: int = 0,
20
20
  width_scale: float = 10.0,
@@ -136,18 +136,23 @@ def mock_l1c_pset_product_rectangular( # noqa: PLR0913
136
136
  ensure_spice(spice.unitim, time_kernels_only=True)(tdb_et, "ET", "TT") * 1e9
137
137
  )
138
138
 
139
+ logical_source = f"imap_ultra_l1c_{head}sensor-spacecraftpset"
140
+ logical_file_id = (
141
+ f"{logical_source}_{timestr[:4]}{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
142
+ )
143
+
139
144
  pset_product = xr.Dataset(
140
145
  {
141
146
  "counts": (
142
147
  [
143
148
  CoordNames.TIME.value,
144
- CoordNames.ENERGY.value,
149
+ CoordNames.ENERGY_ULTRA.value,
145
150
  CoordNames.AZIMUTH_L1C.value,
146
151
  CoordNames.ELEVATION_L1C.value,
147
152
  ],
148
153
  counts,
149
154
  ),
150
- "exposure_time": (
155
+ "exposure_factor": (
151
156
  [
152
157
  CoordNames.TIME.value,
153
158
  CoordNames.AZIMUTH_L1C.value,
@@ -158,7 +163,7 @@ def mock_l1c_pset_product_rectangular( # noqa: PLR0913
158
163
  "sensitivity": (
159
164
  [
160
165
  CoordNames.TIME.value,
161
- CoordNames.ENERGY.value,
166
+ CoordNames.ENERGY_ULTRA.value,
162
167
  CoordNames.AZIMUTH_L1C.value,
163
168
  CoordNames.ELEVATION_L1C.value,
164
169
  ],
@@ -169,7 +174,7 @@ def mock_l1c_pset_product_rectangular( # noqa: PLR0913
169
174
  CoordNames.TIME.value: [
170
175
  tt_j2000ns,
171
176
  ],
172
- CoordNames.ENERGY.value: energy_bin_midpoints,
177
+ CoordNames.ENERGY_ULTRA.value: energy_bin_midpoints,
173
178
  CoordNames.AZIMUTH_L1C.value: np.arange(
174
179
  0 + spacing_deg / 2, 360, spacing_deg
175
180
  ),
@@ -178,17 +183,16 @@ def mock_l1c_pset_product_rectangular( # noqa: PLR0913
178
183
  ),
179
184
  },
180
185
  attrs={
181
- "Logical_file_id": (
182
- f"imap_ultra_l1c_{head}sensor-pset_{timestr[:4]}"
183
- f"{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
184
- )
186
+ "Logical_file_id": logical_file_id,
187
+ "Logical_source": logical_source,
188
+ "Data_version": "001",
185
189
  },
186
190
  )
187
191
 
188
192
  return pset_product
189
193
 
190
194
 
191
- def mock_l1c_pset_product_healpix( # noqa: PLR0913
195
+ def mock_l1c_pset_product_healpix(
192
196
  nside: int = DEFAULT_HEALPIX_NSIDE_L1C,
193
197
  stripe_center_lat: int = 0,
194
198
  width_scale: float = 10.0,
@@ -251,7 +255,8 @@ def mock_l1c_pset_product_healpix( # noqa: PLR0913
251
255
  head : str, optional
252
256
  The sensor head (either '45' or '90') (default is '45').
253
257
  """
254
- _, energy_bin_midpoints, _ = build_energy_bins()
258
+ energy_intervals, energy_bin_midpoints, _ = build_energy_bins()
259
+ energy_bin_delta = np.diff(energy_intervals, axis=1).squeeze()
255
260
  num_energy_bins = len(energy_bin_midpoints)
256
261
  npix = hp.nside2npix(nside)
257
262
  counts = np.zeros(npix)
@@ -277,8 +282,13 @@ def mock_l1c_pset_product_healpix( # noqa: PLR0913
277
282
  ]
278
283
  )
279
284
 
280
- # Generate exposure times using gaussian distribution
281
- exposure_time = peak_exposure * (prob_scaling_factor / prob_scaling_factor.max())
285
+ # Generate exposure times using gaussian distribution, but wider
286
+ prob_scaling_factor_exptime = counts_scaling_params[1] * np.exp(
287
+ -(lat_diff**2) / (2 * (3 * width_scale) ** 2)
288
+ )
289
+ exposure_time = peak_exposure * (
290
+ prob_scaling_factor_exptime / prob_scaling_factor_exptime.max()
291
+ )
282
292
 
283
293
  # Ensure counts are integers
284
294
  counts = counts.astype(int)
@@ -292,24 +302,37 @@ def mock_l1c_pset_product_healpix( # noqa: PLR0913
292
302
  ensure_spice(spice.unitim, time_kernels_only=True)(tdb_et, "ET", "TT") * 1e9
293
303
  )
294
304
 
305
+ logical_source = f"imap_ultra_l1c_{head}sensor-spacecraftpset"
306
+ logical_file_id = (
307
+ f"{logical_source}_{timestr[:4]}{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
308
+ )
309
+
295
310
  pset_product = xr.Dataset(
296
311
  {
297
312
  "counts": (
298
313
  [
299
314
  CoordNames.TIME.value,
300
- CoordNames.ENERGY.value,
315
+ CoordNames.ENERGY_ULTRA.value,
301
316
  CoordNames.HEALPIX_INDEX.value,
302
317
  ],
303
318
  counts,
304
319
  ),
305
- "exposure_time": (
320
+ "background_rates": (
321
+ [
322
+ CoordNames.TIME.value,
323
+ CoordNames.ENERGY_ULTRA.value,
324
+ CoordNames.HEALPIX_INDEX.value,
325
+ ],
326
+ np.full_like(counts, 0.05, dtype=float),
327
+ ),
328
+ "exposure_factor": (
306
329
  [CoordNames.HEALPIX_INDEX.value],
307
330
  exposure_time,
308
331
  ),
309
332
  "sensitivity": (
310
333
  [
311
334
  CoordNames.TIME.value,
312
- CoordNames.ENERGY.value,
335
+ CoordNames.ENERGY_ULTRA.value,
313
336
  CoordNames.HEALPIX_INDEX.value,
314
337
  ],
315
338
  sensitivity,
@@ -322,19 +345,24 @@ def mock_l1c_pset_product_healpix( # noqa: PLR0913
322
345
  [CoordNames.HEALPIX_INDEX.value],
323
346
  lat_pix,
324
347
  ),
348
+ "energy_bin_delta": (
349
+ [CoordNames.ENERGY_ULTRA.value],
350
+ energy_bin_delta,
351
+ ),
325
352
  },
326
353
  coords={
327
354
  CoordNames.TIME.value: [
328
355
  tt_j2000ns,
329
356
  ],
330
- CoordNames.ENERGY.value: energy_bin_midpoints,
357
+ CoordNames.ENERGY_ULTRA.value: xr.DataArray(
358
+ energy_bin_midpoints, dims=(CoordNames.ENERGY_ULTRA.value,)
359
+ ),
331
360
  CoordNames.HEALPIX_INDEX.value: pix_indices,
332
361
  },
333
362
  attrs={
334
- "Logical_file_id": (
335
- f"imap_ultra_l1c_{head}sensor-pset_{timestr[:4]}"
336
- f"{timestr[5:7]}{timestr[8:10]}-repointNNNNN_vNNN"
337
- )
363
+ "Logical_file_id": logical_file_id,
364
+ "Logical_source": logical_source,
365
+ "Data_version": "v001",
338
366
  },
339
367
  )
340
368