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
@@ -4,8 +4,10 @@ import numpy as np
4
4
  import pandas as pd
5
5
  import pytest
6
6
 
7
+ from imap_processing import imap_module_directory
7
8
  from imap_processing.spice.spin import get_spin_data
8
9
  from imap_processing.ultra.constants import UltraConstants
10
+ from imap_processing.ultra.l1b.lookup_utils import get_angular_profiles
9
11
  from imap_processing.ultra.l1b.ultra_l1b_extended import (
10
12
  CoinType,
11
13
  StartType,
@@ -16,32 +18,35 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
16
18
  get_ctof,
17
19
  get_de_energy_kev,
18
20
  get_de_velocity,
21
+ get_efficiency,
19
22
  get_energy_pulse_height,
20
23
  get_energy_ssd,
21
24
  get_eventtimes,
22
25
  get_front_x_position,
23
26
  get_front_y_position,
27
+ get_fwhm,
24
28
  get_path_length,
25
29
  get_ph_tof_and_back_positions,
26
30
  get_phi_theta,
27
31
  get_ssd_back_position_and_tof_offset,
28
32
  get_ssd_tof,
33
+ interpolate_fwhm,
29
34
  )
30
35
 
36
+ TEST_PATH = imap_module_directory / "tests" / "ultra" / "data" / "l1"
31
37
 
32
- @pytest.fixture()
38
+
39
+ @pytest.fixture
33
40
  def test_fixture(de_dataset, events_fsw_comparison_theta_0):
34
41
  """Fixture to compute and return yf and related data."""
35
42
  # Remove start_type with fill values
36
- de_dataset = de_dataset.where(
37
- de_dataset["START_TYPE"] != np.iinfo(np.int64).min, drop=True
38
- )
43
+ de_dataset = de_dataset.where(de_dataset["start_type"] != 255, drop=True)
39
44
 
40
45
  df = pd.read_csv(events_fsw_comparison_theta_0)
41
46
  df_filt = df[df["StartType"] != -1]
42
47
 
43
48
  d, yf = get_front_y_position(
44
- de_dataset["START_TYPE"].data, df_filt.Yb.values.astype("float")
49
+ de_dataset["start_type"].data, df_filt.Yb.values.astype("float")
45
50
  )
46
51
 
47
52
  return df_filt, d, yf, de_dataset
@@ -55,8 +60,9 @@ def test_get_front_x_position(
55
60
  df_filt, _, _, de_dataset = test_fixture
56
61
 
57
62
  xf = get_front_x_position(
58
- de_dataset["START_TYPE"].data,
59
- de_dataset["START_POS_TDC"].data,
63
+ de_dataset["start_type"].data,
64
+ de_dataset["start_pos_tdc"].data,
65
+ "ultra45",
60
66
  )
61
67
 
62
68
  assert xf == pytest.approx(df_filt["Xf"].astype("float"), 1e-5)
@@ -96,7 +102,7 @@ def test_get_ph_tof_and_back_positions(
96
102
  )
97
103
 
98
104
  ph_indices = np.nonzero(
99
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
105
+ np.isin(de_dataset["stop_type"], [StopType.Top.value, StopType.Bottom.value])
100
106
  )[0]
101
107
 
102
108
  selected_rows = df_filt.iloc[ph_indices]
@@ -114,7 +120,9 @@ def test_get_ssd_back_position_and_tof_offset(
114
120
  ):
115
121
  """Tests get_ssd_back_position function."""
116
122
  _, _, _, de_dataset = test_fixture
117
- yb, tof_offset, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
123
+ yb, tof_offset, ssd_number = get_ssd_back_position_and_tof_offset(
124
+ de_dataset, "ultra45"
125
+ )
118
126
 
119
127
  df = pd.read_csv(events_fsw_comparison_theta_0)
120
128
  df_filt = df[(df["StartType"] != -1) & (df["StopType"] >= 8)]
@@ -159,7 +167,7 @@ def test_get_coincidence_positions(test_fixture):
159
167
 
160
168
  # Filter for stop type.
161
169
  indices = np.nonzero(
162
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
170
+ np.isin(de_dataset["stop_type"], [StopType.Top.value, StopType.Bottom.value])
163
171
  )[0]
164
172
  de_filtered = de_dataset.isel(epoch=indices)
165
173
  rows = df_filt.iloc[indices]
@@ -182,17 +190,17 @@ def test_calculate_etof_xc(test_fixture):
182
190
  )
