imap-processing 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/__init__.py +10 -11
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/excel_to_xtce.py +65 -16
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -28
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +365 -42
- 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 +26 -13
- 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 +6 -9
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +1 -1
- 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 +9 -21
- 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_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 +48 -52
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +2 -14
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +51 -2
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +29 -14
- imap_processing/cdf/utils.py +13 -7
- imap_processing/cli.py +23 -8
- imap_processing/codice/codice_l1a.py +207 -85
- imap_processing/codice/constants.py +1322 -568
- imap_processing/codice/decompress.py +2 -6
- imap_processing/ena_maps/ena_maps.py +480 -116
- 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 +45 -47
- imap_processing/hi/l1a/hi_l1a.py +24 -18
- 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 +31 -39
- imap_processing/hi/l1c/hi_l1c.py +405 -17
- imap_processing/hi/utils.py +58 -12
- 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 +173 -1
- imap_processing/hit/l0/constants.py +20 -11
- imap_processing/hit/l0/decom_hit.py +18 -4
- imap_processing/hit/l1a/hit_l1a.py +45 -54
- imap_processing/hit/l1b/constants.py +317 -0
- imap_processing/hit/l1b/hit_l1b.py +367 -18
- imap_processing/hit/l2/constants.py +281 -0
- imap_processing/hit/l2/hit_l2.py +614 -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 +246 -0
- imap_processing/ialirt/l0/process_swe.py +252 -0
- imap_processing/ialirt/packet_definitions/ialirt.xml +7 -3
- imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
- 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 +25 -0
- imap_processing/idex/idex_l1a.py +6 -7
- imap_processing/idex/idex_l1b.py +4 -31
- imap_processing/idex/idex_l2a.py +789 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +39 -33
- imap_processing/lo/l0/lo_science.py +6 -0
- imap_processing/lo/l1a/lo_l1a.py +0 -1
- imap_processing/lo/l1b/lo_l1b.py +177 -25
- imap_processing/mag/constants.py +8 -0
- imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +6 -0
- imap_processing/mag/l0/decom_mag.py +10 -3
- imap_processing/mag/l1a/mag_l1a.py +22 -11
- imap_processing/mag/l1a/mag_l1a_data.py +28 -3
- imap_processing/mag/l1b/mag_l1b.py +190 -48
- imap_processing/mag/l1c/interpolation_methods.py +211 -0
- imap_processing/mag/l1c/mag_l1c.py +447 -9
- imap_processing/quality_flags.py +1 -0
- imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
- imap_processing/spacecraft/quaternions.py +123 -0
- imap_processing/spice/geometry.py +16 -19
- imap_processing/spice/repoint.py +120 -0
- imap_processing/swapi/l1/swapi_l1.py +4 -0
- imap_processing/swapi/l2/swapi_l2.py +0 -1
- imap_processing/swe/l1a/swe_l1a.py +47 -8
- imap_processing/swe/l1a/swe_science.py +5 -2
- imap_processing/swe/l1b/swe_l1b_science.py +103 -56
- imap_processing/swe/l2/swe_l2.py +60 -65
- imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
- imap_processing/swe/utils/swe_constants.py +63 -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 +23 -20
- imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
- imap_processing/tests/codice/conftest.py +1 -1
- 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 +110 -46
- imap_processing/tests/codice/test_decompress.py +4 -4
- imap_processing/tests/conftest.py +166 -10
- imap_processing/tests/ena_maps/conftest.py +51 -0
- imap_processing/tests/ena_maps/test_ena_maps.py +638 -109
- imap_processing/tests/ena_maps/test_map_utils.py +66 -43
- imap_processing/tests/ena_maps/test_spatial_utils.py +16 -20
- 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 +12 -15
- imap_processing/tests/hi/test_hi_l1c.py +234 -6
- imap_processing/tests/hi/test_l1a.py +30 -0
- imap_processing/tests/hi/test_science_direct_event.py +1 -1
- imap_processing/tests/hi/test_utils.py +24 -2
- imap_processing/tests/hit/helpers/l1_validation.py +39 -39
- 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 +4 -0
- imap_processing/tests/hit/test_hit_l1a.py +24 -28
- imap_processing/tests/hit/test_hit_l1b.py +304 -40
- imap_processing/tests/hit/test_hit_l2.py +454 -0
- imap_processing/tests/hit/test_hit_utils.py +112 -2
- 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/ialirt/test_data/l0/461971383-404.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971384-405.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971385-406.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971386-407.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971387-408.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971388-409.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971389-410.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971390-411.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971391-412.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/sample_decoded_i-alirt_data.csv +383 -0
- imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
- imap_processing/tests/ialirt/unit/test_parse_mag.py +168 -0
- imap_processing/tests/ialirt/unit/test_process_swe.py +208 -3
- imap_processing/tests/ialirt/unit/test_time.py +16 -0
- imap_processing/tests/idex/conftest.py +62 -6
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
- imap_processing/tests/idex/test_idex_l1a.py +48 -4
- imap_processing/tests/idex/test_idex_l1b.py +3 -3
- imap_processing/tests/idex/test_idex_l2a.py +383 -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_l1b.py +148 -4
- imap_processing/tests/lo/test_lo_science.py +1 -0
- imap_processing/tests/mag/conftest.py +69 -0
- imap_processing/tests/mag/test_mag_decom.py +1 -1
- imap_processing/tests/mag/test_mag_l1a.py +38 -0
- imap_processing/tests/mag/test_mag_l1b.py +34 -53
- imap_processing/tests/mag/test_mag_l1c.py +251 -20
- imap_processing/tests/mag/test_mag_validation.py +109 -25
- 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/imap_calibration_mag_20240229_v01.cdf +0 -0
- imap_processing/tests/spacecraft/__init__.py +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_geometry.py +6 -9
- imap_processing/tests/spice/test_repoint.py +111 -0
- imap_processing/tests/swapi/test_swapi_l1.py +7 -3
- 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/test_swe_l1a.py +18 -0
- 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_l1b_science.py +23 -4
- imap_processing/tests/swe/test_swe_l2.py +112 -30
- imap_processing/tests/test_cli.py +2 -2
- imap_processing/tests/test_utils.py +138 -16
- 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 +341 -0
- imap_processing/tests/ultra/unit/conftest.py +69 -26
- imap_processing/tests/ultra/unit/test_badtimes.py +2 -0
- imap_processing/tests/ultra/unit/test_cullingmask.py +4 -0
- imap_processing/tests/ultra/unit/test_de.py +12 -4
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +44 -0
- imap_processing/tests/ultra/unit/test_spacecraft_pset.py +78 -0
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +28 -12
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +34 -6
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +22 -26
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -51
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +94 -52
- imap_processing/ultra/l0/decom_tools.py +6 -5
- imap_processing/ultra/l1a/ultra_l1a.py +28 -56
- imap_processing/ultra/l1b/de.py +72 -28
- imap_processing/ultra/l1b/extendedspin.py +12 -14
- imap_processing/ultra/l1b/ultra_l1b.py +34 -9
- imap_processing/ultra/l1b/ultra_l1b_culling.py +65 -29
- imap_processing/ultra/l1b/ultra_l1b_extended.py +64 -19
- imap_processing/ultra/l1c/spacecraft_pset.py +86 -0
- imap_processing/ultra/l1c/ultra_l1c.py +7 -4
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +112 -61
- imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
- imap_processing/ultra/utils/ultra_l1_utils.py +20 -2
- imap_processing/utils.py +68 -28
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/METADATA +8 -5
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/RECORD +250 -199
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
- imap_processing/hi/l1a/housekeeping.py +0 -27
- 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/ultra/test_data/mock_data.py +0 -161
- imap_processing/ultra/l1c/pset.py +0 -40
- /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.12.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Test coverage for imap_processing.hi.l1c.hi_l1c.py"""
|
|
2
2
|
|
|
3
|
+
from collections import namedtuple
|
|
3
4
|
from unittest import mock
|
|
5
|
+
from unittest.mock import MagicMock
|
|
4
6
|
|
|
5
7
|
import numpy as np
|
|
6
8
|
import pandas as pd
|
|
@@ -9,9 +11,10 @@ import xarray as xr
|
|
|
9
11
|
|
|
10
12
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
11
13
|
from imap_processing.cdf.utils import load_cdf, write_cdf
|
|
14
|
+
from imap_processing.hi.l1a.science_direct_event import DE_CLOCK_TICK_S
|
|
12
15
|
from imap_processing.hi.l1c import hi_l1c
|
|
13
16
|
from imap_processing.hi.l1c.hi_l1c import CalibrationProductConfig
|
|
14
|
-
from imap_processing.hi.utils import HIAPID
|
|
17
|
+
from imap_processing.hi.utils import HIAPID, CoincidenceBitmap
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
@pytest.fixture(scope="module")
|
|
@@ -37,10 +40,14 @@ def test_hi_l1c_not_implemented():
|
|
|
37
40
|
hi_l1c.hi_l1c([None, None], "0")
|
|
38
41
|
|
|
39
42
|
|
|
43
|
+
@pytest.mark.external_test_data()
|
|
40
44
|
@pytest.mark.external_kernel()
|
|
41
45
|
@pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
|
|
42
|
-
def test_generate_pset_dataset(
|
|
46
|
+
def test_generate_pset_dataset(
|
|
47
|
+
hi_l1_test_data_path, hi_test_cal_prod_config_path, use_fake_spin_data_for_time
|
|
48
|
+
):
|
|
43
49
|
"""Test coverage for generate_pset_dataset function"""
|
|
50
|
+
use_fake_spin_data_for_time(482372987.999)
|
|
44
51
|
l1b_de_path = hi_l1_test_data_path / "imap_hi_l1b_45sensor-de_20250415_v999.cdf"
|
|
45
52
|
l1b_dataset = load_cdf(l1b_de_path)
|
|
46
53
|
l1c_dataset = hi_l1c.generate_pset_dataset(
|
|
@@ -54,9 +61,9 @@ def test_generate_pset_dataset(hi_l1_test_data_path, hi_test_cal_prod_config_pat
|
|
|
54
61
|
np.testing.assert_array_equal(l1c_dataset.despun_z.data.shape, (1, 3))
|
|
55
62
|
np.testing.assert_array_equal(l1c_dataset.hae_latitude.data.shape, (1, 3600))
|
|
56
63
|
np.testing.assert_array_equal(l1c_dataset.hae_longitude.data.shape, (1, 3600))
|
|
64
|
+
np.testing.assert_array_equal(l1c_dataset.exposure_times.data.shape, (1, 9, 3600))
|
|
57
65
|
for var in [
|
|
58
66
|
"counts",
|
|
59
|
-
"exposure_times",
|
|
60
67
|
"background_rates",
|
|
61
68
|
"background_rates_uncertainty",
|
|
62
69
|
]:
|
|
@@ -131,6 +138,218 @@ def test_pset_geometry(mock_frame_transform, mock_geom_frame_transform, sensor_s
|
|
|
131
138
|
)
|
|
132
139
|
|
|
133
140
|
|
|
141
|
+
@pytest.mark.external_test_data()
|
|
142
|
+
def test_pset_counts(hi_l1_test_data_path, hi_test_cal_prod_config_path):
|
|
143
|
+
"""Test coverage for pset_counts function."""
|
|
144
|
+
l1b_de_path = hi_l1_test_data_path / "imap_hi_l1b_45sensor-de_20250415_v999.cdf"
|
|
145
|
+
l1b_dataset = load_cdf(l1b_de_path)
|
|
146
|
+
cal_config_df = hi_l1c.CalibrationProductConfig.from_csv(
|
|
147
|
+
hi_test_cal_prod_config_path
|
|
148
|
+
)
|
|
149
|
+
empty_pset = hi_l1c.empty_pset_dataset(
|
|
150
|
+
l1b_dataset.esa_energy_step.data,
|
|
151
|
+
cal_config_df.cal_prod_config.number_of_products,
|
|
152
|
+
HIAPID.H90_SCI_DE.sensor,
|
|
153
|
+
)
|
|
154
|
+
counts_var = hi_l1c.pset_counts(empty_pset.coords, cal_config_df, l1b_dataset)
|
|
155
|
+
assert "counts" in counts_var
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_get_tof_window_mask():
|
|
159
|
+
"""Test coverage for get_tof_window_mask function."""
|
|
160
|
+
# Create a synthetic dataframe with required columns containing data
|
|
161
|
+
# intended to test all aspects of the function.
|
|
162
|
+
fill_vals = {
|
|
163
|
+
"tof_ab": -11,
|
|
164
|
+
"tof_ac1": -12,
|
|
165
|
+
"tof_bc1": -13,
|
|
166
|
+
"tof_c1c2": -14,
|
|
167
|
+
}
|
|
168
|
+
Row = namedtuple(
|
|
169
|
+
"Row",
|
|
170
|
+
[
|
|
171
|
+
"Index",
|
|
172
|
+
"tof_ab_low",
|
|
173
|
+
"tof_ab_high",
|
|
174
|
+
"tof_ac1_low",
|
|
175
|
+
"tof_ac1_high",
|
|
176
|
+
"tof_bc1_low",
|
|
177
|
+
"tof_bc1_high",
|
|
178
|
+
"tof_c1c2_low",
|
|
179
|
+
"tof_c1c2_high",
|
|
180
|
+
],
|
|
181
|
+
)
|
|
182
|
+
prod_config_row = Row((1, 0), 0, 1, -1, 2, 1, 5, 4, 6)
|
|
183
|
+
synth_df = pd.DataFrame(
|
|
184
|
+
{
|
|
185
|
+
"tof_ab": np.array(
|
|
186
|
+
[0, 2, 1, 0, -1, -5, -11], dtype=np.int32
|
|
187
|
+
), # T, F, T, T, F, F, FILL
|
|
188
|
+
"tof_ac1": np.array(
|
|
189
|
+
[-1, 2, -2, 0, 3, 0, -12], dtype=np.int32
|
|
190
|
+
), # T, T, F, T, F, T, FILL
|
|
191
|
+
"tof_bc1": np.array(
|
|
192
|
+
[1, 5, 3, 0, 6, 2, -13], dtype=np.int32
|
|
193
|
+
), # T, T, T, F, F, T, FILL
|
|
194
|
+
"tof_c1c2": np.array(
|
|
195
|
+
[4, 6, 5, 3, 7, -9, -14], dtype=np.int32
|
|
196
|
+
), # T, T, T, F, F, F, FILL
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
expected_mask = np.array([True, False, False, False, False, False, True])
|
|
200
|
+
window_mask = hi_l1c.get_tof_window_mask(synth_df, prod_config_row, fill_vals)
|
|
201
|
+
np.testing.assert_array_equal(expected_mask, window_mask)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@mock.patch("imap_processing.hi.l1c.hi_l1c.get_spin_data", return_value=None)
|
|
205
|
+
@mock.patch("imap_processing.hi.l1c.hi_l1c.get_instrument_spin_phase")
|
|
206
|
+
@mock.patch("imap_processing.hi.l1c.hi_l1c.get_de_clock_ticks_for_esa_step")
|
|
207
|
+
@mock.patch("imap_processing.hi.l1c.hi_l1c.find_second_de_packet_data")
|
|
208
|
+
def test_pset_exposure(
|
|
209
|
+
mock_find_second_de_packet_data,
|
|
210
|
+
mock_de_clock_ticks,
|
|
211
|
+
mock_spin_phase,
|
|
212
|
+
mock_spin_data,
|
|
213
|
+
):
|
|
214
|
+
"""Test coverage for pset_exposure function"""
|
|
215
|
+
empty_pset = hi_l1c.empty_pset_dataset(
|
|
216
|
+
np.arange(2) + 1, 2, HIAPID.H90_SCI_DE.sensor
|
|
217
|
+
)
|
|
218
|
+
# Set the mock of find_second_de_packet_data to return a xr.Dataset
|
|
219
|
+
# with some dummy data. ESA 1 will get binned data once, ESA 2 will get
|
|
220
|
+
# binned data twice.
|
|
221
|
+
mock_find_second_de_packet_data.return_value = xr.Dataset(
|
|
222
|
+
coords={"epoch": xr.DataArray(np.arange(3), dims=["epoch"])},
|
|
223
|
+
data_vars={
|
|
224
|
+
"ccsds_met": xr.DataArray(np.arange(3), dims=["epoch"]),
|
|
225
|
+
"esa_energy_step": xr.DataArray(np.array([1, 2, 2]), dims=["epoch"]),
|
|
226
|
+
},
|
|
227
|
+
)
|
|
228
|
+
# Set mock of get_de_clock_ticks_for_esa_step and spin phase to generate
|
|
229
|
+
# deterministic histogram values.
|
|
230
|
+
# ESA step 1 should have repeating values of 3, 1.
|
|
231
|
+
# ESA step 2 should have repeating values of 6, 2
|
|
232
|
+
mock_spin_phase.return_value = np.concat(
|
|
233
|
+
[hi_l1c.SPIN_PHASE_BIN_CENTERS, hi_l1c.SPIN_PHASE_BIN_CENTERS[::2]]
|
|
234
|
+
)
|
|
235
|
+
mock_de_clock_ticks.return_value = (
|
|
236
|
+
np.zeros(hi_l1c.N_SPIN_BINS + hi_l1c.N_SPIN_BINS // 2),
|
|
237
|
+
np.concat([np.ones(hi_l1c.N_SPIN_BINS), np.ones(hi_l1c.N_SPIN_BINS // 2) * 2]),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# The above mocks mean no data needs to be in the l1b_dataset. It
|
|
241
|
+
# only needs to provide a logical source that contains "90sensor".
|
|
242
|
+
l1b_dataset = MagicMock()
|
|
243
|
+
l1b_dataset.attrs = {"Logical_source": "90sensor"}
|
|
244
|
+
|
|
245
|
+
# All the setup is done, call the pset_exposure function
|
|
246
|
+
exposure_dict = hi_l1c.pset_exposure(empty_pset.coords, l1b_dataset)
|
|
247
|
+
|
|
248
|
+
# Based on the spin phase and clock_tick mocks, the expected output is:
|
|
249
|
+
# - Repeated values of 3, 1 for the first half of the spin bins
|
|
250
|
+
# - Repeated values of 3, 2 for the second half of the spin bins
|
|
251
|
+
expected_values = np.stack(
|
|
252
|
+
[
|
|
253
|
+
np.tile([3, 1], hi_l1c.N_SPIN_BINS // 2),
|
|
254
|
+
np.tile([6, 2], hi_l1c.N_SPIN_BINS // 2),
|
|
255
|
+
]
|
|
256
|
+
)[None, :, :]
|
|
257
|
+
np.testing.assert_array_equal(exposure_dict["exposure_times"].data, expected_values)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def test_find_second_de_packet_data():
|
|
261
|
+
"""Test coverage for find_second_de_packet_data function"""
|
|
262
|
+
# Create a test l1b_dataset
|
|
263
|
+
# Expect to remove index 0 and 5 due to missing esa_step pair
|
|
264
|
+
# Expect to remove index 11 due to 0 being a calibration step
|
|
265
|
+
# Expect to return indices 2, 4, 7, 9, 13
|
|
266
|
+
esa_steps = np.array([1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 0, 0, 7, 7])
|
|
267
|
+
l1b_dataset = xr.Dataset(
|
|
268
|
+
coords={
|
|
269
|
+
"epoch": xr.DataArray(
|
|
270
|
+
np.arange(esa_steps.size),
|
|
271
|
+
dims=["epoch"],
|
|
272
|
+
),
|
|
273
|
+
"event_met": xr.DataArray(
|
|
274
|
+
np.arange(10),
|
|
275
|
+
dims=["event_met"],
|
|
276
|
+
),
|
|
277
|
+
},
|
|
278
|
+
data_vars={
|
|
279
|
+
"esa_step": xr.DataArray(
|
|
280
|
+
esa_steps,
|
|
281
|
+
dims=["epoch"],
|
|
282
|
+
),
|
|
283
|
+
"coincidence_type": xr.DataArray(
|
|
284
|
+
np.ones(10),
|
|
285
|
+
dims=["event_met"],
|
|
286
|
+
),
|
|
287
|
+
},
|
|
288
|
+
)
|
|
289
|
+
subset = hi_l1c.find_second_de_packet_data(l1b_dataset)
|
|
290
|
+
np.testing.assert_array_equal(subset.epoch.data, np.array([2, 4, 7, 9, 13]))
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@pytest.fixture(scope="module")
|
|
294
|
+
def fake_spin_df():
|
|
295
|
+
"""Generate a synthetic spin dataframe"""
|
|
296
|
+
# Generate some spin periods that vary by a random fraction of a second
|
|
297
|
+
spin_period = np.full(10, 15) + np.random.randn(10) / 10
|
|
298
|
+
d = {
|
|
299
|
+
"spin_start_time": np.add.accumulate(spin_period),
|
|
300
|
+
"spin_period_sec": spin_period,
|
|
301
|
+
}
|
|
302
|
+
spin_df = pd.DataFrame.from_dict(d)
|
|
303
|
+
return spin_df
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_get_de_clock_ticks_for_esa_step(fake_spin_df):
|
|
307
|
+
"""Test coverage for get_de_clock_ticks_for_esa_step function."""
|
|
308
|
+
|
|
309
|
+
# Test nominal cases where CCSDS met falls after 8th spin start and before
|
|
310
|
+
# the end spin in the table + 1/2 spin period
|
|
311
|
+
for _, spin_row in fake_spin_df.iloc[8:].iterrows():
|
|
312
|
+
for ccsds_met in np.linspace(
|
|
313
|
+
spin_row.spin_start_time,
|
|
314
|
+
spin_row.spin_start_time + np.floor(spin_row.spin_period_sec / 2),
|
|
315
|
+
10,
|
|
316
|
+
):
|
|
317
|
+
clock_tick_mets, clock_tick_weights = (
|
|
318
|
+
hi_l1c.get_de_clock_ticks_for_esa_step(ccsds_met, fake_spin_df)
|
|
319
|
+
)
|
|
320
|
+
np.testing.assert_array_equal(clock_tick_mets.shape, clock_tick_mets.shape)
|
|
321
|
+
# Verify last weight entry
|
|
322
|
+
exp_final_weight = (
|
|
323
|
+
np.absolute(
|
|
324
|
+
fake_spin_df.spin_start_time.to_numpy() - clock_tick_mets[-1]
|
|
325
|
+
).min()
|
|
326
|
+
/ DE_CLOCK_TICK_S
|
|
327
|
+
)
|
|
328
|
+
assert clock_tick_weights[-1] == exp_final_weight
|
|
329
|
+
assert np.all(clock_tick_weights[:-1] == 1)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def test_get_de_clock_ticks_for_esa_step_exceptions(fake_spin_df):
|
|
333
|
+
"""Test the exception logic in the get_de_clock_ticks_for_esa_step function."""
|
|
334
|
+
# Test the ccsds_met being > 1/2 spin period past the spin start
|
|
335
|
+
bad_ccsds_met = (
|
|
336
|
+
fake_spin_df.iloc[8].spin_start_time
|
|
337
|
+
+ fake_spin_df.iloc[8].spin_period_sec / 2
|
|
338
|
+
+ 0.1
|
|
339
|
+
)
|
|
340
|
+
with pytest.raises(
|
|
341
|
+
ValueError, match="The difference between ccsds_met and spin_start_met"
|
|
342
|
+
):
|
|
343
|
+
hi_l1c.get_de_clock_ticks_for_esa_step(bad_ccsds_met, fake_spin_df)
|
|
344
|
+
|
|
345
|
+
# Test the ccsds_met being too close to the start of the spin table
|
|
346
|
+
bad_ccsds_met = fake_spin_df.iloc[7].spin_start_time
|
|
347
|
+
with pytest.raises(
|
|
348
|
+
ValueError, match="Error determining start/end time for exposure time"
|
|
349
|
+
):
|
|
350
|
+
hi_l1c.get_de_clock_ticks_for_esa_step(bad_ccsds_met, fake_spin_df)
|
|
351
|
+
|
|
352
|
+
|
|
134
353
|
class TestCalibrationProductConfig:
|
|
135
354
|
"""
|
|
136
355
|
All test coverage for the pd.DataFrame accessor extension "cal_prod_config".
|
|
@@ -138,7 +357,7 @@ class TestCalibrationProductConfig:
|
|
|
138
357
|
|
|
139
358
|
def test_wrong_columns(self):
|
|
140
359
|
"""Test coverage for a dataframe with the wrong columns."""
|
|
141
|
-
required_columns = CalibrationProductConfig.required_columns
|
|
360
|
+
required_columns = hi_l1c.CalibrationProductConfig.required_columns
|
|
142
361
|
for exclude_column_name in required_columns:
|
|
143
362
|
include_columns = set(required_columns) - {exclude_column_name}
|
|
144
363
|
df = pd.DataFrame({col: [1, 2, 3] for col in include_columns})
|
|
@@ -147,10 +366,19 @@ class TestCalibrationProductConfig:
|
|
|
147
366
|
|
|
148
367
|
def test_from_csv(self, hi_test_cal_prod_config_path):
|
|
149
368
|
"""Test coverage for read_csv function."""
|
|
369
|
+
df = hi_l1c.CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
|
|
370
|
+
assert isinstance(df["coincidence_type_list"][0, 1], tuple)
|
|
371
|
+
|
|
372
|
+
def test_added_coincidence_type_values_column(self, hi_test_cal_prod_config_path):
|
|
150
373
|
df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
|
|
151
|
-
assert
|
|
374
|
+
assert "coincidence_type_values" in df.columns
|
|
375
|
+
for _, row in df.iterrows():
|
|
376
|
+
for detect_string, val in zip(
|
|
377
|
+
row["coincidence_type_list"], row["coincidence_type_values"]
|
|
378
|
+
):
|
|
379
|
+
assert val == CoincidenceBitmap.detector_hit_str_to_int(detect_string)
|
|
152
380
|
|
|
153
381
|
def test_number_of_products(self, hi_test_cal_prod_config_path):
|
|
154
382
|
"""Test coverage for number of products accessor."""
|
|
155
|
-
df = CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
|
|
383
|
+
df = hi_l1c.CalibrationProductConfig.from_csv(hi_test_cal_prod_config_path)
|
|
156
384
|
assert df.cal_prod_config.number_of_products == 2
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
2
3
|
|
|
3
4
|
from imap_processing.cdf.utils import write_cdf
|
|
4
5
|
from imap_processing.hi.l1a.hi_l1a import hi_l1a
|
|
@@ -23,6 +24,35 @@ def test_sci_de_decom(hi_l0_test_data_path):
|
|
|
23
24
|
assert cdf_filepath.name == cdf_filename
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def test_diag_fee_decom(hi_l0_test_data_path):
|
|
28
|
+
"""Test diag_fee data"""
|
|
29
|
+
bin_data_path = hi_l0_test_data_path / "H45_diag_fee_20250208.bin"
|
|
30
|
+
processed_data = hi_l1a(packet_file_path=bin_data_path, data_version="001")
|
|
31
|
+
dataset = processed_data[0]
|
|
32
|
+
cdf_filepath = write_cdf(processed_data[0], istp=False)
|
|
33
|
+
assert cdf_filepath.name == "imap_hi_l1a_45sensor-diagfee_20250208_v001.cdf"
|
|
34
|
+
|
|
35
|
+
assert np.unique(processed_data[0]["pkt_apid"].values) == HIAPID.H45_DIAG_FEE.value
|
|
36
|
+
|
|
37
|
+
validation_df = pd.read_csv(
|
|
38
|
+
hi_l0_test_data_path / "H45_diag_fee_20250208_verify.csv"
|
|
39
|
+
)
|
|
40
|
+
val_to_test_map = {
|
|
41
|
+
"PHVERNO": "version",
|
|
42
|
+
"PHTYPE": "type",
|
|
43
|
+
"PHSHF": "sec_hdr_flg",
|
|
44
|
+
"PHAPID": "pkt_apid",
|
|
45
|
+
"PHGROUPF": "seq_flgs",
|
|
46
|
+
"PHSEQCNT": "src_seq_ctr",
|
|
47
|
+
"PHDLEN": "pkt_len",
|
|
48
|
+
}
|
|
49
|
+
for col_name, series in validation_df.items():
|
|
50
|
+
if col_name == "timestamp":
|
|
51
|
+
continue
|
|
52
|
+
ds_var_name = val_to_test_map.get(col_name, col_name.lower())
|
|
53
|
+
np.testing.assert_array_equal(series.values, dataset[ds_var_name].data)
|
|
54
|
+
|
|
55
|
+
|
|
26
56
|
def test_app_nhk_decom(hi_l0_test_data_path):
|
|
27
57
|
"""Test housekeeping data"""
|
|
28
58
|
|
|
@@ -21,8 +21,8 @@ def test_parse_direct_events():
|
|
|
21
21
|
# Encode the random events data into a bit-string
|
|
22
22
|
bin_str = ""
|
|
23
23
|
for i in range(n_events):
|
|
24
|
-
bin_str += f"{exp_dict['trigger_id'][i]:02b}" # 2-bits for trigger_id
|
|
25
24
|
bin_str += f"{exp_dict['de_tag'][i]:016b}" # 16-bits for de_tag
|
|
25
|
+
bin_str += f"{exp_dict['trigger_id'][i]:02b}" # 2-bits for trigger_id
|
|
26
26
|
bin_str += f"{exp_dict['tof_1'][i]:010b}" # 10-bits for tof_1
|
|
27
27
|
bin_str += f"{exp_dict['tof_2'][i]:010b}" # 10-bits for tof_2
|
|
28
28
|
bin_str += f"{exp_dict['tof_3'][i]:010b}" # 10-bits for tof_3
|
|
@@ -7,6 +7,7 @@ import xarray as xr
|
|
|
7
7
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
8
8
|
from imap_processing.hi.utils import (
|
|
9
9
|
HIAPID,
|
|
10
|
+
CoincidenceBitmap,
|
|
10
11
|
create_dataset_variables,
|
|
11
12
|
full_dataarray,
|
|
12
13
|
parse_sensor_number,
|
|
@@ -74,13 +75,13 @@ def test_full_dataarray(name, shape, fill_value, expected_shape):
|
|
|
74
75
|
@pytest.mark.parametrize(
|
|
75
76
|
"var_names, shape, fill_value, lookup_str",
|
|
76
77
|
[
|
|
77
|
-
(["
|
|
78
|
+
(["tof_ab", "tof_ac1"], 5, None, "hi_de_{0}"),
|
|
78
79
|
(["hae_latitude"], (3, 5), 0, "hi_pset_{0}"),
|
|
79
80
|
],
|
|
80
81
|
)
|
|
81
82
|
def test_create_dataset_variables(var_names, shape, fill_value, lookup_str):
|
|
82
83
|
"""Test coverage for `imap_processing.hi.utils.create_dataset_variables`"""
|
|
83
|
-
var_names = ["
|
|
84
|
+
var_names = ["tof_ab", "tof_ac1", "tof_bc1"]
|
|
84
85
|
l1b_de_vars = create_dataset_variables(
|
|
85
86
|
var_names, shape, fill_value=fill_value, att_manager_lookup_str="hi_de_{0}"
|
|
86
87
|
)
|
|
@@ -100,3 +101,24 @@ def test_create_dataset_variables(var_names, shape, fill_value, lookup_str):
|
|
|
100
101
|
assert data_array.shape == shape
|
|
101
102
|
expected_fill_value = fill_value if fill_value is not None else attrs["FILLVAL"]
|
|
102
103
|
np.testing.assert_array_equal(data_array, expected_fill_value)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@pytest.mark.parametrize(
|
|
107
|
+
"sensor_hit_str, expected_val",
|
|
108
|
+
[
|
|
109
|
+
("ABC1C2", 15),
|
|
110
|
+
("ABC1", 14),
|
|
111
|
+
("AB", 12),
|
|
112
|
+
("AC1C2", 11),
|
|
113
|
+
("AC1", 10),
|
|
114
|
+
("A", 8),
|
|
115
|
+
("BC1C2", 7),
|
|
116
|
+
("BC1", 6),
|
|
117
|
+
("B", 4),
|
|
118
|
+
("C1C2", 3),
|
|
119
|
+
("C1", 2),
|
|
120
|
+
],
|
|
121
|
+
)
|
|
122
|
+
def test_coincidence_type_string_to_int(sensor_hit_str, expected_val):
|
|
123
|
+
"""Test coverage for coincidence_type_string_to_int function"""
|
|
124
|
+
assert CoincidenceBitmap.detector_hit_str_to_int(sensor_hit_str) == expected_val
|
|
@@ -48,16 +48,16 @@ RENAME_COLUMNS = {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
MOD_VALUE_TO_SPECIES_ENERGY_MAP = {
|
|
51
|
-
0: {"species": "
|
|
52
|
-
1: {"species": "
|
|
53
|
-
2: {"species": "
|
|
54
|
-
3: {"species": "
|
|
55
|
-
4: {"species": "
|
|
56
|
-
5: {"species": "
|
|
57
|
-
6: {"species": "
|
|
58
|
-
7: {"species": "
|
|
59
|
-
8: {"species": "
|
|
60
|
-
9: {"species": "
|
|
51
|
+
0: {"species": "h", "energy_bin": 0},
|
|
52
|
+
1: {"species": "h", "energy_bin": 1},
|
|
53
|
+
2: {"species": "h", "energy_bin": 2},
|
|
54
|
+
3: {"species": "he4", "energy_bin": 0},
|
|
55
|
+
4: {"species": "he4", "energy_bin": 1},
|
|
56
|
+
5: {"species": "cno", "energy_bin": 0},
|
|
57
|
+
6: {"species": "cno", "energy_bin": 1},
|
|
58
|
+
7: {"species": "nemgsi", "energy_bin": 0},
|
|
59
|
+
8: {"species": "nemgsi", "energy_bin": 1},
|
|
60
|
+
9: {"species": "fe", "energy_bin": 0},
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
@@ -170,7 +170,7 @@ def consolidate_rate_columns(
|
|
|
170
170
|
def consolidate_sectorates(data: pd.DataFrame) -> pd.DataFrame:
|
|
171
171
|
"""Consolidate sector rate data into arrays.
|
|
172
172
|
|
|
173
|
-
This function distinguishes between
|
|
173
|
+
This function distinguishes between sectored rate columns with three digits
|
|
174
174
|
and those with four digits in their names.
|
|
175
175
|
|
|
176
176
|
SECTORATES_000 SECTORATES_000_0 SECTORATES_000_1 SECTORATES_000_2...SECTORATES_120_9
|
|
@@ -185,9 +185,9 @@ def consolidate_sectorates(data: pd.DataFrame) -> pd.DataFrame:
|
|
|
185
185
|
|
|
186
186
|
Columns with four digits (e.g., SECTORATES_000_0) include the sectorate
|
|
187
187
|
values with a mod 10 value appended (e.g., 0). The mod 10 value determines
|
|
188
|
-
the species and energy range the
|
|
188
|
+
the species and energy range the sectored rates represent in the science frame.
|
|
189
189
|
There are 10 possible species and energy ranges, but only one has data per
|
|
190
|
-
science frame. The validation data has 10 columns per 120
|
|
190
|
+
science frame. The validation data has 10 columns per 120 sectored rates,
|
|
191
191
|
totaling 1200 columns per science frame. Each set of 10 columns will have
|
|
192
192
|
only one value, resulting in an array that looks like this:
|
|
193
193
|
|
|
@@ -215,13 +215,13 @@ def consolidate_sectorates(data: pd.DataFrame) -> pd.DataFrame:
|
|
|
215
215
|
).columns
|
|
216
216
|
|
|
217
217
|
data["sectorates"] = data[sectorates_three_digits].apply(
|
|
218
|
-
lambda row: row.values.reshape(
|
|
218
|
+
lambda row: row.values.reshape(15, 8), axis=1
|
|
219
219
|
)
|
|
220
220
|
data["sectorates_delta_plus"] = data[sectorates_delta_plus_three_digits].apply(
|
|
221
|
-
lambda row: row.values.reshape(
|
|
221
|
+
lambda row: row.values.reshape(15, 8), axis=1
|
|
222
222
|
)
|
|
223
223
|
data["sectorates_delta_minus"] = data[sectorates_delta_minus_three_digits].apply(
|
|
224
|
-
lambda row: row.values.reshape(
|
|
224
|
+
lambda row: row.values.reshape(15, 8), axis=1
|
|
225
225
|
)
|
|
226
226
|
|
|
227
227
|
sectorates_four_digits = data.filter(regex=r"^SECTORATES_\d{3}_\d{1}$").columns
|
|
@@ -279,7 +279,7 @@ def process_single_rates(data: pd.DataFrame) -> pd.DataFrame:
|
|
|
279
279
|
def add_species_energy(data: pd.DataFrame) -> pd.DataFrame:
|
|
280
280
|
"""Add species and energy index to the validation data.
|
|
281
281
|
|
|
282
|
-
The
|
|
282
|
+
The sectored rate data is organized by species and energy index
|
|
283
283
|
in the processed data so this function adds this information
|
|
284
284
|
to each row (i.e. science frame) in the validation data.
|
|
285
285
|
|
|
@@ -304,12 +304,12 @@ def add_species_energy(data: pd.DataFrame) -> pd.DataFrame:
|
|
|
304
304
|
)
|
|
305
305
|
)
|
|
306
306
|
data["species"] = data["mod_10"].apply(
|
|
307
|
-
lambda row: MOD_VALUE_TO_SPECIES_ENERGY_MAP[row]["species"]
|
|
307
|
+
lambda row: MOD_VALUE_TO_SPECIES_ENERGY_MAP[row]["species"]
|
|
308
308
|
if row is not None
|
|
309
309
|
else None
|
|
310
310
|
)
|
|
311
|
-
data["
|
|
312
|
-
lambda row: MOD_VALUE_TO_SPECIES_ENERGY_MAP[row]["
|
|
311
|
+
data["energy_bin"] = data["mod_10"].apply(
|
|
312
|
+
lambda row: MOD_VALUE_TO_SPECIES_ENERGY_MAP[row]["energy_bin"]
|
|
313
313
|
if row is not None
|
|
314
314
|
else None
|
|
315
315
|
)
|
|
@@ -336,7 +336,7 @@ def compare_data(
|
|
|
336
336
|
if field not in [
|
|
337
337
|
"sc_tick_by_frame",
|
|
338
338
|
"species",
|
|
339
|
-
"
|
|
339
|
+
"energy_bin",
|
|
340
340
|
]:
|
|
341
341
|
assert (
|
|
342
342
|
field in actual_data.data_vars.keys()
|
|
@@ -344,47 +344,47 @@ def compare_data(
|
|
|
344
344
|
if field not in skip:
|
|
345
345
|
for frame in range(expected_data.shape[0]):
|
|
346
346
|
if field == "species":
|
|
347
|
-
# Compare
|
|
347
|
+
# Compare sectored rates data using species and energy index.
|
|
348
348
|
# which are only present in the validation data. In the actual
|
|
349
|
-
# data,
|
|
350
|
-
# i.e.
|
|
351
|
-
# (epoch, h_energy_index,
|
|
349
|
+
# data, sectored rates are organized by species in 4D arrays.
|
|
350
|
+
# i.e. h_sectored_counts has shape
|
|
351
|
+
# (epoch, h_energy_index, azimuth, declination).
|
|
352
352
|
# species and energy index are used to find the correct
|
|
353
|
-
# array of
|
|
353
|
+
# array of sectored rate data from the actual data for comparison.
|
|
354
354
|
species = expected_data[field][frame]
|
|
355
|
-
|
|
355
|
+
energy_bin = expected_data["energy_bin"][frame]
|
|
356
356
|
if "sectorates_delta_plus" in expected_data.columns:
|
|
357
357
|
np.testing.assert_allclose(
|
|
358
|
-
actual_data[f"{species}
|
|
359
|
-
|
|
358
|
+
actual_data[f"{species}_sectored_counts_delta_plus"][frame][
|
|
359
|
+
energy_bin
|
|
360
360
|
].data,
|
|
361
361
|
expected_data["sectorates_delta_plus"][frame],
|
|
362
362
|
rtol=1e-7, # relative tolerance
|
|
363
363
|
atol=1e-8, # absolute tolerance
|
|
364
|
-
err_msg=f"Mismatch in {species}
|
|
365
|
-
f"plus at frame {frame},
|
|
364
|
+
err_msg=f"Mismatch in {species}_sectored_counts_delta_"
|
|
365
|
+
f"plus at frame {frame}, energy_bin {energy_bin}",
|
|
366
366
|
)
|
|
367
367
|
if "sectorates_delta_minus" in expected_data.columns:
|
|
368
368
|
np.testing.assert_allclose(
|
|
369
|
-
actual_data[f"{species}
|
|
369
|
+
actual_data[f"{species}_sectored_counts_delta_minus"][
|
|
370
370
|
frame
|
|
371
|
-
][
|
|
371
|
+
][energy_bin].data,
|
|
372
372
|
expected_data["sectorates_delta_minus"][frame],
|
|
373
373
|
rtol=1e-7,
|
|
374
374
|
atol=1e-8,
|
|
375
|
-
err_msg=f"Mismatch in {species}
|
|
376
|
-
f"minus at frame {frame},
|
|
375
|
+
err_msg=f"Mismatch in {species}_sectored_counts_delta_"
|
|
376
|
+
f"minus at frame {frame}, energy_bin {energy_bin}",
|
|
377
377
|
)
|
|
378
378
|
else:
|
|
379
379
|
np.testing.assert_allclose(
|
|
380
|
-
actual_data[f"{species}
|
|
381
|
-
|
|
380
|
+
actual_data[f"{species}_sectored_counts"][frame][
|
|
381
|
+
energy_bin
|
|
382
382
|
].data,
|
|
383
383
|
expected_data["sectorates"][frame],
|
|
384
384
|
rtol=1e-7,
|
|
385
385
|
atol=1e-8,
|
|
386
|
-
err_msg=f"Mismatch in {species}
|
|
387
|
-
f"frame {frame},
|
|
386
|
+
err_msg=f"Mismatch in {species}_sectored_counts at"
|
|
387
|
+
f"frame {frame}, energy_bin {energy_bin}",
|
|
388
388
|
)
|
|
389
389
|
elif field == "sc_tick_by_frame":
|
|
390
390
|
# Get the sc_tick values for each frame in the actual data
|
|
Binary file
|
|
Binary file
|
|
@@ -7,6 +7,7 @@ from imap_processing import imap_module_directory
|
|
|
7
7
|
from imap_processing.hit.hit_utils import (
|
|
8
8
|
HitAPID,
|
|
9
9
|
)
|
|
10
|
+
from imap_processing.hit.l0.constants import AZIMUTH_ANGLES, DECLINATION_ANGLES
|
|
10
11
|
from imap_processing.hit.l0.decom_hit import (
|
|
11
12
|
assemble_science_frames,
|
|
12
13
|
decom_hit,
|
|
@@ -122,6 +123,9 @@ def test_parse_count_rates(sci_dataset):
|
|
|
122
123
|
if count_rate_vars in list(sci_dataset.keys()):
|
|
123
124
|
assert True
|
|
124
125
|
|
|
126
|
+
assert np.allclose(sci_dataset["declination"].values, DECLINATION_ANGLES)
|
|
127
|
+
assert np.allclose(sci_dataset["azimuth"].values, AZIMUTH_ANGLES)
|
|
128
|
+
|
|
125
129
|
|
|
126
130
|
def test_is_sequential():
|
|
127
131
|
"""Test the is_sequential function."""
|