imap-processing 0.6.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.
- imap_processing/__init__.py +34 -0
- imap_processing/_version.py +3 -0
- imap_processing/ccsds/__init__.py +0 -0
- imap_processing/ccsds/ccsds_data.py +55 -0
- imap_processing/ccsds/excel_to_xtce.py +477 -0
- imap_processing/cdf/__init__.py +0 -0
- imap_processing/cdf/cdf_attribute_manager.py +322 -0
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +212 -0
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +1358 -0
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +391 -0
- imap_processing/cdf/config/imap_constant_attrs.yaml +33 -0
- imap_processing/cdf/config/imap_default_global_cdf_attrs.yaml +17 -0
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +41 -0
- imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +499 -0
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +334 -0
- imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +51 -0
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +435 -0
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -0
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +493 -0
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +564 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +24 -0
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +426 -0
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +90 -0
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +487 -0
- imap_processing/cdf/config/imap_lo_l1b_variable_attrs.yaml +121 -0
- imap_processing/cdf/config/imap_lo_l1c_variable_attrs.yaml +179 -0
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +97 -0
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +201 -0
- imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +33 -0
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +137 -0
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +24 -0
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +234 -0
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +273 -0
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +100 -0
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +52 -0
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +297 -0
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +121 -0
- imap_processing/cdf/config/shared/default_global_cdf_attrs_schema.yaml +246 -0
- imap_processing/cdf/config/shared/default_variable_cdf_attrs_schema.yaml +466 -0
- imap_processing/cdf/imap_cdf_manager.py +64 -0
- imap_processing/cdf/utils.py +147 -0
- imap_processing/cli.py +863 -0
- imap_processing/codice/__init__.py +1 -0
- imap_processing/codice/codice_l0.py +54 -0
- imap_processing/codice/codice_l1a.py +558 -0
- imap_processing/codice/codice_l1b.py +194 -0
- imap_processing/codice/constants.py +986 -0
- imap_processing/codice/data/esa_sweep_values.csv +257 -0
- imap_processing/codice/data/lo_stepping_values.csv +129 -0
- imap_processing/codice/decompress.py +142 -0
- imap_processing/codice/packet_definitions/P_COD_NHK.xml +618 -0
- imap_processing/codice/packet_definitions/codice_packet_definition.xml +5073 -0
- imap_processing/codice/utils.py +95 -0
- imap_processing/decom.py +40 -0
- imap_processing/glows/__init__.py +1 -0
- imap_processing/glows/ancillary/l1b_conversion_table_v001.json +42 -0
- imap_processing/glows/l0/__init__.py +0 -0
- imap_processing/glows/l0/decom_glows.py +91 -0
- imap_processing/glows/l0/glows_l0_data.py +194 -0
- imap_processing/glows/l1a/glows_l1a.py +424 -0
- imap_processing/glows/l1a/glows_l1a_data.py +555 -0
- imap_processing/glows/l1b/glows_l1b.py +270 -0
- imap_processing/glows/l1b/glows_l1b_data.py +583 -0
- imap_processing/glows/packet_definitions/GLX_COMBINED.xml +254 -0
- imap_processing/glows/packet_definitions/P_GLX_TMSCDE.xml +97 -0
- imap_processing/glows/packet_definitions/P_GLX_TMSCHIST.xml +215 -0
- imap_processing/glows/utils/__init__.py +0 -0
- imap_processing/glows/utils/constants.py +105 -0
- imap_processing/hi/__init__.py +1 -0
- imap_processing/hi/l0/__init__.py +0 -0
- imap_processing/hi/l0/decom_hi.py +24 -0
- imap_processing/hi/l1a/__init__.py +0 -0
- imap_processing/hi/l1a/hi_l1a.py +73 -0
- imap_processing/hi/l1a/histogram.py +142 -0
- imap_processing/hi/l1a/housekeeping.py +27 -0
- imap_processing/hi/l1a/science_direct_event.py +341 -0
- imap_processing/hi/l1b/__init__.py +0 -0
- imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +154 -0
- imap_processing/hi/l1b/hi_l1b.py +127 -0
- imap_processing/hi/l1c/__init__.py +0 -0
- imap_processing/hi/l1c/hi_l1c.py +228 -0
- imap_processing/hi/packet_definitions/__init__.py +0 -0
- imap_processing/hi/packet_definitions/hi_packet_definition.xml +482 -0
- imap_processing/hi/utils.py +27 -0
- imap_processing/hit/__init__.py +1 -0
- imap_processing/hit/l0/__init__.py +0 -0
- imap_processing/hit/l0/data_classes/housekeeping.py +240 -0
- imap_processing/hit/l0/data_classes/science_packet.py +259 -0
- imap_processing/hit/l0/decom_hit.py +467 -0
- imap_processing/hit/l0/utils/hit_base.py +57 -0
- imap_processing/hit/l1a/__init__.py +0 -0
- imap_processing/hit/l1a/hit_l1a.py +254 -0
- imap_processing/hit/l1b/hit_l1b.py +179 -0
- imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1276 -0
- imap_processing/ialirt/__init__.py +0 -0
- imap_processing/ialirt/l0/__init__.py +0 -0
- imap_processing/ialirt/l0/process_hit.py +220 -0
- imap_processing/ialirt/packet_definitions/__init__.py +0 -0
- imap_processing/ialirt/packet_definitions/ialirt.xml +778 -0
- imap_processing/ialirt/packet_definitions/ialirt_hit.xml +186 -0
- imap_processing/idex/__init__.py +2 -0
- imap_processing/idex/idex_constants.py +27 -0
- imap_processing/idex/idex_l0.py +31 -0
- imap_processing/idex/idex_l1a.py +631 -0
- imap_processing/idex/packet_definitions/idex_packet_definition.xml +3162 -0
- imap_processing/lo/__init__.py +1 -0
- imap_processing/lo/l0/__init__.py +0 -0
- imap_processing/lo/l0/data_classes/science_direct_events.py +215 -0
- imap_processing/lo/l0/data_classes/star_sensor.py +98 -0
- imap_processing/lo/l0/decompression_tables/12_to_16_bit.csv +4097 -0
- imap_processing/lo/l0/decompression_tables/8_to_12_bit.csv +257 -0
- imap_processing/lo/l0/decompression_tables/8_to_16_bit.csv +257 -0
- imap_processing/lo/l0/decompression_tables/decompression_tables.py +75 -0
- imap_processing/lo/l0/lo_apid.py +15 -0
- imap_processing/lo/l0/lo_science.py +150 -0
- imap_processing/lo/l0/utils/binary_string.py +59 -0
- imap_processing/lo/l0/utils/bit_decompression.py +62 -0
- imap_processing/lo/l0/utils/lo_base.py +57 -0
- imap_processing/lo/l1a/__init__.py +0 -0
- imap_processing/lo/l1a/lo_l1a.py +157 -0
- imap_processing/lo/l1b/lo_l1b.py +160 -0
- imap_processing/lo/l1c/lo_l1c.py +180 -0
- imap_processing/lo/packet_definitions/lo_xtce.xml +3541 -0
- imap_processing/mag/__init__.py +2 -0
- imap_processing/mag/constants.py +108 -0
- imap_processing/mag/l0/decom_mag.py +170 -0
- imap_processing/mag/l0/mag_l0_data.py +118 -0
- imap_processing/mag/l1a/mag_l1a.py +317 -0
- imap_processing/mag/l1a/mag_l1a_data.py +1007 -0
- imap_processing/mag/l1b/__init__.py +0 -0
- imap_processing/mag/l1b/imap_calibration_mag_20240229_v01.cdf +0 -0
- imap_processing/mag/l1b/mag_l1b.py +125 -0
- imap_processing/mag/l1c/mag_l1c.py +57 -0
- imap_processing/mag/packet_definitions/MAG_SCI_COMBINED.xml +235 -0
- imap_processing/quality_flags.py +91 -0
- imap_processing/spice/__init__.py +1 -0
- imap_processing/spice/geometry.py +322 -0
- imap_processing/spice/kernels.py +459 -0
- imap_processing/spice/time.py +72 -0
- imap_processing/swapi/__init__.py +1 -0
- imap_processing/swapi/l1/__init__.py +0 -0
- imap_processing/swapi/l1/swapi_l1.py +685 -0
- imap_processing/swapi/l2/__init__.py +0 -0
- imap_processing/swapi/l2/swapi_l2.py +107 -0
- imap_processing/swapi/packet_definitions/__init__.py +0 -0
- imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +708 -0
- imap_processing/swapi/swapi_utils.py +25 -0
- imap_processing/swe/__init__.py +1 -0
- imap_processing/swe/l1a/__init__.py +0 -0
- imap_processing/swe/l1a/swe_l1a.py +48 -0
- imap_processing/swe/l1a/swe_science.py +223 -0
- imap_processing/swe/l1b/engineering_unit_convert_table.csv +65 -0
- imap_processing/swe/l1b/swe_esa_lookup_table.csv +1441 -0
- imap_processing/swe/l1b/swe_l1b.py +49 -0
- imap_processing/swe/l1b/swe_l1b_science.py +557 -0
- imap_processing/swe/packet_definitions/__init__.py +0 -0
- imap_processing/swe/packet_definitions/swe_packet_definition.xml +303 -0
- imap_processing/swe/utils/__init__.py +0 -0
- imap_processing/swe/utils/swe_utils.py +9 -0
- imap_processing/tests/__init__.py +0 -0
- imap_processing/tests/ccsds/test_data/expected_output.xml +171 -0
- imap_processing/tests/ccsds/test_excel_to_xtce.py +285 -0
- imap_processing/tests/cdf/__init__.py +0 -0
- imap_processing/tests/cdf/imap_default_global_cdf_attrs.yaml +8 -0
- imap_processing/tests/cdf/shared/default_global_cdf_attrs_schema.yaml +246 -0
- imap_processing/tests/cdf/shared/default_variable_cdf_attrs_schema.yaml +466 -0
- imap_processing/tests/cdf/test_cdf_attribute_manager.py +353 -0
- imap_processing/tests/cdf/test_data/imap_default_global_test_cdf_attrs.yaml +7 -0
- imap_processing/tests/cdf/test_data/imap_instrument1_global_cdf_attrs.yaml +14 -0
- imap_processing/tests/cdf/test_data/imap_instrument1_level1_variable_attrs.yaml +23 -0
- imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +23 -0
- imap_processing/tests/cdf/test_data/imap_instrument2_level2_variable_attrs.yaml +30 -0
- imap_processing/tests/cdf/test_data/imap_test_global.yaml +26 -0
- imap_processing/tests/cdf/test_data/imap_test_variable.yaml +41 -0
- imap_processing/tests/cdf/test_imap_cdf_manager.py +62 -0
- imap_processing/tests/cdf/test_utils.py +109 -0
- imap_processing/tests/codice/__init__.py +0 -0
- imap_processing/tests/codice/conftest.py +56 -0
- imap_processing/tests/codice/data/eu_unit_lookup_table.csv +101 -0
- imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +100 -0
- imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +100 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-counters-aggregated_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-counters-singles_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-omni_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-pha_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-sectored_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hskp_20100101_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-counters-aggregated_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-counters-singles_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-angular_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-priority_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-species_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-pha_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-angular_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-priority_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-species_20240429_v001.pkts +0 -0
- 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/codice/test_codice_l0.py +144 -0
- imap_processing/tests/codice/test_codice_l1a.py +187 -0
- imap_processing/tests/codice/test_codice_l1b.py +60 -0
- imap_processing/tests/codice/test_decompress.py +50 -0
- imap_processing/tests/conftest.py +372 -0
- imap_processing/tests/glows/direct_events_validation_data_l1a.csv +5704 -0
- imap_processing/tests/glows/glows_test_packet_20110921_v01.pkts +0 -0
- imap_processing/tests/glows/test_glows_decom.py +133 -0
- imap_processing/tests/glows/test_glows_l1a_cdf.py +85 -0
- imap_processing/tests/glows/test_glows_l1a_data.py +510 -0
- imap_processing/tests/glows/test_glows_l1b.py +348 -0
- imap_processing/tests/glows/test_glows_l1b_data.py +70 -0
- imap_processing/tests/hi/__init__.py +0 -0
- imap_processing/tests/hi/conftest.py +133 -0
- imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.bin +0 -0
- imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.csv +201 -0
- imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_CNT.bin +0 -0
- imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_DE.bin +0 -0
- imap_processing/tests/hi/test_data/l0/README.txt +54 -0
- imap_processing/tests/hi/test_decom.py +55 -0
- imap_processing/tests/hi/test_hi_l1b.py +31 -0
- imap_processing/tests/hi/test_hi_l1c.py +69 -0
- imap_processing/tests/hi/test_l1a.py +96 -0
- imap_processing/tests/hi/test_l1a_sci_de.py +72 -0
- imap_processing/tests/hi/test_utils.py +15 -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/__init__.py +0 -0
- imap_processing/tests/hit/test_data/imap_hit_l0_hk_20100105_v001.pkts +0 -0
- imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
- imap_processing/tests/hit/test_hit_decom.py +230 -0
- imap_processing/tests/hit/test_hit_l1a.py +224 -0
- imap_processing/tests/hit/test_hit_l1b.py +52 -0
- imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +88 -0
- imap_processing/tests/ialirt/__init__.py +0 -0
- imap_processing/tests/ialirt/test_data/l0/IALiRT Raw Packet Telemetry.txt +33 -0
- imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.ccsds +0 -0
- imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.csv +1001 -0
- imap_processing/tests/ialirt/unit/__init__.py +0 -0
- imap_processing/tests/ialirt/unit/test_decom_ialirt.py +94 -0
- imap_processing/tests/ialirt/unit/test_process_hit.py +226 -0
- imap_processing/tests/idex/__init__.py +0 -0
- imap_processing/tests/idex/conftest.py +22 -0
- imap_processing/tests/idex/imap_idex_l0_raw_20230725_v001.pkts +0 -0
- imap_processing/tests/idex/impact_14_tof_high_data.txt +8189 -0
- imap_processing/tests/idex/test_idex_l0.py +45 -0
- imap_processing/tests/idex/test_idex_l1a.py +91 -0
- imap_processing/tests/lo/__init__.py +0 -0
- imap_processing/tests/lo/test_binary_string.py +21 -0
- imap_processing/tests/lo/test_bit_decompression.py +39 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l0_raw_20240627_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/lo/test_cdfs/imap_lo_l1b_de_20100101_v001.cdf +0 -0
- imap_processing/tests/lo/test_lo_l1a.py +66 -0
- imap_processing/tests/lo/test_lo_l1b.py +74 -0
- imap_processing/tests/lo/test_lo_l1c.py +66 -0
- imap_processing/tests/lo/test_science_counts.py +41 -0
- imap_processing/tests/lo/test_science_direct_events.py +209 -0
- imap_processing/tests/lo/test_star_sensor.py +35 -0
- imap_processing/tests/mag/imap_mag_l1a_burst-magi_20231025_v001.cdf +0 -0
- imap_processing/tests/mag/mag_l0_test_data.pkts +0 -0
- imap_processing/tests/mag/mag_l0_test_output.csv +37 -0
- imap_processing/tests/mag/mag_l1_test_data.pkts +0 -0
- imap_processing/tests/mag/mag_l1a_test_output.csv +97 -0
- imap_processing/tests/mag/test_mag_decom.py +117 -0
- imap_processing/tests/mag/test_mag_l1a.py +856 -0
- imap_processing/tests/mag/test_mag_l1b.py +77 -0
- imap_processing/tests/mag/test_mag_l1c.py +40 -0
- imap_processing/tests/spice/__init__.py +0 -0
- imap_processing/tests/spice/test_data/imap_ena_sim_metakernel.template +4 -0
- imap_processing/tests/spice/test_data/imap_science_0001.tf +171 -0
- imap_processing/tests/spice/test_data/imap_sclk_0000.tsc +156 -0
- imap_processing/tests/spice/test_data/imap_sim_ck_2hr_2secsampling_with_nutation.bc +0 -0
- imap_processing/tests/spice/test_data/imap_simple_metakernel.template +3 -0
- imap_processing/tests/spice/test_data/imap_spk_demo.bsp +0 -0
- imap_processing/tests/spice/test_data/imap_wkcp.tf +1806 -0
- imap_processing/tests/spice/test_data/naif0012.tls +150 -0
- imap_processing/tests/spice/test_data/sim_1yr_imap_attitude.bc +0 -0
- imap_processing/tests/spice/test_data/sim_1yr_imap_pointing_frame.bc +0 -0
- imap_processing/tests/spice/test_geometry.py +214 -0
- imap_processing/tests/spice/test_kernels.py +272 -0
- imap_processing/tests/spice/test_time.py +35 -0
- imap_processing/tests/swapi/__init__.py +0 -0
- imap_processing/tests/swapi/conftest.py +16 -0
- imap_processing/tests/swapi/l0_data/__init__.py +0 -0
- imap_processing/tests/swapi/l0_data/imap_swapi_l0_raw_20231012_v001.pkts +0 -0
- imap_processing/tests/swapi/l0_validation_data/__init__.py +0 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_AUT_20231012_125245.csv +124 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_HK_20231012_125245.csv +98 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_MG_20231012_125245.csv +9 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_SCI_20231012_125245.csv +72 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_AUT_20231012_125245.csv +124 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_HK_20231012_125245.csv +98 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_MG_20231012_125245.csv +9 -0
- imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_SCI_20231012_125245.csv +72 -0
- imap_processing/tests/swapi/test_swapi_decom.py +135 -0
- imap_processing/tests/swapi/test_swapi_l1.py +354 -0
- imap_processing/tests/swapi/test_swapi_l2.py +21 -0
- imap_processing/tests/swe/__init__.py +0 -0
- imap_processing/tests/swe/conftest.py +35 -0
- imap_processing/tests/swe/decompressed/20230927173238_4th_quarter_decompressed.csv +181 -0
- imap_processing/tests/swe/decompressed/20230927173253_1st_quarter_decompressed.csv +181 -0
- imap_processing/tests/swe/decompressed/20230927173308_2nd_quarter_decompressed.csv +181 -0
- imap_processing/tests/swe/decompressed/20230927173323_3rd_quarter_decompressed.csv +181 -0
- imap_processing/tests/swe/l0_data/2024051010_SWE_SCIENCE_packet.bin +0 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_SCIENCE_20240510_092742.csv +544 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_raw.SWE_SCIENCE_20240510_092742.csv +363 -0
- imap_processing/tests/swe/test_swe_l1a.py +12 -0
- imap_processing/tests/swe/test_swe_l1a_science.py +129 -0
- imap_processing/tests/swe/test_swe_l1b.py +61 -0
- imap_processing/tests/swe/test_swe_l1b_science.py +65 -0
- imap_processing/tests/test_cli.py +229 -0
- imap_processing/tests/test_decom.py +66 -0
- imap_processing/tests/test_quality_flags.py +71 -0
- imap_processing/tests/test_utils.py +107 -0
- imap_processing/tests/ultra/__init__.py +0 -0
- imap_processing/tests/ultra/test_data/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
- imap_processing/tests/ultra/test_data/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
- imap_processing/tests/ultra/test_data/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
- imap_processing/tests/ultra/test_data/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +105 -0
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -0
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +702 -0
- imap_processing/tests/ultra/unit/__init__.py +0 -0
- imap_processing/tests/ultra/unit/conftest.py +210 -0
- imap_processing/tests/ultra/unit/test_decom_apid_880.py +98 -0
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +50 -0
- imap_processing/tests/ultra/unit/test_decom_apid_883.py +44 -0
- imap_processing/tests/ultra/unit/test_decom_apid_896.py +104 -0
- imap_processing/tests/ultra/unit/test_lookup_utils.py +68 -0
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +338 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +122 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +57 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +342 -0
- imap_processing/tests/ultra/unit/test_ultra_l1c.py +104 -0
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +35 -0
- imap_processing/ultra/__init__.py +1 -0
- imap_processing/ultra/constants.py +60 -0
- imap_processing/ultra/l0/__init__.py +0 -0
- imap_processing/ultra/l0/decom_tools.py +281 -0
- imap_processing/ultra/l0/decom_ultra.py +278 -0
- imap_processing/ultra/l0/ultra_utils.py +326 -0
- imap_processing/ultra/l1a/__init__.py +0 -0
- imap_processing/ultra/l1a/ultra_l1a.py +319 -0
- imap_processing/ultra/l1b/badtimes.py +26 -0
- imap_processing/ultra/l1b/cullingmask.py +26 -0
- imap_processing/ultra/l1b/de.py +59 -0
- imap_processing/ultra/l1b/extendedspin.py +45 -0
- imap_processing/ultra/l1b/lookup_utils.py +165 -0
- imap_processing/ultra/l1b/ultra_l1b.py +65 -0
- imap_processing/ultra/l1b/ultra_l1b_annotated.py +54 -0
- imap_processing/ultra/l1b/ultra_l1b_extended.py +764 -0
- imap_processing/ultra/l1c/histogram.py +36 -0
- imap_processing/ultra/l1c/pset.py +36 -0
- imap_processing/ultra/l1c/ultra_l1c.py +52 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +54 -0
- imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +32769 -0
- imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
- imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +4097 -0
- imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +2050 -0
- imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +4097 -0
- imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +2050 -0
- imap_processing/ultra/lookup_tables/yadjust.csv +257 -0
- imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +547 -0
- imap_processing/ultra/packet_definitions/__init__.py +0 -0
- imap_processing/ultra/utils/__init__.py +0 -0
- imap_processing/ultra/utils/ultra_l1_utils.py +50 -0
- imap_processing/utils.py +413 -0
- imap_processing-0.6.0.dist-info/LICENSE +21 -0
- imap_processing-0.6.0.dist-info/METADATA +107 -0
- imap_processing-0.6.0.dist-info/RECORD +398 -0
- imap_processing-0.6.0.dist-info/WHEEL +4 -0
- imap_processing-0.6.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Contains code to perform SWE L1b processing."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import xarray as xr
|
|
6
|
+
|
|
7
|
+
from imap_processing import imap_module_directory
|
|
8
|
+
from imap_processing.swe.l1b.swe_l1b_science import swe_l1b_science
|
|
9
|
+
from imap_processing.swe.utils.swe_utils import SWEAPID
|
|
10
|
+
from imap_processing.utils import convert_raw_to_eu
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def swe_l1b(l1a_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
|
|
16
|
+
"""
|
|
17
|
+
Will process data to L1B.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
l1a_dataset : xarray.Dataset
|
|
22
|
+
The l1a data input.
|
|
23
|
+
data_version : str
|
|
24
|
+
Version of the data product being created.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
data : xarray.Dataset
|
|
29
|
+
Processed data to L1B.
|
|
30
|
+
"""
|
|
31
|
+
apid = int(l1a_dataset.attrs["packet_apid"])
|
|
32
|
+
|
|
33
|
+
# convert value from raw to engineering units as needed
|
|
34
|
+
conversion_table_path = str(
|
|
35
|
+
imap_module_directory / "swe/l1b/engineering_unit_convert_table.csv"
|
|
36
|
+
)
|
|
37
|
+
# Look up packet name from APID
|
|
38
|
+
packet_name = next(packet for packet in SWEAPID if packet.value == apid)
|
|
39
|
+
|
|
40
|
+
# Convert raw data to engineering units as needed
|
|
41
|
+
eu_data = convert_raw_to_eu(
|
|
42
|
+
l1a_dataset,
|
|
43
|
+
conversion_table_path=conversion_table_path,
|
|
44
|
+
packet_name=packet_name.name,
|
|
45
|
+
)
|
|
46
|
+
data = swe_l1b_science(eu_data, data_version)
|
|
47
|
+
if data is None:
|
|
48
|
+
logger.info("No data to write to CDF")
|
|
49
|
+
return data
|
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
"""Contains code to perform SWE L1b science processing."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import numpy.typing as npt
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import xarray as xr
|
|
10
|
+
|
|
11
|
+
from imap_processing import imap_module_directory
|
|
12
|
+
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
# ESA voltage and index in the final data table
|
|
17
|
+
esa_voltage_row_index_dict = {
|
|
18
|
+
0.56: 0,
|
|
19
|
+
0.78: 1,
|
|
20
|
+
1.08: 2,
|
|
21
|
+
1.51: 3,
|
|
22
|
+
2.10: 4,
|
|
23
|
+
2.92: 5,
|
|
24
|
+
4.06: 6,
|
|
25
|
+
5.64: 7,
|
|
26
|
+
7.85: 8,
|
|
27
|
+
10.92: 9,
|
|
28
|
+
15.19: 10,
|
|
29
|
+
21.13: 11,
|
|
30
|
+
29.39: 12,
|
|
31
|
+
40.88: 13,
|
|
32
|
+
56.87: 14,
|
|
33
|
+
79.10: 15,
|
|
34
|
+
110.03: 16,
|
|
35
|
+
153.05: 17,
|
|
36
|
+
212.89: 18,
|
|
37
|
+
296.14: 19,
|
|
38
|
+
411.93: 20,
|
|
39
|
+
572.99: 21,
|
|
40
|
+
797.03: 22,
|
|
41
|
+
1108.66: 23,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def read_lookup_table(table_index_value: int) -> Any:
|
|
46
|
+
"""
|
|
47
|
+
Read lookup table from file.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
table_index_value : int
|
|
52
|
+
ESA table index number.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
list
|
|
57
|
+
Line from lookup table todo check.
|
|
58
|
+
"""
|
|
59
|
+
# This is equivalent of os.path.join in Path
|
|
60
|
+
lookup_table_filepath = imap_module_directory / "swe/l1b/swe_esa_lookup_table.csv"
|
|
61
|
+
lookup_table = pd.read_csv(
|
|
62
|
+
lookup_table_filepath,
|
|
63
|
+
index_col="e_step",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if table_index_value == 0:
|
|
67
|
+
return lookup_table.loc[lookup_table["table_index"] == 0]
|
|
68
|
+
elif table_index_value == 1:
|
|
69
|
+
return lookup_table.loc[lookup_table["table_index"] == 1]
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError("Error: Invalid table index value")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def deadtime_correction(counts: np.ndarray, acq_duration: int) -> npt.NDArray:
|
|
75
|
+
"""
|
|
76
|
+
Calculate deadtime correction.
|
|
77
|
+
|
|
78
|
+
Deadtime correction is a technique used in various fields, including
|
|
79
|
+
nuclear physics, radiation detection, and particle counting, to compensate
|
|
80
|
+
for the effects of the time period during which a detector is not able to
|
|
81
|
+
record new events or measurements after detecting a previous event.
|
|
82
|
+
This "deadtime" is essentially the time during which the detector is
|
|
83
|
+
recovering from the previous detection and is unable to detect new events.
|
|
84
|
+
|
|
85
|
+
In particle detectors, there is a finite time required for the detector to
|
|
86
|
+
reset or recover after detecting a particle. During this deadtime, any
|
|
87
|
+
subsequent particles that may have arrived go undetected. As a result,
|
|
88
|
+
the recorded count rate appears to be lower than the actual count rate.
|
|
89
|
+
|
|
90
|
+
Deadtime correction involves mathematically adjusting the measured count
|
|
91
|
+
rates to compensate for this deadtime effect. This correction is crucial
|
|
92
|
+
when dealing with high-intensity sources or particle fluxes, as the deadtime
|
|
93
|
+
can significantly affect the accuracy of the measurements.
|
|
94
|
+
|
|
95
|
+
Deadtime correction is important to ensure accurate measurements and data
|
|
96
|
+
analysis in fields where event detection rates are high and where every
|
|
97
|
+
detected event is critical for understanding physical processes.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
counts : numpy.ndarray
|
|
102
|
+
Counts data before deadtime corrections.
|
|
103
|
+
acq_duration : int
|
|
104
|
+
This is ACQ_DURATION from science packet.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
corrected_count : numpy.ndarray
|
|
109
|
+
Corrected counts.
|
|
110
|
+
"""
|
|
111
|
+
# deadtime will be constant once it's defined.
|
|
112
|
+
# This deadtime value is from previous mission. SWE
|
|
113
|
+
# will give new one once they have it ready.
|
|
114
|
+
# TODO: update deadtime when we get new number
|
|
115
|
+
deadtime = 1.5e-6
|
|
116
|
+
correct = 1.0 - (deadtime * counts / acq_duration)
|
|
117
|
+
correct = np.maximum(0.1, correct)
|
|
118
|
+
corrected_count = np.divide(counts, correct)
|
|
119
|
+
return corrected_count
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def convert_counts_to_rate(data: np.ndarray, acq_duration: int) -> npt.NDArray:
|
|
123
|
+
"""
|
|
124
|
+
Convert counts to rate using sampling time.
|
|
125
|
+
|
|
126
|
+
acq_duration is ACQ_DURATION from science packet.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
data : numpy.ndarray
|
|
131
|
+
Counts data.
|
|
132
|
+
acq_duration : int
|
|
133
|
+
Acquisition duration. acq_duration is in millieseconds.
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
numpy.ndarray
|
|
138
|
+
Count rates array in seconds.
|
|
139
|
+
"""
|
|
140
|
+
# convert milliseconds to seconds
|
|
141
|
+
# Todo: check with SWE team about int or float types.
|
|
142
|
+
acq_duration = int(acq_duration / 1000.0)
|
|
143
|
+
return data / acq_duration
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def calculate_calibration_factor(time: int) -> None:
|
|
147
|
+
"""
|
|
148
|
+
Calculate calibration factor.
|
|
149
|
+
|
|
150
|
+
Steps to calculate calibration factor:
|
|
151
|
+
|
|
152
|
+
1. Convert input time to match time format in the calibration data file.
|
|
153
|
+
2. Find the nearest in time calibration data point.
|
|
154
|
+
3. Linear interpolate between those two nearest time and get factor for input time.
|
|
155
|
+
|
|
156
|
+
What this function is doing:
|
|
157
|
+
|
|
158
|
+
| 1. **Reading Calibration Data**: The function first reads a file containing
|
|
159
|
+
| calibration data for electron measurements over time. This data helps
|
|
160
|
+
| adjust or correct the measurements based on changes in the instrument's
|
|
161
|
+
| sensitivity.
|
|
162
|
+
|
|
163
|
+
| 2. **Interpolating Calibration Factors**: Imagine you have several points on
|
|
164
|
+
| a graph, and you want to estimate values between those points. In our case,
|
|
165
|
+
| these points represent calibration measurements taken at different times.
|
|
166
|
+
| The function figures out which two calibration points are closest in time
|
|
167
|
+
| to the specific measurement time you're interested in.
|
|
168
|
+
|
|
169
|
+
| 3. **Calculating Factors**: Once it finds these two nearby calibration points,
|
|
170
|
+
| the function calculates a correction factor by drawing a straight line
|
|
171
|
+
| between them (linear interpolation). This factor helps adjust the measurement
|
|
172
|
+
| to make it more accurate, considering how the instrument's sensitivity changed
|
|
173
|
+
| between those two calibration points.
|
|
174
|
+
|
|
175
|
+
| 4. **Returning the Correction Factor**: Finally, the function returns this
|
|
176
|
+
| correction factor. You can then use this factor to adjust or calibrate your
|
|
177
|
+
| measurements at the specific time you're interested in. This ensures that
|
|
178
|
+
| your measurements are as accurate as possible, taking into account the
|
|
179
|
+
| instrument's changing sensitivity over time.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
time : int
|
|
184
|
+
Input time.
|
|
185
|
+
"""
|
|
186
|
+
# NOTE: waiting on fake calibration data to write this.
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def apply_in_flight_calibration(data: np.ndarray) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Apply in flight calibration to full cycle data.
|
|
193
|
+
|
|
194
|
+
These factors are used to account for changes in gain with time.
|
|
195
|
+
|
|
196
|
+
They are derived from the weekly electron calibration data.
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
data : numpy.ndarray
|
|
201
|
+
Full cycle data array.
|
|
202
|
+
"""
|
|
203
|
+
# calculate calibration factor
|
|
204
|
+
# Apply to all data
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def populate_full_cycle_data(
|
|
209
|
+
l1a_data: xr.Dataset, packet_index: int, esa_table_num: int
|
|
210
|
+
) -> npt.NDArray:
|
|
211
|
+
"""
|
|
212
|
+
Populate full cycle data array using esa lookup table and l1a_data.
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
l1a_data : xarray.Dataset
|
|
217
|
+
L1a data with full cycle data only.
|
|
218
|
+
packet_index : int
|
|
219
|
+
Index of current packet in the whole packet list.
|
|
220
|
+
esa_table_num : int
|
|
221
|
+
ESA lookup table number.
|
|
222
|
+
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
numpy.ndarray
|
|
226
|
+
Array with full cycle data populated.
|
|
227
|
+
"""
|
|
228
|
+
esa_lookup_table = read_lookup_table(esa_table_num)
|
|
229
|
+
|
|
230
|
+
# If esa lookup table number is 0, then populate using esa lookup table data
|
|
231
|
+
# with information that esa step ramps up in even column and ramps down
|
|
232
|
+
# in odd column every six steps.
|
|
233
|
+
if esa_table_num == 0:
|
|
234
|
+
# create new full cycle data array
|
|
235
|
+
full_cycle_data = np.zeros((24, 30, 7))
|
|
236
|
+
|
|
237
|
+
# Initialize esa_step_number and column_index.
|
|
238
|
+
# esa_step_number goes from 0 to 719 range where
|
|
239
|
+
# 720 came from 24 x 30. full_cycle_data array has (24, 30)
|
|
240
|
+
# dimension.
|
|
241
|
+
esa_step_number = 0
|
|
242
|
+
# column_index goes from 0 to 29 range where
|
|
243
|
+
# 30 came from 30 column in full_cycle_data array
|
|
244
|
+
column_index = -1
|
|
245
|
+
|
|
246
|
+
# Go through four quarter cycle data packets
|
|
247
|
+
for index in range(4):
|
|
248
|
+
decompressed_counts = l1a_data["science_data"].data[packet_index + index]
|
|
249
|
+
# Do deadtime correction
|
|
250
|
+
acq_duration = l1a_data["acq_duration"].data[packet_index + index]
|
|
251
|
+
corrected_counts = deadtime_correction(decompressed_counts, acq_duration)
|
|
252
|
+
# Convert counts to rate
|
|
253
|
+
counts_rate = convert_counts_to_rate(corrected_counts, acq_duration)
|
|
254
|
+
|
|
255
|
+
# Go through each quarter cycle's 180 ESA measurements
|
|
256
|
+
# and put counts rate in full cycle data array
|
|
257
|
+
for step in range(180):
|
|
258
|
+
# Get esa voltage value from esa lookup table and
|
|
259
|
+
# use that to get row index in full data array
|
|
260
|
+
esa_voltage_value = esa_lookup_table.loc[esa_step_number]["esa_v"]
|
|
261
|
+
esa_voltage_row_index = esa_voltage_row_index_dict[esa_voltage_value]
|
|
262
|
+
|
|
263
|
+
# every six steps, increment column index
|
|
264
|
+
if esa_step_number % 6 == 0:
|
|
265
|
+
column_index += 1
|
|
266
|
+
# Put counts rate in full cycle data array
|
|
267
|
+
full_cycle_data[esa_voltage_row_index][column_index] = counts_rate[step]
|
|
268
|
+
esa_step_number += 1
|
|
269
|
+
|
|
270
|
+
# reset column index for next quarter cycle
|
|
271
|
+
column_index = -1
|
|
272
|
+
# TODO: Apply in flight calibration to full cycle data
|
|
273
|
+
|
|
274
|
+
# NOTE: We may get more lookup table with different setup when we get real
|
|
275
|
+
# data. But for now, we are advice to continue with current setup and can
|
|
276
|
+
# add/change it when we get real data.
|
|
277
|
+
|
|
278
|
+
return full_cycle_data
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def find_cycle_starts(cycles: np.ndarray) -> npt.NDArray:
|
|
282
|
+
"""
|
|
283
|
+
Find index of where new cycle started.
|
|
284
|
+
|
|
285
|
+
Brandon Stone helped developed this algorithm.
|
|
286
|
+
|
|
287
|
+
Parameters
|
|
288
|
+
----------
|
|
289
|
+
cycles : numpy.ndarray
|
|
290
|
+
Array that contains quarter cycle information.
|
|
291
|
+
|
|
292
|
+
Returns
|
|
293
|
+
-------
|
|
294
|
+
numpy.ndarray
|
|
295
|
+
Array of indices of start cycle.
|
|
296
|
+
"""
|
|
297
|
+
if cycles.size < 4:
|
|
298
|
+
return np.array([], np.int64)
|
|
299
|
+
|
|
300
|
+
# calculate difference between consecutive cycles
|
|
301
|
+
diff = cycles[1:] - cycles[:-1]
|
|
302
|
+
|
|
303
|
+
# This uses sliding window to find index where cycle starts.
|
|
304
|
+
# This is what this below code line is doing:
|
|
305
|
+
# [1 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0] # Is cycle zero?
|
|
306
|
+
# [1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1] # Next diff is one?
|
|
307
|
+
# [1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0] # Next diff is one?
|
|
308
|
+
# [0 1 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0] # Next diff is one?
|
|
309
|
+
#
|
|
310
|
+
# [0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0] # And all?
|
|
311
|
+
ione = diff == 1
|
|
312
|
+
valid = (cycles == 0)[:-3] & ione[:-2] & ione[1:-1] & ione[2:]
|
|
313
|
+
return np.where(valid)[0]
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def get_indices_of_full_cycles(quarter_cycle: np.ndarray) -> npt.NDArray:
|
|
317
|
+
"""
|
|
318
|
+
Get indices of full cycles.
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
quarter_cycle : numpy.ndarray
|
|
323
|
+
Array that contains quarter cycles information.
|
|
324
|
+
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
numpy.ndarray
|
|
328
|
+
1D array with indices of full cycle data.
|
|
329
|
+
"""
|
|
330
|
+
indices_of_start = find_cycle_starts(quarter_cycle)
|
|
331
|
+
# indices_of_start[..., None] creates array of shape(n, 1).
|
|
332
|
+
# Eg. [[3], [8]]
|
|
333
|
+
# np.arange(4)[None, ...] creates array of shape(1, 4)
|
|
334
|
+
# Eg. [[0, 1, 2, 3]]
|
|
335
|
+
# then we add both of them together to get an array of shape(n, 4)
|
|
336
|
+
# Eg. [[3, 4, 5, 6], [8, 9, 10, 11]]
|
|
337
|
+
full_cycles_indices = indices_of_start[..., None] + np.arange(4)[None, ...]
|
|
338
|
+
return full_cycles_indices.reshape(-1)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def filter_full_cycle_data(
|
|
342
|
+
full_cycle_data_indices: np.ndarray, l1a_data: xr.Dataset
|
|
343
|
+
) -> xr.Dataset:
|
|
344
|
+
"""
|
|
345
|
+
Filter metadata and science of packets that makes full cycles.
|
|
346
|
+
|
|
347
|
+
Parameters
|
|
348
|
+
----------
|
|
349
|
+
full_cycle_data_indices : numpy.ndarray
|
|
350
|
+
Array with indices of full cycles.
|
|
351
|
+
l1a_data : xarray.Dataset
|
|
352
|
+
L1A dataset.
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
xarray.Dataset
|
|
357
|
+
L1A dataset with filtered metadata.
|
|
358
|
+
"""
|
|
359
|
+
for key, value in l1a_data.items():
|
|
360
|
+
l1a_data[key] = value.data[full_cycle_data_indices]
|
|
361
|
+
return l1a_data
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def swe_l1b_science(l1a_data: xr.Dataset, data_version: str) -> xr.Dataset:
|
|
365
|
+
"""
|
|
366
|
+
SWE l1b science processing.
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
l1a_data : xarray.Dataset
|
|
371
|
+
Input data.
|
|
372
|
+
data_version : str
|
|
373
|
+
Version of the data product being created.
|
|
374
|
+
|
|
375
|
+
Returns
|
|
376
|
+
-------
|
|
377
|
+
xarray.Dataset
|
|
378
|
+
Processed l1b data.
|
|
379
|
+
"""
|
|
380
|
+
total_packets = len(l1a_data["science_data"].data)
|
|
381
|
+
|
|
382
|
+
# Array to store list of table populated with data
|
|
383
|
+
# of full cycles
|
|
384
|
+
all_data = []
|
|
385
|
+
packet_index = 0
|
|
386
|
+
l1a_data_copy = l1a_data.copy(deep=True)
|
|
387
|
+
|
|
388
|
+
full_cycle_data_indices = get_indices_of_full_cycles(l1a_data["quarter_cycle"].data)
|
|
389
|
+
logger.debug(
|
|
390
|
+
f"Quarter cycle data before filtering: {l1a_data_copy['quarter_cycle'].data}"
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
# Delete Raw Science Data from l1b and onwards
|
|
394
|
+
del l1a_data_copy["raw_science_data"]
|
|
395
|
+
|
|
396
|
+
if full_cycle_data_indices.size == 0:
|
|
397
|
+
# Log that no data is found for science data
|
|
398
|
+
return None
|
|
399
|
+
|
|
400
|
+
if len(full_cycle_data_indices) != total_packets:
|
|
401
|
+
# Filter metadata and science data of packets that makes full cycles
|
|
402
|
+
full_cycle_l1a_data = l1a_data_copy.isel({"epoch": full_cycle_data_indices})
|
|
403
|
+
|
|
404
|
+
# Update total packets
|
|
405
|
+
total_packets = len(full_cycle_data_indices)
|
|
406
|
+
logger.debug(
|
|
407
|
+
"Quarters cycle after filtering: "
|
|
408
|
+
f"{full_cycle_l1a_data['quarter_cycle'].data}"
|
|
409
|
+
)
|
|
410
|
+
if len(full_cycle_data_indices) != len(
|
|
411
|
+
full_cycle_l1a_data["quarter_cycle"].data
|
|
412
|
+
):
|
|
413
|
+
raise ValueError(
|
|
414
|
+
"Error: full cycle data indices and filtered quarter cycle data size "
|
|
415
|
+
"mismatch"
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# Go through each cycle and populate full cycle data
|
|
419
|
+
for packet_index in range(0, total_packets, 4):
|
|
420
|
+
# get ESA lookup table information
|
|
421
|
+
esa_table_num = l1a_data["esa_table_num"].data[packet_index]
|
|
422
|
+
|
|
423
|
+
# If ESA lookup table number is in-flight calibration
|
|
424
|
+
# data, then skip current cycle per SWE teams specification.
|
|
425
|
+
# SWE team only wants in-flight calibration data to be processed
|
|
426
|
+
# upto l1a. In-flight calibration data looks same as science data
|
|
427
|
+
# but it only measures one energy steps during the whole duration.
|
|
428
|
+
if esa_table_num == 1:
|
|
429
|
+
continue
|
|
430
|
+
|
|
431
|
+
full_cycle_data = populate_full_cycle_data(
|
|
432
|
+
full_cycle_l1a_data, packet_index, esa_table_num
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# save full data array to file
|
|
436
|
+
all_data.append(full_cycle_data)
|
|
437
|
+
|
|
438
|
+
# ------------------------------------------------------------------
|
|
439
|
+
# Save data to dataset.
|
|
440
|
+
# ------------------------------------------------------------------
|
|
441
|
+
# Load CDF attrs
|
|
442
|
+
cdf_attrs = ImapCdfAttributes()
|
|
443
|
+
cdf_attrs.add_instrument_global_attrs("swe")
|
|
444
|
+
cdf_attrs.add_instrument_variable_attrs("swe", "l1b")
|
|
445
|
+
cdf_attrs.add_global_attribute("Data_version", data_version)
|
|
446
|
+
|
|
447
|
+
# Get epoch time of full cycle data and then reshape it to
|
|
448
|
+
# (n, 4) where n = total number of full cycles and 4 = four
|
|
449
|
+
# quarter cycle data metadata. For epoch's data, we take the first element
|
|
450
|
+
# of each quarter cycle data metadata.
|
|
451
|
+
epoch_time = xr.DataArray(
|
|
452
|
+
l1a_data["epoch"].data[full_cycle_data_indices].reshape(-1, 4)[:, 0],
|
|
453
|
+
name="epoch",
|
|
454
|
+
dims=["epoch"],
|
|
455
|
+
attrs=cdf_attrs.get_variable_attributes("epoch"),
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
energy = xr.DataArray(
|
|
459
|
+
np.arange(24),
|
|
460
|
+
name="energy",
|
|
461
|
+
dims=["energy"],
|
|
462
|
+
attrs=cdf_attrs.get_variable_attributes("energy"),
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
# NOTE: LABL_PTR_1 should be CDF_CHAR.
|
|
466
|
+
energy_label = xr.DataArray(
|
|
467
|
+
energy.values.astype(str),
|
|
468
|
+
name="energy_label",
|
|
469
|
+
dims=["energy_label"],
|
|
470
|
+
attrs=cdf_attrs.get_variable_attributes("energy_label"),
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
angle = xr.DataArray(
|
|
474
|
+
np.arange(30),
|
|
475
|
+
name="angle",
|
|
476
|
+
dims=["angle"],
|
|
477
|
+
attrs=cdf_attrs.get_variable_attributes("angle"),
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
# NOTE: LABL_PTR_2 should be CDF_CHAR.
|
|
481
|
+
angle_label = xr.DataArray(
|
|
482
|
+
angle.values.astype(str),
|
|
483
|
+
name="angle_label",
|
|
484
|
+
dims=["angle_label"],
|
|
485
|
+
attrs=cdf_attrs.get_variable_attributes("angle_label"),
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
cycle = xr.DataArray(
|
|
489
|
+
np.arange(4),
|
|
490
|
+
name="cycle",
|
|
491
|
+
dims=["cycle"],
|
|
492
|
+
attrs=cdf_attrs.get_variable_attributes("cycle"),
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
cem = xr.DataArray(
|
|
496
|
+
np.arange(7, dtype=np.float64),
|
|
497
|
+
name="cem",
|
|
498
|
+
dims=["cem"],
|
|
499
|
+
attrs=cdf_attrs.get_variable_attributes("cem"),
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
# NOTE: LABL_PTR_3 should be CDF_CHAR.
|
|
503
|
+
cem_label = xr.DataArray(
|
|
504
|
+
cem.values.astype(str),
|
|
505
|
+
name="cem_label",
|
|
506
|
+
dims=["cem_label"],
|
|
507
|
+
attrs=cdf_attrs.get_variable_attributes("cem_label"),
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# Add science data and it's associated metadata into dataset.
|
|
511
|
+
# SCIENCE_DATA has array of this shape:
|
|
512
|
+
# (n, 24, 30, 7)
|
|
513
|
+
# n = total number of full cycles
|
|
514
|
+
# 24 rows --> 24 esa voltage measurements
|
|
515
|
+
# 30 columns --> 30 spin angle measurements
|
|
516
|
+
# 7 elements --> 7 CEMs counts
|
|
517
|
+
#
|
|
518
|
+
# The metadata array will need to have this shape:
|
|
519
|
+
# (n, 4)
|
|
520
|
+
# n = total number of full cycles
|
|
521
|
+
# 4 rows --> metadata for each full cycle. Each element of 4 maps to
|
|
522
|
+
# metadata of one quarter cycle.
|
|
523
|
+
|
|
524
|
+
# Create the dataset
|
|
525
|
+
dataset = xr.Dataset(
|
|
526
|
+
coords={
|
|
527
|
+
"epoch": epoch_time,
|
|
528
|
+
"energy": energy,
|
|
529
|
+
"angle": angle,
|
|
530
|
+
"cem": cem,
|
|
531
|
+
"cycle": cycle,
|
|
532
|
+
"energy_label": energy_label,
|
|
533
|
+
"angle_label": angle_label,
|
|
534
|
+
"cem_label": cem_label,
|
|
535
|
+
},
|
|
536
|
+
attrs=cdf_attrs.get_global_attributes("imap_swe_l1b_sci"),
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
dataset["science_data"] = xr.DataArray(
|
|
540
|
+
all_data,
|
|
541
|
+
dims=["epoch", "energy", "angle", "cem"],
|
|
542
|
+
attrs=cdf_attrs.get_variable_attributes("science_data"),
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
# create xarray dataset for each metadata field
|
|
546
|
+
for key, value in full_cycle_l1a_data.items():
|
|
547
|
+
if key == "science_data":
|
|
548
|
+
continue
|
|
549
|
+
metadata_field = key.lower()
|
|
550
|
+
dataset[metadata_field] = xr.DataArray(
|
|
551
|
+
value.data.reshape(-1, 4),
|
|
552
|
+
dims=["epoch", "cycle"],
|
|
553
|
+
attrs=cdf_attrs.get_variable_attributes(metadata_field),
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
logger.info("SWE L1b science processing completed")
|
|
557
|
+
return dataset
|
|
File without changes
|