183
191
  # Filter based on STOP_TYPE.
184
192
  indices = np.nonzero(
185
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
193
+ np.isin(de_dataset["stop_type"], [StopType.Top.value, StopType.Bottom.value])
186
194
  )[0]
187
195
  de_filtered = de_dataset.isel(epoch=indices)
188
196
  df_filtered = df_filt.iloc[indices]
189
197
 
190
198
  # Filter for COIN_TYPE Top and Bottom.
191
- index_top = np.nonzero(np.isin(de_filtered["COIN_TYPE"], CoinType.Top.value))[0]
199
+ index_top = np.nonzero(np.isin(de_filtered["coin_type"], CoinType.Top.value))[0]
192
200
  de_top = de_filtered.isel(epoch=index_top)
193
201
  df_top = df_filtered.iloc[index_top]
194
202
 
195
- index_bottom = np.nonzero(np.isin(de_filtered["COIN_TYPE"], CoinType.Bottom.value))[
203
+ index_bottom = np.nonzero(np.isin(de_filtered["coin_type"], CoinType.Bottom.value))[
196
204
  0
197
205
  ]
198
206
  de_bottom = de_filtered.isel(epoch=index_bottom)
@@ -231,7 +239,7 @@ def test_get_de_velocity(test_fixture):
231
239
  for col in ["Xf", "Yf", "Xb", "Yb", "d", "TOF"]
232
240
  )
233
241
 
