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,257 @@
|
|
|
1
|
+
"""Functions for retrieving repointing table data."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import typing
|
|
5
|
+
from collections.abc import Generator
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import spiceypy
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
from imap_processing.spice.kernels import ensure_spice
|
|
14
|
+
from imap_processing.spice.time import met_to_sclkticks, sct_to_et
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@contextmanager
|
|
20
|
+
def open_spice_ck_file(pointing_frame_path: Path) -> Generator[int, None, None]:
|
|
21
|
+
"""
|
|
22
|
+
Context manager for handling SPICE CK files.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
pointing_frame_path : str
|
|
27
|
+
Path to the CK file.
|
|
28
|
+
|
|
29
|
+
Yields
|
|
30
|
+
------
|
|
31
|
+
handle : int
|
|
32
|
+
Handle to the opened CK file.
|
|
33
|
+
"""
|
|
34
|
+
if pointing_frame_path.exists():
|
|
35
|
+
handle = spiceypy.dafopw(str(pointing_frame_path))
|
|
36
|
+
else:
|
|
37
|
+
handle = spiceypy.ckopn(str(pointing_frame_path), "CK", 0)
|
|
38
|
+
try:
|
|
39
|
+
yield handle
|
|
40
|
+
finally:
|
|
41
|
+
spiceypy.ckcls(handle)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@typing.no_type_check
|
|
45
|
+
@ensure_spice
|
|
46
|
+
def create_pointing_frame(
|
|
47
|
+
pointing_frame_path: Path,
|
|
48
|
+
ck_path: Path,
|
|
49
|
+
repoint_start_met: NDArray,
|
|
50
|
+
repoint_end_met: NDArray,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Create the pointing frame.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
pointing_frame_path : pathlib.Path
|
|
58
|
+
Location of pointing frame kernel.
|
|
59
|
+
ck_path : pathlib.Path
|
|
60
|
+
Location of the CK kernel.
|
|
61
|
+
repoint_start_met : numpy.ndarray
|
|
62
|
+
Start time of the repointing in MET.
|
|
63
|
+
repoint_end_met : numpy.ndarray
|
|
64
|
+
End time of the repointing in MET.
|
|
65
|
+
|
|
66
|
+
Notes
|
|
67
|
+
-----
|
|
68
|
+
Kernels required to be furnished:
|
|
69
|
+
"imap_science_0001.tf",
|
|
70
|
+
"imap_sclk_0000.tsc",
|
|
71
|
+
"imap_sim_ck_2hr_2secsampling_with_nutation.bc" or
|
|
72
|
+
"sim_1yr_imap_attitude.bc",
|
|
73
|
+
"imap_wkcp.tf",
|
|
74
|
+
"naif0012.tls"
|
|
75
|
+
|
|
76
|
+
Assumptions:
|
|
77
|
+
- The MOC has removed timeframe in which nutation/procession are present.
|
|
78
|
+
TODO: We may come back and have a check for this.
|
|
79
|
+
- The pointing frame kernel is made based on the most recent ck kernel.
|
|
80
|
+
In other words 1:1 ratio.
|
|
81
|
+
"""
|
|
82
|
+
# Get IDs.
|
|
83
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.gipool
|
|
84
|
+
id_imap_dps = spiceypy.gipool("FRAME_IMAP_DPS", 0, 1)
|
|
85
|
+
id_imap_sclk = spiceypy.gipool("CK_-43000_SCLK", 0, 1)
|
|
86
|
+
|
|
87
|
+
# Verify that only ck_path kernel is loaded.
|
|
88
|
+
count = spiceypy.ktotal("ck")
|
|
89
|
+
loaded_ck_kernel, _, _, _ = spiceypy.kdata(count - 1, "ck")
|
|
90
|
+
|
|
91
|
+
if count != 1 or str(ck_path) != loaded_ck_kernel:
|
|
92
|
+
raise ValueError(f"Error: Expected CK kernel {ck_path}")
|
|
93
|
+
|
|
94
|
+
id_imap_spacecraft = spiceypy.gipool("FRAME_IMAP_SPACECRAFT", 0, 1)
|
|
95
|
+
|
|
96
|
+
# Select only the pointings within the attitude coverage.
|
|
97
|
+
ck_cover = spiceypy.ckcov(
|
|
98
|
+
str(ck_path), int(id_imap_spacecraft), True, "INTERVAL", 0, "TDB"
|
|
99
|
+
)
|
|
100
|
+
num_intervals = spiceypy.wncard(ck_cover)
|
|
101
|
+
et_start, _ = spiceypy.wnfetd(ck_cover, 0)
|
|
102
|
+
_, et_end = spiceypy.wnfetd(ck_cover, num_intervals - 1)
|
|
103
|
+
|
|
104
|
+
sclk_ticks_start = met_to_sclkticks(repoint_start_met)
|
|
105
|
+
et_start_repoint = sct_to_et(sclk_ticks_start)
|
|
106
|
+
sclk_ticks_end = met_to_sclkticks(repoint_end_met)
|
|
107
|
+
et_end_repoint = sct_to_et(sclk_ticks_end)
|
|
108
|
+
|
|
109
|
+
valid_mask = (et_start_repoint >= et_start) & (et_end_repoint <= et_end)
|
|
110
|
+
et_start_repoint = et_start_repoint[valid_mask]
|
|
111
|
+
et_end_repoint = et_end_repoint[valid_mask]
|
|
112
|
+
|
|
113
|
+
with open_spice_ck_file(pointing_frame_path) as handle:
|
|
114
|
+
for i in range(len(repoint_start_met)):
|
|
115
|
+
# 1 spin/15 seconds; 10 quaternions / spin.
|
|
116
|
+
num_samples = (et_end_repoint[i] - et_start_repoint[i]) / 15 * 10
|
|
117
|
+
# There were rounding errors when using spiceypy.pxform
|
|
118
|
+
# so np.ceil and np.floor were used to ensure the start
|
|
119
|
+
# and end times were within the ck range.
|
|
120
|
+
et_times = np.linspace(
|
|
121
|
+
np.ceil(et_start_repoint[i] * 1e6) / 1e6,
|
|
122
|
+
np.floor(et_end_repoint[i] * 1e6) / 1e6,
|
|
123
|
+
int(num_samples),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Create a rotation matrix
|
|
127
|
+
rotation_matrix = _create_rotation_matrix(et_times)
|
|
128
|
+
|
|
129
|
+
# Convert the rotation matrix to a quaternion.
|
|
130
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.m2q
|
|
131
|
+
q_avg = spiceypy.m2q(rotation_matrix)
|
|
132
|
+
|
|
133
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.sce2c
|
|
134
|
+
# Convert start and end times to SCLK.
|
|
135
|
+
sclk_begtim = spiceypy.sce2c(int(id_imap_sclk), et_times[0])
|
|
136
|
+
sclk_endtim = spiceypy.sce2c(int(id_imap_sclk), et_times[-1])
|
|
137
|
+
|
|
138
|
+
# Create the pointing frame kernel.
|
|
139
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.ckw02
|
|
140
|
+
spiceypy.ckw02(
|
|
141
|
+
# Handle of an open CK file.
|
|
142
|
+
handle,
|
|
143
|
+
# Start time of the segment.
|
|
144
|
+
sclk_begtim,
|
|
145
|
+
# End time of the segment.
|
|
146
|
+
sclk_endtim,
|
|
147
|
+
# Pointing frame ID.
|
|
148
|
+
int(id_imap_dps),
|
|
149
|
+
# Reference frame.
|
|
150
|
+
"ECLIPJ2000", # Reference frame
|
|
151
|
+
# Identifier.
|
|
152
|
+
"IMAP_DPS",
|
|
153
|
+
# Number of pointing intervals.
|
|
154
|
+
1,
|
|
155
|
+
# Start times of individual pointing records within segment.
|
|
156
|
+
# Since there is only a single record this is equal to sclk_begtim.
|
|
157
|
+
np.array([sclk_begtim]),
|
|
158
|
+
# End times of individual pointing records within segment.
|
|
159
|
+
# Since there is only a single record this is equal to sclk_endtim.
|
|
160
|
+
np.array([sclk_endtim]), # Single stop time
|
|
161
|
+
# Average quaternion.
|
|
162
|
+
q_avg,
|
|
163
|
+
# 0.0 Angular rotation terms.
|
|
164
|
+
np.array([0.0, 0.0, 0.0]),
|
|
165
|
+
# Rates (seconds per tick) at which the quaternion and
|
|
166
|
+
# angular velocity change.
|
|
167
|
+
np.array([1.0]),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@typing.no_type_check
|
|
172
|
+
@ensure_spice
|
|
173
|
+
def _average_quaternions(et_times: np.ndarray) -> NDArray:
|
|
174
|
+
"""
|
|
175
|
+
Average the quaternions.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
et_times : numpy.ndarray
|
|
180
|
+
Array of times between et_start and et_end.
|
|
181
|
+
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
q_avg : np.ndarray
|
|
185
|
+
Average quaternion.
|
|
186
|
+
"""
|
|
187
|
+
aggregate = np.zeros((4, 4))
|
|
188
|
+
for tdb in et_times:
|
|
189
|
+
# we use a quick and dirty method here for grabbing the quaternions
|
|
190
|
+
# from the attitude kernel. Depending on how well the kernel input
|
|
191
|
+
# data is built and sampled, there may or may not be aliasing with this
|
|
192
|
+
# approach. If it turns out that we need to pull the quaternions
|
|
193
|
+
# directly from the CK there are several routines that exist to do this
|
|
194
|
+
# but it's not straight forward. We'll revisit this if needed.
|
|
195
|
+
|
|
196
|
+
# Rotation matrix from IMAP spacecraft frame to ECLIPJ2000.
|
|
197
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.pxform
|
|
198
|
+
body_rots = spiceypy.pxform("IMAP_SPACECRAFT", "ECLIPJ2000", tdb)
|
|
199
|
+
# Convert rotation matrix to quaternion.
|
|
200
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.m2q
|
|
201
|
+
body_quat = spiceypy.m2q(body_rots)
|
|
202
|
+
|
|
203
|
+
# Standardize the quaternion so that they may be compared.
|
|
204
|
+
body_quat = body_quat * np.sign(body_quat[0])
|
|
205
|
+
# Aggregate quaternions into a single matrix.
|
|
206
|
+
aggregate += np.outer(body_quat, body_quat)
|
|
207
|
+
|
|
208
|
+
# Reference: "On Averaging Rotations".
|
|
209
|
+
# Link: https://link.springer.com/content/pdf/10.1023/A:1011129215388.pdf
|
|
210
|
+
aggregate /= len(et_times)
|
|
211
|
+
|
|
212
|
+
# Compute eigen values and vectors of the matrix A
|
|
213
|
+
# Eigenvalues tell you how much "influence" each
|
|
214
|
+
# direction (eigenvector) has.
|
|
215
|
+
# The largest eigenvalue corresponds to the direction
|
|
216
|
+
# that has the most influence.
|
|
217
|
+
# The eigenvector corresponding to the largest
|
|
218
|
+
# eigenvalue points in the direction that has the most
|
|
219
|
+
# combined rotation influence.
|
|
220
|
+
eigvals, eigvecs = np.linalg.eig(aggregate)
|
|
221
|
+
# q0: The scalar part of the quaternion.
|
|
222
|
+
# q1, q2, q3: The vector part of the quaternion.
|
|
223
|
+
q_avg = eigvecs[:, np.argmax(eigvals)]
|
|
224
|
+
|
|
225
|
+
return q_avg
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _create_rotation_matrix(et_times: np.ndarray) -> NDArray:
|
|
229
|
+
"""
|
|
230
|
+
Create a rotation matrix.
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
et_times : numpy.ndarray
|
|
235
|
+
Array of times between et_start and et_end.
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
rotation_matrix : np.ndarray
|
|
240
|
+
Rotation matrix.
|
|
241
|
+
"""
|
|
242
|
+
# Averaged quaternions.
|
|
243
|
+
q_avg = _average_quaternions(et_times)
|
|
244
|
+
|
|
245
|
+
# Converts the averaged quaternion (q_avg) into a rotation matrix
|
|
246
|
+
# and get inertial z axis.
|
|
247
|
+
# https://spiceypy.readthedocs.io/en/main/documentation.html#spiceypy.spiceypy.q2m
|
|
248
|
+
z_avg = spiceypy.q2m(list(q_avg))[:, 2]
|
|
249
|
+
# y_avg is perpendicular to both z_avg and the standard Z-axis.
|
|
250
|
+
y_avg = np.cross(z_avg, [0, 0, 1])
|
|
251
|
+
# x_avg is perpendicular to y_avg and z_avg.
|
|
252
|
+
x_avg = np.cross(y_avg, z_avg)
|
|
253
|
+
|
|
254
|
+
# Construct the rotation matrix from x_avg, y_avg, z_avg
|
|
255
|
+
rotation_matrix = np.asarray([x_avg, y_avg, z_avg])
|
|
256
|
+
|
|
257
|
+
return rotation_matrix
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Functions for retrieving repointing table data."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from numpy import typing as npt
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_repoint_data() -> pd.DataFrame:
|
|
16
|
+
"""
|
|
17
|
+
Read repointing file using environment variable and return as dataframe.
|
|
18
|
+
|
|
19
|
+
Pointing and repointing nomenclature can be confusing. In this case,
|
|
20
|
+
repoint is taken to mean a repoint maneuver. Thus, repoint_start and repoint_end
|
|
21
|
+
are the times that bound when the spacecraft is performing a repointing maneuver.
|
|
22
|
+
This is different from a pointing which is the time between repointing maneuvers.
|
|
23
|
+
|
|
24
|
+
REPOINT_DATA_FILEPATH environment variable should point to a local
|
|
25
|
+
file where the repointing csv file is located.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
repoint_df : pandas.DataFrame
|
|
30
|
+
The repointing csv loaded into a pandas dataframe. The dataframe will
|
|
31
|
+
contain the following columns:
|
|
32
|
+
|
|
33
|
+
* `repoint_start_sec_sclk`: Starting MET seconds of repoint maneuver.
|
|
34
|
+
* `repoint_start_subsec_sclk`: Starting MET microseconds of repoint
|
|
35
|
+
maneuver.
|
|
36
|
+
* `repoint_start_met`: Floating point MET of repoint maneuver start time.
|
|
37
|
+
Derived from `repoint_start_sec_sclk` and `repoint_start_subsec_sclk`.
|
|
38
|
+
* `repoint_start_utc`: UTC time of repoint maneuver start time.
|
|
39
|
+
* `repoint_end_sec_sclk`: Ending MET seconds of repoint maneuver.
|
|
40
|
+
* `repoint_end_subsec_sclk`: Ending MET microseconds of repoint maneuver.
|
|
41
|
+
* `repoint_end_met`: Floating point MET of repoint maneuver end time.
|
|
42
|
+
Derived from `repoint_end_sec_sclk` and `repoint_end_subsec_sclk`.
|
|
43
|
+
* `repoint_end_utc`: UTC time of repoint maneuver end time.
|
|
44
|
+
* `repoint_id`: Unique ID number of each repoint maneuver.
|
|
45
|
+
"""
|
|
46
|
+
repoint_data_filepath = os.getenv("REPOINT_DATA_FILEPATH")
|
|
47
|
+
if repoint_data_filepath is not None:
|
|
48
|
+
path_to_spin_file = Path(repoint_data_filepath)
|
|
49
|
+
else:
|
|
50
|
+
# Handle the case where the environment variable is not set
|
|
51
|
+
raise ValueError("REPOINT_DATA_FILEPATH environment variable is not set.")
|
|
52
|
+
|
|
53
|
+
logger.info(f"Reading repointing data from {path_to_spin_file}")
|
|
54
|
+
repoint_df = pd.read_csv(path_to_spin_file, comment="#")
|
|
55
|
+
|
|
56
|
+
# Compute times by combining seconds and subseconds fields
|
|
57
|
+
repoint_df["repoint_start_met"] = (
|
|
58
|
+
repoint_df["repoint_start_sec_sclk"]
|
|
59
|
+
+ repoint_df["repoint_start_subsec_sclk"] / 1e6
|
|
60
|
+
)
|
|
61
|
+
repoint_df["repoint_end_met"] = (
|
|
62
|
+
repoint_df["repoint_end_sec_sclk"] + repoint_df["repoint_end_subsec_sclk"] / 1e6
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return repoint_df
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def interpolate_repoint_data(
|
|
69
|
+
query_met_times: Union[float, npt.NDArray],
|
|
70
|
+
) -> pd.DataFrame:
|
|
71
|
+
"""
|
|
72
|
+
Interpolate repointing data to the queried MET times.
|
|
73
|
+
|
|
74
|
+
In addition to the repoint start, end, and id values that come directly from
|
|
75
|
+
the universal repointing table, a column is added to the output dataframe
|
|
76
|
+
which indicates whether each query met time occurs during a repoint maneuver
|
|
77
|
+
i.e. between the repoint start and end times of a row in the repointing
|
|
78
|
+
table.
|
|
79
|
+
|
|
80
|
+
Query times that are more than 24-hours after that last repoint start time
|
|
81
|
+
in the repoint table will cause an error to be raised. The assumption here
|
|
82
|
+
is that we shouldn't be processing data that occurs that close to the next
|
|
83
|
+
expected repoint start time before getting an updated repoint table.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
query_met_times : float or np.ndarray
|
|
88
|
+
Query times in Mission Elapsed Time (MET).
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
repoint_df : pandas.DataFrame
|
|
93
|
+
Repoint table data interpolated such that there is one row
|
|
94
|
+
for each of the queried MET times. Output columns are:
|
|
95
|
+
|
|
96
|
+
* `repoint_start_sec_sclk`
|
|
97
|
+
* `repoint_start_subsec_sclk`
|
|
98
|
+
* `repoint_start_met`
|
|
99
|
+
* `repoint_end_sec_sclk`
|
|
100
|
+
* `repoint_end_subsec_sclk`
|
|
101
|
+
* `repoint_end_met`
|
|
102
|
+
* `repoint_id`
|
|
103
|
+
* `repoint_in_progress`
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
ValueError : If any of the query_met_times are before the first repoint
|
|
108
|
+
start time or after the last repoint start time plus 24-hours.
|
|
109
|
+
"""
|
|
110
|
+
repoint_df = get_repoint_data()
|
|
111
|
+
|
|
112
|
+
# Ensure query_met_times is an array
|
|
113
|
+
query_met_times = np.atleast_1d(query_met_times)
|
|
114
|
+
|
|
115
|
+
# Make sure no query times are before the first repoint in the dataframe.
|
|
116
|
+
repoint_df_start_met = repoint_df["repoint_start_met"].values[0]
|
|
117
|
+
if np.any(query_met_times < repoint_df_start_met):
|
|
118
|
+
bad_times = query_met_times[query_met_times < repoint_df_start_met]
|
|
119
|
+
raise ValueError(
|
|
120
|
+
f"{bad_times.size} query times are before the first repoint start "
|
|
121
|
+
f" time in the repoint table. {bad_times=}, {repoint_df_start_met=}"
|
|
122
|
+
)
|
|
123
|
+
# Make sure that no query times are after the valid range of the dataframe.
|
|
124
|
+
# We approximate the end time of the table by adding 24 hours to the last
|
|
125
|
+
# known repoint start time.
|
|
126
|
+
repoint_df_end_met = repoint_df["repoint_start_met"].values[-1] + 24 * 60 * 60
|
|
127
|
+
if np.any(query_met_times >= repoint_df_end_met):
|
|
128
|
+
bad_times = query_met_times[query_met_times >= repoint_df_end_met]
|
|
129
|
+
raise ValueError(
|
|
130
|
+
f"{bad_times.size} query times are after the valid time of the "
|
|
131
|
+
f"pointing table. The valid end time is 24-hours after the last "
|
|
132
|
+
f"repoint_start_time. {bad_times=}, {repoint_df_end_met=}"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Find the row index for each queried MET time such that:
|
|
136
|
+
# repoint_start_time[i] <= MET < repoint_start_time[i+1]
|
|
137
|
+
row_indices = (
|
|
138
|
+
np.searchsorted(repoint_df["repoint_start_met"], query_met_times, side="right")
|
|
139
|
+
- 1
|
|
140
|
+
)
|
|
141
|
+
out_df = repoint_df.iloc[row_indices]
|
|
142
|
+
|
|
143
|
+
# Add a column indicating if the query time is during a repoint or not.
|
|
144
|
+
# The table already has the correct row for each query time, so we
|
|
145
|
+
# only need to check if the query time is less than the repoint end time to
|
|
146
|
+
# get the same result as `repoint_start_time <= query_met_times < repoint_end_time`.
|
|
147
|
+
out_df["repoint_in_progress"] = query_met_times < out_df["repoint_end_met"].values
|
|
148
|
+
|
|
149
|
+
return out_df
|
imap_processing/spice/spin.py
CHANGED
|
@@ -22,20 +22,21 @@ def get_spin_data() -> pd.DataFrame:
|
|
|
22
22
|
It could be s3 filepath that can be used to download the data
|
|
23
23
|
through API or it could be path EFS or Batch volume mount path.
|
|
24
24
|
|
|
25
|
-
Spin data should contain the following fields:
|
|
26
|
-
* spin_number
|
|
27
|
-
* spin_start_sec
|
|
28
|
-
* spin_start_subsec
|
|
29
|
-
* spin_period_sec
|
|
30
|
-
* spin_period_valid
|
|
31
|
-
* spin_phase_valid
|
|
32
|
-
* spin_period_source
|
|
33
|
-
* thruster_firing
|
|
34
|
-
|
|
35
25
|
Returns
|
|
36
26
|
-------
|
|
37
27
|
spin_data : pandas.DataFrame
|
|
38
|
-
Spin data.
|
|
28
|
+
Spin data. The DataFrame will have the following columns:
|
|
29
|
+
|
|
30
|
+
* `spin_number`: Unique integer spin number.
|
|
31
|
+
* `spin_start_sec_sclk`: MET seconds of spin start time.
|
|
32
|
+
* `spin_start_subsec_sclk`: MET microseconds of spin start time.
|
|
33
|
+
* `spin_start_met`: Floating point MET seconds of spin start.
|
|
34
|
+
* `spin_start_utc`: UTC string of spin start time.
|
|
35
|
+
* `spin_period_sec`: Floating point spin period in seconds.
|
|
36
|
+
* `spin_period_valid`: Boolean indicating whether spin period is valid.
|
|
37
|
+
* `spin_phase_valid`: Boolean indicating whether spin phase is valid.
|
|
38
|
+
* `spin_period_source`: Source used for determining spin period.
|
|
39
|
+
* `thruster_firing`: Boolean indicating whether thruster is firing.
|
|
39
40
|
"""
|
|
40
41
|
spin_data_filepath = os.getenv("SPIN_DATA_FILEPATH")
|
|
41
42
|
if spin_data_filepath is not None:
|
|
@@ -44,11 +45,24 @@ def get_spin_data() -> pd.DataFrame:
|
|
|
44
45
|
# Handle the case where the environment variable is not set
|
|
45
46
|
raise ValueError("SPIN_DATA_FILEPATH environment variable is not set.")
|
|
46
47
|
|
|
47
|
-
spin_df = pd.read_csv(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
spin_df = pd.read_csv(
|
|
49
|
+
path_to_spin_file,
|
|
50
|
+
comment="#",
|
|
51
|
+
dtype={
|
|
52
|
+
"spin_number": int,
|
|
53
|
+
"spin_start_sec_sclk": int,
|
|
54
|
+
"spin_start_subsec_sclk": int,
|
|
55
|
+
"spin_start_utc": str,
|
|
56
|
+
"spin_period_sec": float,
|
|
57
|
+
"spin_period_valid": bool,
|
|
58
|
+
"spin_period_source": int,
|
|
59
|
+
"thruster_firing": bool,
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
# Combine spin_start_sec_sclk and spin_start_subsec_sclk to get the spin start
|
|
63
|
+
# time in seconds. The spin start subseconds are in microseconds.
|
|
64
|
+
spin_df["spin_start_met"] = (
|
|
65
|
+
spin_df["spin_start_sec_sclk"] + spin_df["spin_start_subsec_sclk"] / 1e6
|
|
52
66
|
)
|
|
53
67
|
|
|
54
68
|
return spin_df
|
|
@@ -71,18 +85,9 @@ def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.Data
|
|
|
71
85
|
Returns
|
|
72
86
|
-------
|
|
73
87
|
spin_df : pandas.DataFrame
|
|
74
|
-
Spin table data
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
* spin_start_sec
|
|
78
|
-
* spin_start_subsec
|
|
79
|
-
* spin_period_sec
|
|
80
|
-
* spin_period_valid
|
|
81
|
-
* spin_phase_valid
|
|
82
|
-
* spin_period_source
|
|
83
|
-
* thruster_firing
|
|
84
|
-
* spin_start_met
|
|
85
|
-
* sc_spin_phase
|
|
88
|
+
Spin table data interpolated for each queried MET time. In addition to
|
|
89
|
+
the columns output from :py:func:`get_spin_data`, the `sc_spin_phase`
|
|
90
|
+
column is added and is uniquely computed for each queried MET time.
|
|
86
91
|
"""
|
|
87
92
|
spin_df = get_spin_data()
|
|
88
93
|
|
|
@@ -95,9 +100,9 @@ def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.Data
|
|
|
95
100
|
query_met_times = np.atleast_1d(query_met_times)
|
|
96
101
|
|
|
97
102
|
# Make sure input times are within the bounds of spin data
|
|
98
|
-
spin_df_start_time = spin_df["
|
|
103
|
+
spin_df_start_time = spin_df["spin_start_met"].values[0]
|
|
99
104
|
spin_df_end_time = (
|
|
100
|
-
spin_df["
|
|
105
|
+
spin_df["spin_start_met"].values[-1] + spin_df["spin_period_sec"].values[-1]
|
|
101
106
|
)
|
|
102
107
|
input_start_time = query_met_times.min()
|
|
103
108
|
input_end_time = query_met_times.max()
|
|
@@ -115,13 +120,13 @@ def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.Data
|
|
|
115
120
|
# >>> np.searchsorted(df['a'], [0, 13, 15, 32, 70], side='right')
|
|
116
121
|
# array([1, 1, 2, 3, 5])
|
|
117
122
|
last_spin_indices = (
|
|
118
|
-
np.searchsorted(spin_df["
|
|
123
|
+
np.searchsorted(spin_df["spin_start_met"], query_met_times, side="right") - 1
|
|
119
124
|
)
|
|
120
125
|
# Generate a dataframe with one row per query time
|
|
121
126
|
out_df = spin_df.iloc[last_spin_indices]
|
|
122
127
|
|
|
123
128
|
# Calculate spin phase
|
|
124
|
-
spin_phases = (query_met_times - out_df["
|
|
129
|
+
spin_phases = (query_met_times - out_df["spin_start_met"].values) / out_df[
|
|
125
130
|
"spin_period_sec"
|
|
126
131
|
].values
|
|
127
132
|
|
|
@@ -185,7 +190,7 @@ def get_spacecraft_spin_phase(
|
|
|
185
190
|
Get the spacecraft spin phase for the input query times.
|
|
186
191
|
|
|
187
192
|
Formula to calculate spin phase:
|
|
188
|
-
spin_phase = (query_met_times -
|
|
193
|
+
spin_phase = (query_met_times - spin_start_met) / spin_period_sec
|
|
189
194
|
|
|
190
195
|
Parameters
|
|
191
196
|
----------
|
imap_processing/spice/time.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
4
|
from collections.abc import Collection, Iterable
|
|
5
|
+
from datetime import datetime
|
|
5
6
|
from typing import Union
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
@@ -297,3 +298,26 @@ def et_to_utc(
|
|
|
297
298
|
UTC time(s).
|
|
298
299
|
"""
|
|
299
300
|
return spiceypy.et2utc(et, format_str, precision, utclen)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def epoch_to_doy(epoch: np.ndarray) -> npt.NDArray:
|
|
304
|
+
"""
|
|
305
|
+
Convert epoch times to day of year (1-365/366).
|
|
306
|
+
|
|
307
|
+
Parameters
|
|
308
|
+
----------
|
|
309
|
+
epoch : xarray.DataArray
|
|
310
|
+
Time, number of nanoseconds since J2000 with leap seconds included.
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
day_of_year : numpy.ndarray
|
|
315
|
+
Day of year (1-365/366) for each epoch value.
|
|
316
|
+
"""
|
|
317
|
+
et = ttj2000ns_to_et(epoch.data)
|
|
318
|
+
# Get UTC time strings in ISO calendar format
|
|
319
|
+
time_strings = et_to_utc(et, "ISOC")
|
|
320
|
+
# Extract DOY from datetime
|
|
321
|
+
return np.array(
|
|
322
|
+
[datetime.fromisoformat(date).timetuple().tm_yday for date in time_strings]
|
|
323
|
+
)
|
|
@@ -72,8 +72,7 @@ def filter_good_data(full_sweep_sci: xr.Dataset) -> npt.NDArray:
|
|
|
72
72
|
f"{full_sweep_sci['sweep_table'].data[bad_cycle_indices]}"
|
|
73
73
|
)
|
|
74
74
|
logger.debug(
|
|
75
|
-
"Plan ID should be same: "
|
|
76
|
-
f"{full_sweep_sci['plan_id'].data[bad_cycle_indices]}"
|
|
75
|
+
f"Plan ID should be same: {full_sweep_sci['plan_id'].data[bad_cycle_indices]}"
|
|
77
76
|
)
|
|
78
77
|
logger.debug(
|
|
79
78
|
f"Mode Id should be 3(HVSCI): {full_sweep_sci['mode'].data[bad_cycle_indices]}"
|
|
@@ -426,7 +425,7 @@ def process_sweep_data(full_sweep_sci: xr.Dataset, cem_prefix: str) -> xr.Datase
|
|
|
426
425
|
|
|
427
426
|
|
|
428
427
|
def process_swapi_science(
|
|
429
|
-
sci_dataset: xr.Dataset, hk_dataset: xr.Dataset
|
|
428
|
+
sci_dataset: xr.Dataset, hk_dataset: xr.Dataset
|
|
430
429
|
) -> xr.Dataset:
|
|
431
430
|
"""
|
|
432
431
|
Will process SWAPI science data and create CDF file.
|
|
@@ -437,8 +436,6 @@ def process_swapi_science(
|
|
|
437
436
|
L0 data.
|
|
438
437
|
hk_dataset : xarray.Dataset
|
|
439
438
|
Housekeeping data.
|
|
440
|
-
data_version : str
|
|
441
|
-
Version of the data product being created.
|
|
442
439
|
|
|
443
440
|
Returns
|
|
444
441
|
-------
|
|
@@ -509,6 +506,10 @@ def process_swapi_science(
|
|
|
509
506
|
# since we are not processing in real-time, the ground processing
|
|
510
507
|
# algorithm should use the closest timestamp HK packet to fill in
|
|
511
508
|
# the data quality for the SCI data per SWAPI team.
|
|
509
|
+
|
|
510
|
+
# Drop duplicate epoch values in HK data. Otherwise, the nearest
|
|
511
|
+
# method will not work as expected because .sel requires unique values.
|
|
512
|
+
hk_dataset = hk_dataset.drop_duplicates("epoch")
|
|
512
513
|
good_sweep_times = good_sweep_sci["epoch"].data
|
|
513
514
|
good_sweep_hk_data = hk_dataset.sel({"epoch": good_sweep_times}, method="nearest")
|
|
514
515
|
|
|
@@ -582,8 +583,6 @@ def process_swapi_science(
|
|
|
582
583
|
)
|
|
583
584
|
|
|
584
585
|
# Add other global attributes
|
|
585
|
-
# TODO: add others like below once add_global_attribute is fixed
|
|
586
|
-
cdf_manager.add_global_attribute("Data_version", data_version)
|
|
587
586
|
l1_global_attrs = cdf_manager.get_global_attributes("imap_swapi_l1_sci")
|
|
588
587
|
l1_global_attrs["Apid"] = f"{sci_dataset['pkt_apid'].data[0]}"
|
|
589
588
|
|
|
@@ -628,6 +627,18 @@ def process_swapi_science(
|
|
|
628
627
|
dims=["epoch"],
|
|
629
628
|
attrs=cdf_manager.get_variable_attributes("plan_id"),
|
|
630
629
|
)
|
|
630
|
+
# Add ESA_LVL5 for L2 and L3 purposes.
|
|
631
|
+
# We need to store ESA_LVL5 at SEQ_NUMBER==11
|
|
632
|
+
# which is 71 energy step's ESA_LVL5 value. ESA_LVL5 gets
|
|
633
|
+
# updated every 6th step. This is used in L2 to calculate last 9 fine
|
|
634
|
+
# energy steps.
|
|
635
|
+
dataset["esa_lvl5"] = xr.DataArray(
|
|
636
|
+
good_sweep_sci["esa_lvl5"].data.reshape(total_full_sweeps, 12)[:, 11],
|
|
637
|
+
name="esa_lvl5",
|
|
638
|
+
dims=["epoch"],
|
|
639
|
+
attrs=cdf_manager.get_variable_attributes("esa_lvl5"),
|
|
640
|
+
)
|
|
641
|
+
|
|
631
642
|
# Add these additional housekeeping support data
|
|
632
643
|
# SWP_HK.LUT_CHOICE - Which LUT is in use
|
|
633
644
|
# SWP_HK.FPGA_TYPE - Type number of the FPGA
|
|
@@ -699,7 +710,7 @@ def process_swapi_science(
|
|
|
699
710
|
return dataset
|
|
700
711
|
|
|
701
712
|
|
|
702
|
-
def swapi_l1(dependencies: list
|
|
713
|
+
def swapi_l1(dependencies: list) -> xr.Dataset:
|
|
703
714
|
"""
|
|
704
715
|
Will process SWAPI level 0 data to level 1.
|
|
705
716
|
|
|
@@ -707,8 +718,6 @@ def swapi_l1(dependencies: list, data_version: str) -> xr.Dataset:
|
|
|
707
718
|
----------
|
|
708
719
|
dependencies : list
|
|
709
720
|
Input dependencies needed for L1 processing.
|
|
710
|
-
data_version : str
|
|
711
|
-
Version of the data product being created.
|
|
712
721
|
|
|
713
722
|
Returns
|
|
714
723
|
-------
|
|
@@ -740,7 +749,7 @@ def swapi_l1(dependencies: list, data_version: str) -> xr.Dataset:
|
|
|
740
749
|
):
|
|
741
750
|
# process science data
|
|
742
751
|
sci_dataset = process_swapi_science(
|
|
743
|
-
l0_unpacked_dict[SWAPIAPID.SWP_SCI], l1_hk_ds
|
|
752
|
+
l0_unpacked_dict[SWAPIAPID.SWP_SCI], l1_hk_ds
|
|
744
753
|
)
|
|
745
754
|
processed_data.append(sci_dataset)
|
|
746
755
|
|
|
@@ -749,7 +758,6 @@ def swapi_l1(dependencies: list, data_version: str) -> xr.Dataset:
|
|
|
749
758
|
# Add HK datalevel attrs
|
|
750
759
|
imap_attrs = ImapCdfAttributes()
|
|
751
760
|
imap_attrs.add_instrument_global_attrs("swapi")
|
|
752
|
-
imap_attrs.add_global_attribute("Data_version", data_version)
|
|
753
761
|
imap_attrs.add_instrument_variable_attrs(instrument="swapi", level=None)
|
|
754
762
|
hk_ds.attrs.update(imap_attrs.get_global_attributes("imap_swapi_l1_hk"))
|
|
755
763
|
hk_common_attrs = imap_attrs.get_variable_attributes("hk_attrs")
|