imap-processing 0.11.0__py3-none-any.whl → 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/__init__.py +11 -11
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/ccsds_data.py +1 -2
- imap_processing/ccsds/excel_to_xtce.py +66 -18
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +24 -40
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +934 -42
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
- imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -14
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +25 -9
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +6 -4
- imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +3 -3
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +23 -20
- imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
- imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
- imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
- imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +64 -52
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +180 -19
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +80 -17
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +32 -57
- imap_processing/cdf/utils.py +52 -38
- imap_processing/cli.py +477 -233
- imap_processing/codice/codice_l1a.py +466 -131
- imap_processing/codice/codice_l1b.py +51 -152
- imap_processing/codice/constants.py +1360 -569
- imap_processing/codice/decompress.py +2 -6
- imap_processing/ena_maps/ena_maps.py +1103 -146
- imap_processing/ena_maps/utils/coordinates.py +19 -0
- imap_processing/ena_maps/utils/map_utils.py +14 -17
- imap_processing/ena_maps/utils/spatial_utils.py +55 -52
- imap_processing/glows/l1a/glows_l1a.py +28 -99
- imap_processing/glows/l1a/glows_l1a_data.py +2 -2
- imap_processing/glows/l1b/glows_l1b.py +1 -4
- imap_processing/glows/l1b/glows_l1b_data.py +1 -3
- imap_processing/glows/l2/glows_l2.py +2 -5
- imap_processing/hi/l1a/hi_l1a.py +54 -29
- imap_processing/hi/l1a/histogram.py +0 -1
- imap_processing/hi/l1a/science_direct_event.py +6 -8
- imap_processing/hi/l1b/hi_l1b.py +111 -82
- imap_processing/hi/l1c/hi_l1c.py +416 -32
- imap_processing/hi/utils.py +58 -12
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
- imap_processing/hit/hit_utils.py +235 -5
- imap_processing/hit/l0/constants.py +20 -11
- imap_processing/hit/l0/decom_hit.py +21 -5
- imap_processing/hit/l1a/hit_l1a.py +71 -75
- imap_processing/hit/l1b/constants.py +321 -0
- imap_processing/hit/l1b/hit_l1b.py +377 -67
- imap_processing/hit/l2/constants.py +318 -0
- imap_processing/hit/l2/hit_l2.py +723 -0
- imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
- imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
- imap_processing/ialirt/l0/parse_mag.py +374 -0
- imap_processing/ialirt/l0/process_swapi.py +69 -0
- imap_processing/ialirt/l0/process_swe.py +548 -0
- imap_processing/ialirt/packet_definitions/ialirt.xml +216 -208
- imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +1 -1
- imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +1 -1
- imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
- imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +14 -14
- imap_processing/ialirt/utils/grouping.py +114 -0
- imap_processing/ialirt/utils/time.py +29 -0
- imap_processing/idex/atomic_masses.csv +22 -0
- imap_processing/idex/decode.py +2 -2
- imap_processing/idex/idex_constants.py +33 -0
- imap_processing/idex/idex_l0.py +22 -8
- imap_processing/idex/idex_l1a.py +81 -51
- imap_processing/idex/idex_l1b.py +13 -39
- imap_processing/idex/idex_l2a.py +823 -0
- imap_processing/idex/idex_l2b.py +120 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +11 -11
- imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
- imap_processing/lo/l0/lo_science.py +7 -2
- imap_processing/lo/l1a/lo_l1a.py +1 -5
- imap_processing/lo/l1b/lo_l1b.py +702 -29
- imap_processing/lo/l1b/tof_conversions.py +11 -0
- imap_processing/lo/l1c/lo_l1c.py +1 -4
- imap_processing/mag/constants.py +51 -0
- imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
- imap_processing/mag/l0/decom_mag.py +10 -3
- imap_processing/mag/l1a/mag_l1a.py +23 -19
- imap_processing/mag/l1a/mag_l1a_data.py +35 -10
- imap_processing/mag/l1b/mag_l1b.py +259 -50
- imap_processing/mag/l1c/interpolation_methods.py +388 -0
- imap_processing/mag/l1c/mag_l1c.py +621 -17
- imap_processing/mag/l2/mag_l2.py +140 -0
- imap_processing/mag/l2/mag_l2_data.py +288 -0
- imap_processing/quality_flags.py +1 -0
- imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
- imap_processing/spacecraft/quaternions.py +121 -0
- imap_processing/spice/geometry.py +19 -22
- imap_processing/spice/kernels.py +0 -276
- imap_processing/spice/pointing_frame.py +257 -0
- imap_processing/spice/repoint.py +149 -0
- imap_processing/spice/spin.py +38 -33
- imap_processing/spice/time.py +24 -0
- imap_processing/swapi/l1/swapi_l1.py +20 -12
- imap_processing/swapi/l2/swapi_l2.py +116 -5
- imap_processing/swapi/swapi_utils.py +32 -0
- imap_processing/swe/l1a/swe_l1a.py +44 -12
- imap_processing/swe/l1a/swe_science.py +13 -13
- imap_processing/swe/l1b/swe_l1b.py +898 -23
- imap_processing/swe/l2/swe_l2.py +75 -136
- imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
- imap_processing/swe/utils/swe_constants.py +64 -0
- imap_processing/swe/utils/swe_utils.py +85 -28
- imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
- imap_processing/tests/ccsds/test_excel_to_xtce.py +24 -21
- imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
- imap_processing/tests/cdf/test_utils.py +14 -16
- imap_processing/tests/codice/conftest.py +44 -33
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/test_codice_l1a.py +126 -53
- imap_processing/tests/codice/test_codice_l1b.py +6 -7
- imap_processing/tests/codice/test_decompress.py +4 -4
- imap_processing/tests/conftest.py +239 -27
- imap_processing/tests/ena_maps/conftest.py +51 -0
- imap_processing/tests/ena_maps/test_ena_maps.py +1068 -110
- imap_processing/tests/ena_maps/test_map_utils.py +66 -43
- imap_processing/tests/ena_maps/test_spatial_utils.py +17 -21
- imap_processing/tests/glows/conftest.py +10 -14
- imap_processing/tests/glows/test_glows_decom.py +4 -4
- imap_processing/tests/glows/test_glows_l1a_cdf.py +6 -27
- imap_processing/tests/glows/test_glows_l1a_data.py +6 -8
- imap_processing/tests/glows/test_glows_l1b.py +11 -11
- imap_processing/tests/glows/test_glows_l1b_data.py +5 -5
- imap_processing/tests/glows/test_glows_l2.py +2 -8
- imap_processing/tests/hi/conftest.py +1 -1
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
- imap_processing/tests/hi/test_hi_l1b.py +22 -27
- imap_processing/tests/hi/test_hi_l1c.py +249 -18
- imap_processing/tests/hi/test_l1a.py +35 -7
- imap_processing/tests/hi/test_science_direct_event.py +3 -3
- imap_processing/tests/hi/test_utils.py +24 -2
- imap_processing/tests/hit/helpers/l1_validation.py +74 -73
- imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
- imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
- imap_processing/tests/hit/test_decom_hit.py +5 -1
- imap_processing/tests/hit/test_hit_l1a.py +32 -36
- imap_processing/tests/hit/test_hit_l1b.py +300 -81
- imap_processing/tests/hit/test_hit_l2.py +716 -0
- imap_processing/tests/hit/test_hit_utils.py +184 -7
- imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
- imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
- imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
- imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
- imap_processing/tests/ialirt/data/l0/461971383-404.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971384-405.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971385-406.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971386-407.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971387-408.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971388-409.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971389-410.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971390-411.bin +0 -0
- imap_processing/tests/ialirt/data/l0/461971391-412.bin +0 -0
- imap_processing/tests/ialirt/data/l0/sample_decoded_i-alirt_data.csv +383 -0
- imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
- imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
- imap_processing/tests/ialirt/unit/test_parse_mag.py +223 -0
- imap_processing/tests/ialirt/unit/test_process_codicehi.py +3 -3
- imap_processing/tests/ialirt/unit/test_process_codicelo.py +3 -10
- imap_processing/tests/ialirt/unit/test_process_ephemeris.py +4 -4
- imap_processing/tests/ialirt/unit/test_process_hit.py +3 -3
- imap_processing/tests/ialirt/unit/test_process_swapi.py +24 -16
- imap_processing/tests/ialirt/unit/test_process_swe.py +319 -6
- imap_processing/tests/ialirt/unit/test_time.py +16 -0
- imap_processing/tests/idex/conftest.py +127 -6
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20241206_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20250108_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
- imap_processing/tests/idex/test_idex_l0.py +33 -11
- imap_processing/tests/idex/test_idex_l1a.py +92 -21
- imap_processing/tests/idex/test_idex_l1b.py +106 -27
- imap_processing/tests/idex/test_idex_l2a.py +399 -0
- imap_processing/tests/idex/test_idex_l2b.py +93 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_lo_l1a.py +3 -3
- imap_processing/tests/lo/test_lo_l1b.py +515 -6
- imap_processing/tests/lo/test_lo_l1c.py +1 -1
- imap_processing/tests/lo/test_lo_science.py +7 -7
- imap_processing/tests/lo/test_star_sensor.py +1 -1
- imap_processing/tests/mag/conftest.py +120 -2
- imap_processing/tests/mag/test_mag_decom.py +5 -4
- imap_processing/tests/mag/test_mag_l1a.py +51 -7
- imap_processing/tests/mag/test_mag_l1b.py +40 -59
- imap_processing/tests/mag/test_mag_l1c.py +354 -19
- imap_processing/tests/mag/test_mag_l2.py +130 -0
- imap_processing/tests/mag/test_mag_validation.py +247 -26
- imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-in.csv +1217 -0
- imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-magi-normal-out.csv +1857 -0
- imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-in.csv +1217 -0
- imap_processing/tests/mag/validation/L1c/T013/mag-l1b-l1c-t013-mago-normal-out.csv +1857 -0
- imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-in.csv +1217 -0
- imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-magi-normal-out.csv +1793 -0
- imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-in.csv +1217 -0
- imap_processing/tests/mag/validation/L1c/T014/mag-l1b-l1c-t014-mago-normal-out.csv +1793 -0
- imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-burst-in.csv +2561 -0
- imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-in.csv +961 -0
- imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-magi-normal-out.csv +1539 -0
- imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-in.csv +1921 -0
- imap_processing/tests/mag/validation/L1c/T015/mag-l1b-l1c-t015-mago-normal-out.csv +2499 -0
- imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-in.csv +865 -0
- imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-magi-normal-out.csv +1196 -0
- imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-in.csv +1729 -0
- imap_processing/tests/mag/validation/L1c/T016/mag-l1b-l1c-t016-mago-normal-out.csv +3053 -0
- imap_processing/tests/mag/validation/L2/imap_mag_l1b_norm-mago_20251017_v002.cdf +0 -0
- imap_processing/tests/mag/validation/calibration/imap_mag_l1b-calibration_20240229_v001.cdf +0 -0
- imap_processing/tests/mag/validation/calibration/imap_mag_l2-calibration-matrices_20251017_v004.cdf +0 -0
- imap_processing/tests/mag/validation/calibration/imap_mag_l2-offsets-norm_20251017_20251017_v001.cdf +0 -0
- imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
- imap_processing/tests/spacecraft/test_quaternions.py +71 -0
- imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
- imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
- imap_processing/tests/spice/test_geometry.py +9 -12
- imap_processing/tests/spice/test_kernels.py +1 -200
- imap_processing/tests/spice/test_pointing_frame.py +185 -0
- imap_processing/tests/spice/test_repoint.py +121 -0
- imap_processing/tests/spice/test_spin.py +50 -9
- imap_processing/tests/spice/test_time.py +14 -0
- imap_processing/tests/swapi/lut/imap_swapi_esa-unit-conversion_20250211_v000.csv +73 -0
- imap_processing/tests/swapi/lut/imap_swapi_lut-notes_20250211_v000.csv +1025 -0
- imap_processing/tests/swapi/test_swapi_l1.py +13 -11
- imap_processing/tests/swapi/test_swapi_l2.py +180 -8
- imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
- imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
- imap_processing/tests/swe/lut/checker-board-indices.csv +24 -0
- imap_processing/tests/swe/lut/imap_swe_esa-lut_20250301_v000.csv +385 -0
- imap_processing/tests/swe/lut/imap_swe_l1b-in-flight-cal_20240510_20260716_v000.csv +3 -0
- imap_processing/tests/swe/test_swe_l1a.py +20 -2
- imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
- imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
- imap_processing/tests/swe/test_swe_l1a_science.py +3 -3
- imap_processing/tests/swe/test_swe_l1b.py +162 -24
- imap_processing/tests/swe/test_swe_l2.py +153 -91
- imap_processing/tests/test_cli.py +171 -88
- imap_processing/tests/test_utils.py +140 -17
- imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
- imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
- 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
- imap_processing/tests/ultra/data/mock_data.py +369 -0
- imap_processing/tests/ultra/unit/conftest.py +115 -89
- imap_processing/tests/ultra/unit/test_badtimes.py +4 -4
- imap_processing/tests/ultra/unit/test_cullingmask.py +8 -6
- imap_processing/tests/ultra/unit/test_de.py +14 -13
- imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +54 -11
- imap_processing/tests/ultra/unit/test_decom_apid_883.py +12 -10
- imap_processing/tests/ultra/unit/test_decom_apid_896.py +202 -55
- imap_processing/tests/ultra/unit/test_lookup_utils.py +23 -1
- imap_processing/tests/ultra/unit/test_spacecraft_pset.py +77 -0
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +98 -305
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +60 -14
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +26 -27
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +239 -70
- imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +114 -83
- imap_processing/tests/ultra/unit/test_ultra_l2.py +230 -0
- imap_processing/ultra/constants.py +1 -1
- imap_processing/ultra/l0/decom_tools.py +27 -39
- imap_processing/ultra/l0/decom_ultra.py +168 -204
- imap_processing/ultra/l0/ultra_utils.py +152 -136
- imap_processing/ultra/l1a/ultra_l1a.py +55 -271
- imap_processing/ultra/l1b/badtimes.py +1 -4
- imap_processing/ultra/l1b/cullingmask.py +2 -6
- imap_processing/ultra/l1b/de.py +116 -57
- imap_processing/ultra/l1b/extendedspin.py +20 -18
- imap_processing/ultra/l1b/lookup_utils.py +72 -9
- imap_processing/ultra/l1b/ultra_l1b.py +36 -16
- imap_processing/ultra/l1b/ultra_l1b_culling.py +66 -30
- imap_processing/ultra/l1b/ultra_l1b_extended.py +297 -94
- imap_processing/ultra/l1c/histogram.py +2 -6
- imap_processing/ultra/l1c/spacecraft_pset.py +84 -0
- imap_processing/ultra/l1c/ultra_l1c.py +8 -9
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +206 -108
- imap_processing/ultra/l2/ultra_l2.py +299 -0
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +526 -0
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +526 -0
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +526 -0
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +526 -0
- imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -2
- imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
- imap_processing/ultra/packet_definitions/README.md +38 -0
- imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +15302 -482
- imap_processing/ultra/utils/ultra_l1_utils.py +31 -12
- imap_processing/utils.py +69 -29
- {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +10 -6
- imap_processing-0.13.0.dist-info/RECORD +578 -0
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
- imap_processing/hi/l1a/housekeeping.py +0 -27
- imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
- imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
- imap_processing/swe/l1b/swe_l1b_science.py +0 -652
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
- imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
- imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
- imap_processing/tests/swe/test_swe_l1b_science.py +0 -84
- imap_processing/tests/ultra/test_data/mock_data.py +0 -161
- imap_processing/ultra/l1c/pset.py +0 -40
- imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
- imap_processing-0.11.0.dist-info/RECORD +0 -488
- /imap_processing/idex/packet_definitions/{idex_packet_definition.xml → idex_science_packet_definition.xml} +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/IALiRT Raw Packet Telemetry.txt +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/apid01152.tlm +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/eu_SWP_IAL_20240826_152033.csv +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/hi_fsw_view_1_ccsds.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.ccsds +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/hit_ialirt_sample.csv +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
- /imap_processing/{mag/l1b → tests/spacecraft}/__init__.py +0 -0
- /imap_processing/{swe/l1b/engineering_unit_convert_table.csv → tests/swe/lut/imap_swe_eu-conversion_20240510_v000.csv} +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"""Tests the L2a processing for IDEX data"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import xarray as xr
|
|
5
|
+
from scipy.stats import exponnorm
|
|
6
|
+
|
|
7
|
+
from imap_processing.idex import idex_constants
|
|
8
|
+
from imap_processing.idex.idex_l2a import (
|
|
9
|
+
BaselineNoiseTime,
|
|
10
|
+
analyze_peaks,
|
|
11
|
+
butter_lowpass_filter,
|
|
12
|
+
calculate_kappa,
|
|
13
|
+
calculate_snr,
|
|
14
|
+
chi_square,
|
|
15
|
+
estimate_dust_mass,
|
|
16
|
+
fit_impact,
|
|
17
|
+
remove_signal_noise,
|
|
18
|
+
sine_fit,
|
|
19
|
+
time_to_mass,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def mock_microphonics_noise(time: np.ndarray) -> np.ndarray:
|
|
24
|
+
"""Function to mock signal noise (linear and sine wave) due to microphonics."""
|
|
25
|
+
noise_frequency = idex_constants.TARGET_NOISE_FREQUENCY
|
|
26
|
+
phase_shift = 45
|
|
27
|
+
amp = 10
|
|
28
|
+
# Create a sine wave signal
|
|
29
|
+
sine_signal = sine_fit(time, amp, noise_frequency, phase_shift)
|
|
30
|
+
# Combine the sine wave signals with a linear signal to create noise
|
|
31
|
+
combined_sig = sine_signal + (time * 5)
|
|
32
|
+
|
|
33
|
+
return combined_sig
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_l2a_logical_source(l2a_dataset: xr.Dataset):
|
|
37
|
+
"""Tests that the ``idex_l2a`` function generates datasets
|
|
38
|
+
with the expected logical source.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
l2a_dataset : xr.Dataset
|
|
43
|
+
A ``xarray`` dataset containing the test data
|
|
44
|
+
"""
|
|
45
|
+
expected_src = "imap_idex_l2a_sci-1week"
|
|
46
|
+
assert l2a_dataset.attrs["Logical_source"] == expected_src
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_l2a_cdf_variables(l2a_dataset: xr.Dataset):
|
|
50
|
+
"""Tests that the ``idex_l2a`` function generates datasets
|
|
51
|
+
with the expected variables.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
l2a_dataset : xr.Dataset
|
|
56
|
+
A ``xarray`` dataset containing the test data
|
|
57
|
+
"""
|
|
58
|
+
expected_vars = [
|
|
59
|
+
"target_low_fit_parameters",
|
|
60
|
+
"target_low_fit_impact_charge",
|
|
61
|
+
"target_low_fit_impact_mass_estimate",
|
|
62
|
+
"target_low_chi_squared",
|
|
63
|
+
"target_low_reduced_chi_squared",
|
|
64
|
+
"target_low_fit_results",
|
|
65
|
+
"target_high_fit_parameters",
|
|
66
|
+
"target_high_fit_impact_charge",
|
|
67
|
+
"target_high_fit_impact_mass_estimate",
|
|
68
|
+
"target_high_chi_squared",
|
|
69
|
+
"target_high_reduced_chi_squared",
|
|
70
|
+
"target_high_fit_results",
|
|
71
|
+
"ion_grid_fit_parameters",
|
|
72
|
+
"ion_grid_fit_impact_charge",
|
|
73
|
+
"ion_grid_fit_impact_mass_estimate",
|
|
74
|
+
"ion_grid_chi_squared",
|
|
75
|
+
"ion_grid_reduced_chi_squared",
|
|
76
|
+
"ion_grid_fit_results",
|
|
77
|
+
"tof_peak_fit_parameters",
|
|
78
|
+
"tof_peak_area_under_fit",
|
|
79
|
+
"tof_peak_chi_square",
|
|
80
|
+
"tof_peak_reduced_chi_square",
|
|
81
|
+
"tof_peak_kappa",
|
|
82
|
+
"tof_snr",
|
|
83
|
+
"mass",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
cdf_vars = l2a_dataset.variables
|
|
87
|
+
for var in expected_vars:
|
|
88
|
+
assert var in cdf_vars
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_time_to_mass_zero_lag():
|
|
92
|
+
"""
|
|
93
|
+
Tests that the time_to_mass function correctly converts time-of-flight
|
|
94
|
+
to a mass scale using known peak positions.
|
|
95
|
+
"""
|
|
96
|
+
carbon_mass = 12
|
|
97
|
+
masses = np.asarray([1, 4, 9])
|
|
98
|
+
|
|
99
|
+
expected_lag = 10
|
|
100
|
+
expected_stretch = 1500
|
|
101
|
+
# Create a 2d time of flight array exactly where we would expect the peaks to be
|
|
102
|
+
# Each mass should appear at time t = 1400 * sqrt(m) ns
|
|
103
|
+
tof = np.zeros((15, int(np.sqrt(masses[-1]) * expected_stretch + 1 + expected_lag)))
|
|
104
|
+
min_stretch = 1400
|
|
105
|
+
# Mass 1 expected tof
|
|
106
|
+
tof[:-1, min_stretch] = 1
|
|
107
|
+
# Mass 4 expected tof
|
|
108
|
+
tof[:-1, min_stretch * 2] = 1
|
|
109
|
+
# Mass 9 expected tof
|
|
110
|
+
tof[:-1, min_stretch * 3] = 1
|
|
111
|
+
# Change the last TOF array to be shifted and 'stretched'
|
|
112
|
+
# Mass 1 expected tof
|
|
113
|
+
tof[-1, expected_stretch + expected_lag] = 1
|
|
114
|
+
# Mass 4 expected tof
|
|
115
|
+
tof[-1, expected_stretch * 2 + expected_lag] = 1
|
|
116
|
+
# Mass 9 expected tof
|
|
117
|
+
tof[-1, expected_stretch * 3 + expected_lag] = 1
|
|
118
|
+
|
|
119
|
+
time = np.tile(np.arange(len(tof[0])), (15, 1))
|
|
120
|
+
stretch, shift, mass_scale = time_to_mass(tof, time, masses)
|
|
121
|
+
|
|
122
|
+
# Test with carbon mass
|
|
123
|
+
carbon_time = (stretch[0] * np.sqrt(carbon_mass)) / 1e-6 # Convert ms to s
|
|
124
|
+
mass = np.interp(carbon_time, time[0], mass_scale[0])
|
|
125
|
+
assert np.allclose(carbon_mass, mass, rtol=1e-2)
|
|
126
|
+
|
|
127
|
+
# Test shift is zero since peaks are aligned
|
|
128
|
+
assert np.all(shift[:-1] == 0)
|
|
129
|
+
# Test stretch factor matches expected 1400 ns in seconds
|
|
130
|
+
assert np.all(stretch[:-1] == 1400 * 1e-9)
|
|
131
|
+
# Test output shape
|
|
132
|
+
assert mass_scale.shape == time.shape
|
|
133
|
+
# Test that the last shift and stretch are the expected values
|
|
134
|
+
assert shift[-1] == -expected_lag * idex_constants.FM_SAMPLING_RATE
|
|
135
|
+
# Test stretch factor matches expected 1400 ns in seconds
|
|
136
|
+
assert stretch[-1] == expected_stretch * 1e-9
|
|
137
|
+
|
|
138
|
+
# Test with carbon mass
|
|
139
|
+
carbon_time = (stretch[-1] * np.sqrt(carbon_mass) + shift[-1]) / 1e-6
|
|
140
|
+
mass = np.interp(carbon_time, time[-1], mass_scale[-1])
|
|
141
|
+
assert np.allclose(carbon_mass, mass, rtol=1e-2)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_time_to_mass_zero_correlation_warning(caplog):
|
|
145
|
+
"""
|
|
146
|
+
Tests that the time_to_mass function correctly logs a warning if zero correlations
|
|
147
|
+
are found between the TOF and expected mass times array.
|
|
148
|
+
"""
|
|
149
|
+
masses = np.asarray([1, 4, 9])
|
|
150
|
+
# Create a time of flight array that will result in no correlation between the
|
|
151
|
+
# Expected tof peaks.
|
|
152
|
+
tof = np.zeros((10, 8000))
|
|
153
|
+
time = np.tile(np.arange(len(tof[0])), (10, 1))
|
|
154
|
+
with caplog.at_level("WARNING"):
|
|
155
|
+
time_to_mass(tof, time, masses)
|
|
156
|
+
|
|
157
|
+
assert any(
|
|
158
|
+
"There are no correlations found between the"
|
|
159
|
+
" TOF array and the expected mass times array" in message
|
|
160
|
+
for message in caplog.text.splitlines()
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_calculate_kappa():
|
|
165
|
+
"""Tests the functionality of calculate_kappa()."""
|
|
166
|
+
# Create a 2d list of peak indices
|
|
167
|
+
peaks = [[0, 1], [1, 2], [0, 1, 2]]
|
|
168
|
+
|
|
169
|
+
# Create mass_scales array
|
|
170
|
+
mass_scales = np.array(
|
|
171
|
+
[
|
|
172
|
+
[1.2, 2.2, 3.2], # The kappa value for peaks 0,1 should be .2
|
|
173
|
+
[1.4, 2.4, 3.4], # The kappa value for peaks 1,2 should be .4
|
|
174
|
+
[1.7, 2.7, 3.7], # The kappa value for peaks 2,3,4 should be -0.3
|
|
175
|
+
]
|
|
176
|
+
)
|
|
177
|
+
kappas = calculate_kappa(mass_scales, peaks)
|
|
178
|
+
|
|
179
|
+
assert np.allclose(list(kappas), [0.2, 0.4, -0.3], rtol=1e-12)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def test_calculate_snr():
|
|
183
|
+
"""Tests the functionality of calculate_snr()."""
|
|
184
|
+
step = 0.5
|
|
185
|
+
max_tof = 10
|
|
186
|
+
time = np.arange(BaselineNoiseTime.START, 5, step)
|
|
187
|
+
|
|
188
|
+
# Create a baseline noise array with an std of 1 and mean of 1
|
|
189
|
+
baseline_noise = np.asarray([0, 0, 1, 2, 2])
|
|
190
|
+
signal_length = len(time) - len(baseline_noise)
|
|
191
|
+
tof_signal = np.full(int(signal_length), max_tof)
|
|
192
|
+
|
|
193
|
+
tof = np.tile(np.append(baseline_noise, tof_signal), (3, 1))
|
|
194
|
+
time = np.tile(time, (3, 1))
|
|
195
|
+
|
|
196
|
+
snr = calculate_snr(tof, time)
|
|
197
|
+
|
|
198
|
+
# Since std=1 and mean=1, SNR should be (max_tof - mean)/std
|
|
199
|
+
assert np.all(snr == (max_tof - 1))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_calculate_snr_warning(caplog):
|
|
203
|
+
"""Tests that calculate_snr() throws warning if no baseline noise is found."""
|
|
204
|
+
time = np.tile(np.arange(10), (3, 1))
|
|
205
|
+
tof = np.ones_like(time)
|
|
206
|
+
|
|
207
|
+
with caplog.at_level("WARNING"):
|
|
208
|
+
calculate_snr(tof, time)
|
|
209
|
+
assert any(
|
|
210
|
+
"Unable to find baseline noise" in message
|
|
211
|
+
for message in caplog.text.splitlines()
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_analyze_peaks_warning(caplog):
|
|
216
|
+
"""Tests that analyze_peaks() throws warning if the emg curve fit fails."""
|
|
217
|
+
# Create a 2d list of peak indices
|
|
218
|
+
peaks = [[2]]
|
|
219
|
+
time = xr.DataArray(np.arange(6))
|
|
220
|
+
# When there is a flat signal for TOF, we expect the fit to fail and a
|
|
221
|
+
# warning to be logged.
|
|
222
|
+
tof = np.ones_like(time)
|
|
223
|
+
mass_scale = np.ones_like(time)
|
|
224
|
+
with caplog.at_level("WARNING"):
|
|
225
|
+
fit_params, area_under_curve, chisqr, redchi = analyze_peaks(
|
|
226
|
+
tof, time, mass_scale, 0, peaks
|
|
227
|
+
)
|
|
228
|
+
assert any(
|
|
229
|
+
"Failed to fit EMG curve" in message for message in caplog.text.splitlines()
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# The fit_params and area_under_curve arrays should be zero
|
|
233
|
+
assert np.all(fit_params == 0)
|
|
234
|
+
assert np.all(area_under_curve == 0)
|
|
235
|
+
# chi-square and reduced chi-square values should all be np.nan
|
|
236
|
+
np.testing.assert_array_equal(chisqr, np.nan)
|
|
237
|
+
np.testing.assert_array_equal(chisqr, np.nan)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_analyze_peaks_perfect_fits():
|
|
241
|
+
"""Tests that analyze_peaks() returns the expected fit params and areas."""
|
|
242
|
+
event = 0
|
|
243
|
+
# Create a 2d list of peak indices
|
|
244
|
+
peak_1 = 7
|
|
245
|
+
peak_2 = 25
|
|
246
|
+
peak_3 = 80
|
|
247
|
+
# Create tof array of ones
|
|
248
|
+
time = xr.DataArray(np.arange(100))
|
|
249
|
+
tof = np.zeros(100)
|
|
250
|
+
mass_scale = np.arange(100) + 0.5
|
|
251
|
+
# Only test peaks[0] this function is not vectorized but we pass in the full 2d peak
|
|
252
|
+
# array.
|
|
253
|
+
peaks = [np.asarray([peak_1, peak_2, peak_3]), np.asarray([])]
|
|
254
|
+
sigma = 2.0
|
|
255
|
+
lam = 1.0
|
|
256
|
+
k = 1 / (lam * sigma)
|
|
257
|
+
# Create a tof array with an emg curve at each peak
|
|
258
|
+
for peak in peaks[event]:
|
|
259
|
+
# Create a perfect emg curve
|
|
260
|
+
mu = peak - 0.4
|
|
261
|
+
gauss = exponnorm.pdf(time.data, k, mu, sigma)
|
|
262
|
+
tof[peak - 5 : peak + 6] = gauss[peak - 5 : peak + 6]
|
|
263
|
+
|
|
264
|
+
fit_params, area_under_curve, chisqr, redchi = analyze_peaks(
|
|
265
|
+
tof, time, mass_scale, event, peaks
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
for peak in peaks[event]:
|
|
269
|
+
mu = peak - 0.4
|
|
270
|
+
mass = round(mass_scale[round(mu)])
|
|
271
|
+
# Test that the fitted parameters at the mass index match our input parameters
|
|
272
|
+
assert np.allclose(fit_params[mass], np.asarray([mu, sigma, lam]), rtol=1e-12)
|
|
273
|
+
# Test that there is a value greater than zero at this index
|
|
274
|
+
assert area_under_curve[mass] > 0
|
|
275
|
+
# Test the goodness of fit
|
|
276
|
+
assert chisqr < 1e-20
|
|
277
|
+
assert redchi < 1e-20
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def test_estimate_dust_mass_no_noise_removal():
|
|
281
|
+
"""
|
|
282
|
+
Test that estimate_dust_mass() is fitting the signal properly when there is no
|
|
283
|
+
noise removal.
|
|
284
|
+
"""
|
|
285
|
+
# TODO: The IDEX team is iterating on this function and will provide more
|
|
286
|
+
# information soon.
|
|
287
|
+
start_time = -60
|
|
288
|
+
total_low_sampling_microseconds = 126.03 # see algorithm document.
|
|
289
|
+
num_samples = 512
|
|
290
|
+
|
|
291
|
+
# Create realistic low sampling time
|
|
292
|
+
time = xr.DataArray(
|
|
293
|
+
np.linspace(
|
|
294
|
+
start_time, total_low_sampling_microseconds - start_time, num_samples
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
signal = xr.DataArray(
|
|
298
|
+
fit_impact(
|
|
299
|
+
time.data,
|
|
300
|
+
time_of_impact=0.0,
|
|
301
|
+
constant_offset=1.0,
|
|
302
|
+
amplitude=10.0,
|
|
303
|
+
rise_time=0.371,
|
|
304
|
+
discharge_time=0.371,
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
param, sig_amp, chisqr, redchi, result = estimate_dust_mass(
|
|
308
|
+
time, signal, remove_noise=False
|
|
309
|
+
)
|
|
310
|
+
# Assert that the chi square value indicates a very good fit
|
|
311
|
+
assert chisqr <= 1e-12
|
|
312
|
+
|
|
313
|
+
assert np.allclose(result, signal)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def test_lowpass_filter():
|
|
317
|
+
"""
|
|
318
|
+
Tests that the lowpass filter is filtering out high frequency signals.
|
|
319
|
+
|
|
320
|
+
Look at
|
|
321
|
+
https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.filtfilt.html#scipy.signal.filtfilt
|
|
322
|
+
for the source of the testing example.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
time = np.linspace(-60, 60, 512)
|
|
326
|
+
# Calculate nyquist frequency to help get cutoff.
|
|
327
|
+
# This is the highest frequency that can be captured
|
|
328
|
+
time_between_samples = time[1] - time[0]
|
|
329
|
+
nqf = (1 / time_between_samples) / 2
|
|
330
|
+
# Choose cutoff of 0.125 times the Nyquist frequency
|
|
331
|
+
cutoff = nqf * 0.125
|
|
332
|
+
# Create two signals with different frequencies and combine them
|
|
333
|
+
low_freq = cutoff / 4 # Lower than cutoff
|
|
334
|
+
high_freq = nqf # The nyquist frequency is much higher than the cutoff
|
|
335
|
+
# Create sine signals
|
|
336
|
+
signal_low = np.sin(2 * np.pi * low_freq * time)
|
|
337
|
+
signal_high = np.sin(2 * np.pi * high_freq * time)
|
|
338
|
+
combined_sig = signal_low + signal_high
|
|
339
|
+
# The filter should filter out the high frequency signal
|
|
340
|
+
filtered_sig = butter_lowpass_filter(time, combined_sig, cutoff)
|
|
341
|
+
# Assert that the filtered signal is relatively close to the original low
|
|
342
|
+
# frequency signal.
|
|
343
|
+
np.allclose(filtered_sig, signal_low)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def test_remove_signal_noise():
|
|
347
|
+
"""
|
|
348
|
+
Tests that remove_signal_noise() function is filtering out sine wave and linear
|
|
349
|
+
noise due to "microphonics"
|
|
350
|
+
"""
|
|
351
|
+
start_time = -60
|
|
352
|
+
total_low_sampling_microseconds = 126.03 # see algorithm document.
|
|
353
|
+
num_samples = 512
|
|
354
|
+
|
|
355
|
+
# Create realistic low sampling time
|
|
356
|
+
time = np.linspace(
|
|
357
|
+
start_time, total_low_sampling_microseconds - start_time, num_samples
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
mask = time <= (start_time + total_low_sampling_microseconds) / 2
|
|
361
|
+
noisy_signal = mock_microphonics_noise(time)
|
|
362
|
+
# Filter signal
|
|
363
|
+
filtered_sig = remove_signal_noise(time, noisy_signal, mask)
|
|
364
|
+
|
|
365
|
+
np.allclose(filtered_sig, np.zeros_like(filtered_sig), atol=1e-2)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def test_remove_signal_noise_no_sine_wave(caplog):
|
|
369
|
+
"""
|
|
370
|
+
Tests that remove_signal_noise() function filters linear noise when there is no
|
|
371
|
+
sine wave.
|
|
372
|
+
"""
|
|
373
|
+
time = np.linspace(-60, 60, 512)
|
|
374
|
+
# linear signal to create noise
|
|
375
|
+
signal = time * 10
|
|
376
|
+
mask = time <= 0.5
|
|
377
|
+
# Filter signal
|
|
378
|
+
filtered_sig = remove_signal_noise(time, signal, mask)
|
|
379
|
+
# Test that the filtered signal is close to zero
|
|
380
|
+
assert np.allclose(filtered_sig, np.zeros_like(filtered_sig), rtol=1e-24)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def test_chi_square():
|
|
384
|
+
"""
|
|
385
|
+
Test that chi_square() function calculates the expected values for an array of given
|
|
386
|
+
residuals.
|
|
387
|
+
"""
|
|
388
|
+
residual = 3
|
|
389
|
+
nparams = 2
|
|
390
|
+
exp = np.array([16, 18, 16, 14, 12, 12])
|
|
391
|
+
obs = exp + residual
|
|
392
|
+
|
|
393
|
+
expected_chi_square = np.square(residual) * len(exp)
|
|
394
|
+
expected_red_chi_square = expected_chi_square / (len(exp) - nparams)
|
|
395
|
+
|
|
396
|
+
chisqr, redchi = chi_square(obs, exp, nparams)
|
|
397
|
+
|
|
398
|
+
assert chisqr == expected_chi_square
|
|
399
|
+
assert redchi == expected_red_chi_square
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Tests the L2b processing for IDEX data"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
import xarray as xr
|
|
6
|
+
from numpy.testing import assert_array_equal
|
|
7
|
+
|
|
8
|
+
from imap_processing.idex.idex_l2b import idex_l2b, round_spin_phases
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def l2b_dataset(l2a_dataset: xr.Dataset) -> xr.Dataset:
|
|
13
|
+
"""Return a ``xarray`` dataset containing test data.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
dataset : xr.Dataset
|
|
18
|
+
A ``xarray`` dataset containing the test data
|
|
19
|
+
"""
|
|
20
|
+
dataset = idex_l2b(l2a_dataset)
|
|
21
|
+
return dataset
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_l2b_logical_source(l2b_dataset: xr.Dataset):
|
|
25
|
+
"""Tests that the ``idex_l2b`` function generates datasets
|
|
26
|
+
with the expected logical source.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
l2b_dataset : xr.Dataset
|
|
31
|
+
A ``xarray`` dataset containing the test data
|
|
32
|
+
"""
|
|
33
|
+
expected_src = "imap_idex_l2b_sci"
|
|
34
|
+
assert l2b_dataset.attrs["Logical_source"] == expected_src
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_l2a_cdf_variables(l2b_dataset: xr.Dataset):
|
|
38
|
+
"""Tests that the ``idex_l2a`` function generates datasets
|
|
39
|
+
with the expected variables.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
l2b_dataset : xr.Dataset
|
|
44
|
+
A ``xarray`` dataset containing the test data
|
|
45
|
+
"""
|
|
46
|
+
expected_vars = [
|
|
47
|
+
"epoch",
|
|
48
|
+
"impact_day_of_year",
|
|
49
|
+
"spin_phase_quadrants",
|
|
50
|
+
"target_low_fit_impact_charge",
|
|
51
|
+
"target_low_fit_impact_mass_estimate",
|
|
52
|
+
"target_high_fit_impact_charge",
|
|
53
|
+
"target_high_fit_impact_mass_estimate",
|
|
54
|
+
"ion_grid_fit_impact_charge",
|
|
55
|
+
"ion_grid_fit_impact_mass_estimate",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
cdf_vars = l2b_dataset.variables
|
|
59
|
+
for var in expected_vars:
|
|
60
|
+
assert var in cdf_vars
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_round_spin_phases():
|
|
64
|
+
"""Tests that round_spin_phases() produces expected results."""
|
|
65
|
+
spin_phase_angles = xr.DataArray([90, 1, 10, 200, 359, 179, 100])
|
|
66
|
+
expected_quadrants = [90, 0, 0, 180, 0, 180, 90]
|
|
67
|
+
|
|
68
|
+
spin_quadrants = round_spin_phases(spin_phase_angles)
|
|
69
|
+
assert_array_equal(spin_quadrants, expected_quadrants)
|
|
70
|
+
|
|
71
|
+
# Test with a larger number of random values
|
|
72
|
+
spin_phase_angles = np.random.randint(0, 360, 1000)
|
|
73
|
+
spin_quadrants = round_spin_phases(spin_phase_angles)
|
|
74
|
+
unique_quadrants = np.unique(spin_quadrants)
|
|
75
|
+
assert set(unique_quadrants) == {0, 90, 180, 270}
|
|
76
|
+
|
|
77
|
+
# Test values that are exactly halfway between quadrants
|
|
78
|
+
spin_quadrants = round_spin_phases(np.array([45, 135, 225, 315]))
|
|
79
|
+
assert_array_equal(spin_quadrants, [90, 180, 270, 0])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_round_spin_phases_warning(caplog):
|
|
83
|
+
"""Tests that round_spin_phases() logs expected out of range warning."""
|
|
84
|
+
# The last value in the array should trigger a warning since it is >=360.
|
|
85
|
+
spin_phase_angles = xr.DataArray([90, 1, 10, 200, 360])
|
|
86
|
+
|
|
87
|
+
with caplog.at_level("WARNING"):
|
|
88
|
+
round_spin_phases(spin_phase_angles)
|
|
89
|
+
|
|
90
|
+
assert (
|
|
91
|
+
f"Spin phase angles, {spin_phase_angles.data} "
|
|
92
|
+
f"are outside of the expected spin phase angle range, [0, 360)."
|
|
93
|
+
) in caplog.text
|
|
Binary file
|
|
Binary file
|
|
@@ -15,7 +15,7 @@ def test_lo_l1a():
|
|
|
15
15
|
"imap_lo_l1a_histogram",
|
|
16
16
|
"imap_lo_l1a_de",
|
|
17
17
|
]
|
|
18
|
-
output_dataset = lo_l1a(dependency
|
|
18
|
+
output_dataset = lo_l1a(dependency)
|
|
19
19
|
|
|
20
20
|
# Assert
|
|
21
21
|
for dataset, logical_source in zip(output_dataset, expected_logical_source):
|
|
@@ -56,7 +56,7 @@ def test_lo_l1a_dataset():
|
|
|
56
56
|
hist_fields_lower = [field.lower() for field in histogram_fields]
|
|
57
57
|
|
|
58
58
|
# Act
|
|
59
|
-
output_datasets = lo_l1a(dependency
|
|
59
|
+
output_datasets = lo_l1a(dependency)
|
|
60
60
|
|
|
61
61
|
# Assert
|
|
62
62
|
np.testing.assert_array_equal(hist_fields_lower, output_datasets[1].data_vars)
|
|
@@ -108,7 +108,7 @@ def test_validate_spin_data():
|
|
|
108
108
|
validation_data = validation_data.drop(matching_columns, axis=1)
|
|
109
109
|
|
|
110
110
|
# Act
|
|
111
|
-
output_dataset = lo_l1a(dependency
|
|
111
|
+
output_dataset = lo_l1a(dependency)
|
|
112
112
|
|
|
113
113
|
# Assert
|
|
114
114
|
for field in spin_fields:
|