234
- v = get_de_velocity(
242
+ v, vhat, r = get_de_velocity(
235
243
  (test_xf, test_yf),
236
244
  (test_xb, test_yb),
237
245
  test_d,
@@ -258,6 +266,42 @@ def test_get_de_velocity(test_fixture):
258
266
  atol=1e-01,
259
267
  rtol=0,
260
268
  )
269
+ np.testing.assert_allclose(
270
+ vhat[test_tof > 0][:, 0],
271
+ df_ph["vhatX"].astype("float").values[test_tof > 0],
272
+ atol=1e-01,
273
+ rtol=0,
274
+ )
275
+ np.testing.assert_allclose(
276
+ vhat[test_tof > 0][:, 1],
277
+ df_ph["vhatY"].astype("float").values[test_tof > 0],
278
+ atol=1e-01,
279
+ rtol=0,
280
+ )
281
+ np.testing.assert_allclose(
282
+ vhat[test_tof > 0][:, 2],
283
+ df_ph["vhatZ"].astype("float").values[test_tof > 0],
284
+ atol=1e-01,
285
+ rtol=0,
286
+ )
287
+ np.testing.assert_allclose(
288
+ r[test_tof > 0][:, 0],
289
+ -df_ph["vhatX"].astype("float").values[test_tof > 0],
290
+ atol=1e-01,
291
+ rtol=0,
292
+ )
293
+ np.testing.assert_allclose(
294
+ r[test_tof > 0][:, 1],
295
+ -df_ph["vhatY"].astype("float").values[test_tof > 0],
296
+ atol=1e-01,
297
+ rtol=0,
298
+ )
299
+ np.testing.assert_allclose(
300
+ r[test_tof > 0][:, 2],
301
+ -df_ph["vhatZ"].astype("float").values[test_tof > 0],
302
+ atol=1e-01,
303
+ rtol=0,
304
+ )
261
305
 
262
306
 
263
307
  def test_get_ssd_tof(test_fixture):
@@ -266,7 +310,7 @@ def test_get_ssd_tof(test_fixture):
266
310
  df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
267
311
  test_xf = df_filt["Xf"].astype("float").values
268
312
 
269
- ssd_tof = get_ssd_tof(de_dataset, test_xf)
313
+ ssd_tof = get_ssd_tof(de_dataset, test_xf, "ultra45")
270
314
 
271
315
  np.testing.assert_allclose(
272
316
  ssd_tof, df_ssd["TOF"].astype("float"), atol=1e-05, rtol=0
@@ -289,7 +333,7 @@ def test_get_de_energy_kev(test_fixture):
289
333
  for col in ["Xf", "Yf", "Xb", "Yb", "d", "TOF"]
290
334
  )
291
335
 
292
- v = get_de_velocity(
336
+ v, v_hat, r_hat = get_de_velocity(
293
337
  (test_xf, test_yf),
294
338
  (test_xb, test_yb),
295
339
  test_d,
@@ -297,7 +341,7 @@ def test_get_de_energy_kev(test_fixture):
297
341
  )
298
342
 
299
343
  energy = get_de_energy_kev(v, species_bin_ph)
300
- index_hydrogen = np.where(species_bin_ph == "H")
344
+ index_hydrogen = np.where(species_bin_ph == 1)
301
345
  actual_energy = energy[index_hydrogen[0]]
302
346
  expected_energy = df_ph["energy_revised"].astype("float")
303
347
 
@@ -308,7 +352,7 @@ def test_get_energy_ssd(test_fixture):
308
352
  """Tests get_energy_ssd function."""
309
353
  df_filt, _, _, de_dataset = test_fixture
310
354
  df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
311
- _, _, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
355
+ _, _, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset, "ultra45")
312
356
  energy = get_energy_ssd(de_dataset, ssd_number)
313
357
  test_energy = df_ssd["Energy"].astype("float")
314
358
 
@@ -320,14 +364,18 @@ def test_get_energy_pulse_height(test_fixture):
320
364
  df_filt, _, _, de_dataset = test_fixture
321
365
  df_ph = df_filt[np.isin(df_filt["StopType"], [StopType.PH.value])]
322
366
  ph_indices = np.nonzero(
323
- np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
367
+ np.isin(de_dataset["stop_type"], [StopType.Top.value, StopType.Bottom.value])
324
368
  )[0]
325
369
 
326
370
  test_xb = df_filt["Xb"].astype("float").values
327
371
  test_yb = df_filt["Yb"].astype("float").values
328
372
 
329
373
  energy = get_energy_pulse_height(
330
- de_dataset["STOP_TYPE"].data, de_dataset["ENERGY_PH"].data, test_xb, test_yb
374
+ de_dataset["stop_type"].data,
375
+ de_dataset["energy_ph"].data,
376
+ test_xb,
377
+ test_yb,
378
+ "ultra45",
331
379
  )
332
380
  test_energy = df_ph["Energy"].astype("float")
333
381
 
@@ -386,13 +434,13 @@ def test_determine_species(test_fixture):
386
434
  "SSD",
387
435
  )
388
436
 
389
- h_indices_ph = np.where(species_bin_ph == "H")[0]
437
+ h_indices_ph = np.where(species_bin_ph == 1)[0]
390
438
  ctof_indices_ph = np.where(
391
439
  (df_ph["cTOF"].astype("float") > UltraConstants.CTOF_SPECIES_MIN)
392
440
  & (df_ph["cTOF"].astype("float") < UltraConstants.CTOF_SPECIES_MAX)
393
441
  )[0]
394
442
 
395
- h_indices_ssd = np.where(species_bin_ssd == "H")[0]
443
+ h_indices_ssd = np.where(species_bin_ssd == 1)[0]
396
444
  ctof_indices_ssd = np.where(
397
445
  (df_ssd["cTOF"].astype("float") > UltraConstants.CTOF_SPECIES_MIN)
398
446
  & (df_ssd["cTOF"].astype("float") < UltraConstants.CTOF_SPECIES_MAX)
@@ -427,31 +475,117 @@ def test_get_eventtimes(test_fixture, use_fake_spin_data_for_time):
427
475
  use_fake_spin_data_for_time(0, 141 * 15)
428
476
 
429
477
  event_times, spin_starts, spin_period_sec = get_eventtimes(
430
- de_dataset["SPIN"].values, de_dataset["PHASE_ANGLE"].values
478
+ de_dataset["spin"].values, de_dataset["phase_angle"].values
431
479
  )
432
480
 
433
481
  spin_df = get_spin_data()
434
- expected_min_df = spin_df[spin_df["spin_number"] == de_dataset["SPIN"].values.min()]
435
- expected_max_df = spin_df[spin_df["spin_number"] == de_dataset["SPIN"].values.max()]
482
+ expected_min_df = spin_df[spin_df["spin_number"] == de_dataset["spin"].values.min()]
483
+ expected_max_df = spin_df[spin_df["spin_number"] == de_dataset["spin"].values.max()]
436
484
  spin_period_sec_min = expected_min_df["spin_period_sec"].values[0]
437
485
  spin_period_sec_max = expected_max_df["spin_period_sec"].values[0]
438
486
 
439
487
  spin_start_min = (
440
- expected_min_df["spin_start_sec"] + expected_min_df["spin_start_subsec"] / 1000
488
+ expected_min_df["spin_start_sec_sclk"]
489
+ + expected_min_df["spin_start_subsec_sclk"] / 1e6
441
490
  )
442
491
  spin_start_max = (
443
- expected_max_df["spin_start_sec"] + expected_max_df["spin_start_subsec"] / 1000
492
+ expected_max_df["spin_start_sec_sclk"]
493
+ + expected_max_df["spin_start_subsec_sclk"] / 1e6
444
494
  )
445
495
 
446
496
  assert spin_start_min.values[0] == spin_starts.min()
447
497
  assert spin_start_max.values[0] == spin_starts.max()
448
498
 
449
499
  event_times_min = spin_start_min.values[0] + spin_period_sec_min * (
450
- de_dataset["PHASE_ANGLE"][0] / 720
500
+ de_dataset["phase_angle"][0] / 720
451
501
  )
452
502
  event_times_max = spin_start_max.values[0] + spin_period_sec_max * (
453
- de_dataset["PHASE_ANGLE"][-1] / 720
503
+ de_dataset["phase_angle"][-1] / 720
454
504
  )
455
505
 
456
506
  assert event_times_min == event_times.min()
457
507
  assert event_times_max == event_times.max()
508
+
509
+
510
+ def test_interpolate_fwhm():
511
+ """Tests interpolate_fwhm function."""
512
+
513
+ # Test interpolation of FWHM values
514
+ test_phi = np.linspace(1, 53, 40)
515
+ test_theta = np.linspace(-44, 43, 40)
516
+ test_energy = np.full(test_theta.shape, 10)
517
+ lt_table = get_angular_profiles("left", "ultra45")
518
+
519
+ phi_interp, theta_interp = interpolate_fwhm(
520
+ lt_table, test_energy, test_phi, test_theta
521
+ )
522
+
523
+ lt_table_e10 = lt_table[lt_table.Energy == 10]
524
+ lt_table_test = lt_table_e10.sort_values("phi_degrees")
525
+ phi_fwhm_expected = np.interp(
526
+ test_phi, lt_table_test.phi_degrees, lt_table_test.phi_fwhm
527
+ )
528
+
529
+ np.testing.assert_allclose(phi_fwhm_expected, phi_interp, atol=1e-03, rtol=0)
530
+
531
+ # Test empty input
532
+ phi_interp, theta_interp = interpolate_fwhm(
533
+ lt_table, np.array([]), np.array([]), np.array([])
534
+ )
535
+
536
+ assert phi_interp.size == 0
537
+ assert theta_interp.size == 0
538
+
539
+
540
+ def test_get_fwhm():
541
+ """Tests get_fwhm function."""
542
+
543
+ test_phi = np.linspace(1, 53, 40)
544
+ test_theta = np.linspace(-44, 43, 40)
545
+ test_energy = np.full(test_phi.shape, 10)
546
+ test_start_type = np.empty(test_theta.shape, dtype=int)
547
+ test_start_type[:20] = 1 # First half -> Left
548
+ test_start_type[20:] = 2 # Second half -> Right
549
+
550
+ phi_interp, theta_interp = get_fwhm(
551
+ start_type=test_start_type,
552
+ sensor="ultra45",
553
+ energy=test_energy,
554
+ phi_inst=test_phi,
555
+ theta_inst=test_theta,
556
+ )
557
+
558
+ idx_left = test_start_type == StartType.Left.value
559
+ test_phi_left = test_phi[idx_left]
560
+
561
+ lt_table = get_angular_profiles("left", "ultra45")
562
+ lt_table_e10 = lt_table[lt_table.Energy == 10]
563
+ lt_table_sorted = lt_table_e10.sort_values("phi_degrees")
564
+
565
+ phi_expected_left = np.interp(
566
+ test_phi_left,
567
+ lt_table_sorted.phi_degrees.values,
568
+ lt_table_sorted.phi_fwhm.values,
569
+ )
570
+
571
+ np.testing.assert_allclose(
572
+ phi_interp[idx_left], phi_expected_left, atol=1e-3, rtol=0
573
+ )
574
+
575
+ assert phi_interp.shape == test_phi.shape
576
+ assert theta_interp.shape == test_theta.shape
577
+
578
+
579
+ @pytest.mark.external_test_data
580
+ def test_get_efficiency():
581
+ """Tests get_efficiency function."""
582
+
583
+ # spot check
584
+ theta = np.array([-52.7, 52.7, -52.7, -52.7])
585
+ phi = np.array([-60, 60, -60, -50])
586
+ energy = np.array([3, 80, 39.75, 7])
587
+
588
+ efficiency = get_efficiency(energy, phi, theta)
589
+ expected_efficiency = np.array([0.0593281, 0.21803386, 0.0593281, 0.0628940])
590
+
591
+ np.testing.assert_allclose(efficiency, expected_efficiency, atol=1e-03, rtol=0)
@@ -6,7 +6,7 @@ from imap_processing.ultra.l1c.ultra_l1c import ultra_l1c
6
6
  from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
7
7
 
8
8
 
9
- @pytest.fixture()
9
+ @pytest.fixture
10
10
  def mock_data_l1b_dict():
11
11
  # Create sample data for the xarray Dataset
12
12
  epoch = np.arange(
@@ -55,7 +55,7 @@ def mock_data_l1b_dict():
55
55
  return data_dict
56
56
 
57
57
 
58
- @pytest.fixture()
58
+ @pytest.fixture
59
59
  def mock_data_l1c_dict():
60
60
  epoch = np.array(
61
61
  [760591786368000000, 760591787368000000, 760591788368000000],
@@ -68,7 +68,7 @@ def mock_data_l1c_dict():
68
68
  def test_create_dataset(mock_data_l1c_dict):
69
69
  """Tests that dataset is created as expected."""
70
70
  dataset = create_dataset(
71
- mock_data_l1c_dict, "imap_ultra_l1c_45sensor-histogram", "l1c", "001"
71
+ mock_data_l1c_dict, "imap_ultra_l1c_45sensor-histogram", "l1c"
72
72
  )
73
73
 
74
74
  assert "epoch" in dataset.coords
@@ -80,7 +80,7 @@ def test_create_dataset(mock_data_l1c_dict):
80
80
 
81
81
  def test_ultra_l1c(mock_data_l1b_dict):
82
82
  """Tests that L1c data is created."""
83
- output_datasets = ultra_l1c(mock_data_l1b_dict, data_version="001")
83
+ output_datasets = ultra_l1c(mock_data_l1b_dict)
84
84
 
85
85
  assert len(output_datasets) == 1
86
86
  assert (
@@ -101,4 +101,4 @@ def test_ultra_l1c_error(mock_data_l1b_dict):
101
101
  with pytest.raises(
102
102
  ValueError, match="Data dictionary does not contain the expected keys."
103
103
  ):
104
- ultra_l1c(mock_data_l1b_dict, data_version="001")
104
+ ultra_l1c(mock_data_l1b_dict)
@@ -1,14 +1,11 @@
1
1
  "Tests pointing sets"
2
2
 
3
3
  import astropy_healpix.healpy as hp
4
- import cdflib
5
4
  import numpy as np
6
5
  import pandas as pd
7
6
  import pytest
8
- from cdflib import CDF
9
7
 
10
8
  from imap_processing import imap_module_directory
11
- from imap_processing.ena_maps.utils.spatial_utils import build_spatial_bins
12
9
  from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
13
10
  build_energy_bins,
14
11
  get_background_rates,
@@ -16,13 +13,14 @@ from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
16
13
  get_spacecraft_exposure_times,
17
14
  get_spacecraft_histogram,
18
15
  get_spacecraft_sensitivity,
16
+ grid_sensitivity,
19
17
  )
20
18
 
21
19
  BASE_PATH = imap_module_directory / "ultra" / "lookup_tables"
22
20
  TEST_PATH = imap_module_directory / "tests" / "ultra" / "data" / "l1"
23
21
 
24
22
 
25
- @pytest.fixture()
23
+ @pytest.fixture
26
24
  def test_data():
27
25
  """Test data fixture."""
28
26
  vx_sc = np.array([-186.5575, 508.5697, 508.5697, 508.5697])
@@ -98,7 +96,7 @@ def test_get_background_rates():
98
96
  assert background_rates.shape == hp.nside2npix(128)
99
97
 
100
98
 
101
- @pytest.mark.external_test_data()
99
+ @pytest.mark.external_test_data
102
100
  def test_get_spacecraft_exposure_times():
103
101
  """Test get_spacecraft_exposure_times function."""
104
102
  constant_exposure = TEST_PATH / "ultra_90_dps_exposure.csv"
@@ -113,67 +111,49 @@ def test_get_spacecraft_exposure_times():
113
111
  )
114
112
 
115
113
 
116
- @pytest.mark.external_kernel()
114
+ @pytest.mark.external_kernel
117
115
  @pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
118
116
  def test_get_helio_exposure_times():
119
117
  """Tests get_helio_exposure_times function."""
120
118
 
121
- constant_exposure = BASE_PATH / "dps_grid45_compressed.cdf"
122
119
  start_time = 829485054.185627
123
120
  end_time = 829567884.185627
124
- mid_time = np.average([start_time, end_time])
125
-
126
- with cdflib.CDF(constant_exposure) as cdf_file:
127
- sc_exposure = cdf_file.varget("dps_grid45")
128
121
 
129
- exposure_3d = get_helio_exposure_times(mid_time, sc_exposure)
130
-
131
- energy_bin_edges, energy_midpoints, _ = build_energy_bins()
132
- az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
133
- build_spatial_bins()
134
- )
122
+ mid_time = np.average([start_time, end_time])
135
123
 
136
- assert exposure_3d.shape == (
137
- len(el_bin_midpoints),
138
- len(az_bin_midpoints),
139
- len(energy_midpoints),
140
- )
124
+ constant_exposure = TEST_PATH / "ultra_90_dps_exposure.csv"
125
+ df_exposure = pd.read_csv(constant_exposure)
141
126
 
142
- cdf_files = [
143
- ("dps_exposure_helio_45_E1.cdf", "dps_exposure_helio_45_E1"),
144
- ("dps_exposure_helio_45_E12.cdf", "dps_exposure_helio_45_E12"),
145
- ("dps_exposure_helio_45_E24.cdf", "dps_exposure_helio_45_E24"),
146
- ]
127
+ helio_exposure = get_helio_exposure_times(mid_time, df_exposure)
147
128
 
148
- cdf_directory = imap_module_directory / "tests" / "ultra" / "data" / "l1"
129
+ _, energy_midpoints, _ = build_energy_bins()
149
130
 
150
- exposures = []
131
+ nside = 128
132
+ npix = hp.nside2npix(nside)
133
+ assert helio_exposure.shape == (npix, len(energy_midpoints))
151
134
 
152
- for file_name, var_name in cdf_files:
153
- file_path = cdf_directory / file_name
154
- with CDF(file_path) as cdf_file:
155
- exposure_data = cdf_file.varget(var_name)
156
- transposed_exposure = np.transpose(exposure_data, (2, 1, 0))
157
- exposures.append(transposed_exposure)
135
+ total_input = np.sum(df_exposure["Exposure Time"].values)
136
+ total_output = np.sum(helio_exposure[:, 23])
158
137
 
159
- assert np.array_equal(np.squeeze(exposures[0]), exposure_3d[:, :, 0])
160
- assert np.array_equal(np.squeeze(exposures[1]), exposure_3d[:, :, 11])
161
- assert np.array_equal(np.squeeze(exposures[2]), exposure_3d[:, :, 23])
138
+ assert np.allclose(total_input, total_output, atol=1e-6)
162
139
 
163
140
 
164
- @pytest.mark.external_test_data()
141
+ @pytest.mark.external_test_data
165
142
  def test_get_spacecraft_sensitivity():
166
143
  """Tests get_spacecraft_sensitivity function."""
167
144
  # TODO: remove below here with lookup table aux api
168
- efficiences = TEST_PATH / "Ultra_90_DPS_efficiencies_all.csv"
145
+ efficiencies = TEST_PATH / "Ultra_90_DPS_efficiencies_all.csv"
169
146
  geometric_function = TEST_PATH / "ultra_90_dps_gf.csv"
170
147
 
171
- df_efficiencies = pd.read_csv(efficiences)
148
+ df_efficiencies = pd.read_csv(efficiencies)
172
149
  df_geometric_function = pd.read_csv(geometric_function)
173
150
 
174
- sensitivity = get_spacecraft_sensitivity(df_efficiencies, df_geometric_function)
151
+ sensitivity, energy_vals, right_ascension, declination = get_spacecraft_sensitivity(
152
+ df_efficiencies, df_geometric_function
153
+ )
175
154
 
176
- assert sensitivity.shape == df_efficiencies.shape
155
+ assert sensitivity.shape == (df_efficiencies.shape[0], df_efficiencies.shape[1] - 2)
156
+ assert np.array_equal(energy_vals, np.arange(3.0, 80.5, 0.5))
177
157
 
178
158
  df_efficiencies_test = pd.DataFrame(
179
159
  {"3.0keV": [1.0, 2.0], "3.5keV": [3.0, 4.0], "4.0keV": [5.0, 6.0]}
@@ -192,3 +172,12 @@ def test_get_spacecraft_sensitivity():
192
172
  assert np.allclose(
193
173
  df_sensitivity_test.to_numpy(), expected_sensitivity.to_numpy(), atol=1e-6
194
174
  )
175
+
176
+ expected_result = sensitivity["3.0keV"].values
177
+ result = grid_sensitivity(df_efficiencies, df_geometric_function, 3.0)
178
+
179
+ assert np.allclose(result, expected_result, atol=1e-5)
180
+
181
+ # Check that out-of-bounds energy returns all NaNs
182
+ result = grid_sensitivity(df_efficiencies, df_geometric_function, 2.5)
183
+ assert np.isnan(result).all()