imap-processing 0.12.0__py3-none-any.whl → 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/__init__.py +1 -0
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/ccsds_data.py +1 -2
- imap_processing/ccsds/excel_to_xtce.py +1 -2
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +18 -12
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +569 -0
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +1846 -128
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +5 -5
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +20 -1
- 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_mag_global_cdf_attrs.yaml +15 -0
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +22 -0
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +16 -0
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +178 -5
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +5045 -41
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -19
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +8 -48
- imap_processing/cdf/utils.py +41 -33
- imap_processing/cli.py +463 -234
- imap_processing/codice/codice_l1a.py +260 -47
- imap_processing/codice/codice_l1b.py +51 -152
- imap_processing/codice/constants.py +38 -1
- imap_processing/ena_maps/ena_maps.py +658 -65
- imap_processing/ena_maps/utils/coordinates.py +1 -1
- imap_processing/ena_maps/utils/spatial_utils.py +10 -5
- 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 +31 -12
- imap_processing/hi/l1b/hi_l1b.py +80 -43
- imap_processing/hi/l1c/hi_l1c.py +12 -16
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-sector-dt0-factors_20250219_v002.csv +81 -0
- imap_processing/hit/hit_utils.py +93 -35
- imap_processing/hit/l0/decom_hit.py +3 -1
- imap_processing/hit/l1a/hit_l1a.py +30 -25
- imap_processing/hit/l1b/constants.py +6 -2
- imap_processing/hit/l1b/hit_l1b.py +279 -318
- imap_processing/hit/l2/constants.py +37 -0
- imap_processing/hit/l2/hit_l2.py +373 -264
- imap_processing/ialirt/l0/parse_mag.py +138 -10
- imap_processing/ialirt/l0/process_swapi.py +69 -0
- imap_processing/ialirt/l0/process_swe.py +318 -22
- imap_processing/ialirt/packet_definitions/ialirt.xml +216 -212
- 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_swapi.xml +14 -14
- imap_processing/ialirt/utils/grouping.py +1 -1
- imap_processing/idex/idex_constants.py +9 -1
- imap_processing/idex/idex_l0.py +22 -8
- imap_processing/idex/idex_l1a.py +75 -44
- imap_processing/idex/idex_l1b.py +9 -8
- imap_processing/idex/idex_l2a.py +79 -45
- imap_processing/idex/idex_l2b.py +120 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -39
- imap_processing/idex/packet_definitions/idex_housekeeping_packet_definition.xml +9130 -0
- imap_processing/lo/l0/lo_science.py +1 -2
- imap_processing/lo/l1a/lo_l1a.py +1 -4
- imap_processing/lo/l1b/lo_l1b.py +527 -6
- imap_processing/lo/l1b/tof_conversions.py +11 -0
- imap_processing/lo/l1c/lo_l1c.py +1 -4
- imap_processing/mag/constants.py +43 -0
- imap_processing/mag/imap_mag_sdc_configuration_v001.py +8 -0
- imap_processing/mag/l1a/mag_l1a.py +2 -9
- imap_processing/mag/l1a/mag_l1a_data.py +10 -10
- imap_processing/mag/l1b/mag_l1b.py +84 -17
- imap_processing/mag/l1c/interpolation_methods.py +180 -3
- imap_processing/mag/l1c/mag_l1c.py +236 -70
- imap_processing/mag/l2/mag_l2.py +140 -0
- imap_processing/mag/l2/mag_l2_data.py +288 -0
- imap_processing/spacecraft/quaternions.py +1 -3
- imap_processing/spice/geometry.py +3 -3
- imap_processing/spice/kernels.py +0 -276
- imap_processing/spice/pointing_frame.py +257 -0
- imap_processing/spice/repoint.py +48 -19
- imap_processing/spice/spin.py +38 -33
- imap_processing/spice/time.py +24 -0
- imap_processing/swapi/l1/swapi_l1.py +16 -12
- imap_processing/swapi/l2/swapi_l2.py +116 -4
- imap_processing/swapi/swapi_utils.py +32 -0
- imap_processing/swe/l1a/swe_l1a.py +2 -9
- imap_processing/swe/l1a/swe_science.py +8 -11
- imap_processing/swe/l1b/swe_l1b.py +898 -23
- imap_processing/swe/l2/swe_l2.py +21 -77
- imap_processing/swe/utils/swe_constants.py +1 -0
- imap_processing/tests/ccsds/test_excel_to_xtce.py +1 -1
- 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-pha_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/test_codice_l1a.py +20 -11
- imap_processing/tests/codice/test_codice_l1b.py +6 -7
- imap_processing/tests/conftest.py +78 -22
- imap_processing/tests/ena_maps/test_ena_maps.py +462 -33
- imap_processing/tests/ena_maps/test_spatial_utils.py +1 -1
- 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/test_hi_l1b.py +10 -12
- imap_processing/tests/hi/test_hi_l1c.py +27 -24
- imap_processing/tests/hi/test_l1a.py +7 -9
- imap_processing/tests/hi/test_science_direct_event.py +2 -2
- imap_processing/tests/hit/helpers/l1_validation.py +44 -43
- imap_processing/tests/hit/test_decom_hit.py +1 -1
- imap_processing/tests/hit/test_hit_l1a.py +9 -9
- imap_processing/tests/hit/test_hit_l1b.py +172 -217
- imap_processing/tests/hit/test_hit_l2.py +380 -118
- imap_processing/tests/hit/test_hit_utils.py +122 -55
- imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -62
- imap_processing/tests/hit/validation_data/sci_sample_raw.csv +1 -1
- imap_processing/tests/ialirt/unit/test_decom_ialirt.py +16 -81
- imap_processing/tests/ialirt/unit/test_grouping.py +2 -2
- imap_processing/tests/ialirt/unit/test_parse_mag.py +71 -16
- 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 +115 -7
- imap_processing/tests/idex/conftest.py +72 -7
- 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_idex_l0.py +33 -11
- imap_processing/tests/idex/test_idex_l1a.py +50 -23
- imap_processing/tests/idex/test_idex_l1b.py +104 -25
- imap_processing/tests/idex/test_idex_l2a.py +48 -32
- imap_processing/tests/idex/test_idex_l2b.py +93 -0
- imap_processing/tests/lo/test_lo_l1a.py +3 -3
- imap_processing/tests/lo/test_lo_l1b.py +371 -6
- imap_processing/tests/lo/test_lo_l1c.py +1 -1
- imap_processing/tests/lo/test_lo_science.py +6 -7
- imap_processing/tests/lo/test_star_sensor.py +1 -1
- imap_processing/tests/mag/conftest.py +58 -9
- imap_processing/tests/mag/test_mag_decom.py +4 -3
- imap_processing/tests/mag/test_mag_l1a.py +13 -7
- imap_processing/tests/mag/test_mag_l1b.py +9 -9
- imap_processing/tests/mag/test_mag_l1c.py +151 -47
- imap_processing/tests/mag/test_mag_l2.py +130 -0
- imap_processing/tests/mag/test_mag_validation.py +144 -7
- 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_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/test_quaternions.py +1 -1
- imap_processing/tests/spice/test_data/fake_repoint_data.csv +4 -4
- imap_processing/tests/spice/test_data/fake_spin_data.csv +11 -11
- imap_processing/tests/spice/test_geometry.py +3 -3
- 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 +20 -10
- 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 +7 -9
- imap_processing/tests/swapi/test_swapi_l2.py +180 -8
- 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 +6 -6
- 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 +82 -102
- imap_processing/tests/test_cli.py +171 -88
- imap_processing/tests/test_utils.py +2 -1
- imap_processing/tests/ultra/data/mock_data.py +49 -21
- imap_processing/tests/ultra/unit/conftest.py +53 -70
- imap_processing/tests/ultra/unit/test_badtimes.py +2 -4
- imap_processing/tests/ultra/unit/test_cullingmask.py +4 -6
- imap_processing/tests/ultra/unit/test_de.py +3 -10
- imap_processing/tests/ultra/unit/test_decom_apid_880.py +27 -76
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +15 -16
- 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 +3 -4
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +84 -307
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +30 -12
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +2 -2
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +4 -1
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +163 -29
- imap_processing/tests/ultra/unit/test_ultra_l1c.py +5 -5
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +32 -43
- 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 +21 -34
- 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 -243
- imap_processing/ultra/l1b/badtimes.py +1 -4
- imap_processing/ultra/l1b/cullingmask.py +2 -6
- imap_processing/ultra/l1b/de.py +62 -47
- imap_processing/ultra/l1b/extendedspin.py +8 -4
- imap_processing/ultra/l1b/lookup_utils.py +72 -9
- imap_processing/ultra/l1b/ultra_l1b.py +3 -8
- imap_processing/ultra/l1b/ultra_l1b_culling.py +4 -4
- imap_processing/ultra/l1b/ultra_l1b_extended.py +236 -78
- imap_processing/ultra/l1c/histogram.py +2 -6
- imap_processing/ultra/l1c/spacecraft_pset.py +2 -4
- imap_processing/ultra/l1c/ultra_l1c.py +1 -5
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +107 -60
- 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 +13 -12
- imap_processing/utils.py +1 -1
- {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/METADATA +3 -2
- {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/RECORD +264 -225
- imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +0 -154
- imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +0 -6
- imap_processing/mag/l1b/__init__.py +0 -0
- imap_processing/swe/l1b/swe_esa_lookup_table.csv +0 -1441
- imap_processing/swe/l1b/swe_l1b_science.py +0 -699
- imap_processing/tests/swe/test_swe_l1b_science.py +0 -103
- imap_processing/ultra/lookup_tables/dps_sensitivity45.cdf +0 -0
- imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
- /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/461971383-404.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971384-405.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971385-406.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971386-407.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971387-408.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971388-409.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971389-410.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971390-411.bin +0 -0
- /imap_processing/tests/ialirt/{test_data → data}/l0/461971391-412.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/tests/ialirt/{test_data → data}/l0/sample_decoded_i-alirt_data.csv +0 -0
- /imap_processing/tests/mag/validation/{imap_calibration_mag_20240229_v01.cdf → calibration/imap_mag_l1b-calibration_20240229_v001.cdf} +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-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.12.0.dist-info → imap_processing-0.13.0.dist-info}/entry_points.txt +0 -0
|
@@ -26,15 +26,12 @@ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
|
26
26
|
from imap_processing.codice import constants
|
|
27
27
|
from imap_processing.codice.codice_l0 import decom_packets
|
|
28
28
|
from imap_processing.codice.decompress import decompress
|
|
29
|
-
from imap_processing.codice.utils import CODICEAPID
|
|
29
|
+
from imap_processing.codice.utils import CODICEAPID, CoDICECompression
|
|
30
30
|
from imap_processing.spice.time import met_to_ttj2000ns
|
|
31
31
|
|
|
32
32
|
logger = logging.getLogger(__name__)
|
|
33
33
|
logger.setLevel(logging.INFO)
|
|
34
34
|
|
|
35
|
-
# TODO: Determine what should go in event data CDF and how it should be
|
|
36
|
-
# structured.
|
|
37
|
-
|
|
38
35
|
|
|
39
36
|
class CoDICEL1aPipeline:
|
|
40
37
|
"""
|
|
@@ -537,9 +534,7 @@ class CoDICEL1aPipeline:
|
|
|
537
534
|
# No longer need to keep the raw data around
|
|
538
535
|
del self.raw_data
|
|
539
536
|
|
|
540
|
-
def set_data_product_config(
|
|
541
|
-
self, apid: int, dataset: xr.Dataset, data_version: str
|
|
542
|
-
) -> None:
|
|
537
|
+
def set_data_product_config(self, apid: int, dataset: xr.Dataset) -> None:
|
|
543
538
|
"""
|
|
544
539
|
Set the various settings for defining the data products.
|
|
545
540
|
|
|
@@ -549,79 +544,139 @@ class CoDICEL1aPipeline:
|
|
|
549
544
|
The APID of interest.
|
|
550
545
|
dataset : xarray.Dataset
|
|
551
546
|
The dataset for the APID of interest.
|
|
552
|
-
data_version : str
|
|
553
|
-
Version of the data product being created.
|
|
554
547
|
"""
|
|
555
548
|
# Set the packet dataset so that it can be easily called from various
|
|
556
549
|
# methods
|
|
557
550
|
self.dataset = dataset
|
|
558
551
|
|
|
559
552
|
# Set various configurations of the data product
|
|
560
|
-
self.config: dict[str, Any] = constants.DATA_PRODUCT_CONFIGURATIONS
|
|
553
|
+
self.config: dict[str, Any] = constants.DATA_PRODUCT_CONFIGURATIONS[apid]
|
|
561
554
|
|
|
562
555
|
# Gather and set the CDF attributes
|
|
563
556
|
self.cdf_attrs = ImapCdfAttributes()
|
|
564
557
|
self.cdf_attrs.add_instrument_global_attrs("codice")
|
|
565
558
|
self.cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
|
|
566
|
-
self.cdf_attrs.add_global_attribute("Data_version", data_version)
|
|
567
559
|
|
|
568
560
|
|
|
569
|
-
def
|
|
570
|
-
apid: int, packet: xr.Dataset, data_version: str
|
|
571
|
-
) -> xr.Dataset:
|
|
561
|
+
def create_direct_event_dataset(apid: int, packets: xr.Dataset) -> xr.Dataset:
|
|
572
562
|
"""
|
|
573
|
-
Create dataset for event data.
|
|
563
|
+
Create dataset for direct event data.
|
|
564
|
+
|
|
565
|
+
For direct event data, the raw data from the spacecraft is organized first
|
|
566
|
+
by epoch, then by priority, then by events. For example, for a CoDICE-Lo
|
|
567
|
+
dataset with 10 epochs, we expect the length of the `event_data` field to
|
|
568
|
+
be (10 epochs * 8 priorities) = 80 items, with each item being a compressed
|
|
569
|
+
byte object representing a variable number of events (up to 10000 events).
|
|
570
|
+
Each compressed byte object is comprised of several fields with specific
|
|
571
|
+
bit lengths/positions, described by the constants.[LO|HI]_DE_BIT_STRUCTURE
|
|
572
|
+
dictionary. Padding is added to any fields that have less than 10000 events.
|
|
573
|
+
|
|
574
|
+
In order to process these data, we must take the decommed raw data, group
|
|
575
|
+
the packets appropriately based on their `seq_flgs`, decompress the data,
|
|
576
|
+
then arrange the data into CDF data variables for each priority and bit
|
|
577
|
+
field. For example, P2_SpinAngle represents the spin angles for the 2nd
|
|
578
|
+
priority data.
|
|
574
579
|
|
|
575
580
|
Parameters
|
|
576
581
|
----------
|
|
577
582
|
apid : int
|
|
578
583
|
The APID of the packet.
|
|
579
|
-
|
|
580
|
-
The
|
|
581
|
-
data_version : str
|
|
582
|
-
Version of the data product being created.
|
|
584
|
+
packets : xarray.Dataset
|
|
585
|
+
The packets to process..
|
|
583
586
|
|
|
584
587
|
Returns
|
|
585
588
|
-------
|
|
586
589
|
dataset : xarray.Dataset
|
|
587
|
-
Xarray dataset containing the event data.
|
|
590
|
+
Xarray dataset containing the direct event data.
|
|
588
591
|
"""
|
|
592
|
+
# Set some useful variables unique to CoDICE-Lo and CoDICE-Hi
|
|
589
593
|
if apid == CODICEAPID.COD_LO_PHA:
|
|
590
|
-
|
|
594
|
+
num_priorities = 8
|
|
595
|
+
cdf_fields = [
|
|
596
|
+
"NumEvents",
|
|
597
|
+
"DataQuality",
|
|
598
|
+
"APDGain",
|
|
599
|
+
"APD_ID",
|
|
600
|
+
"APDEnergy",
|
|
601
|
+
"TOF",
|
|
602
|
+
"MultiFlag",
|
|
603
|
+
"PHAType",
|
|
604
|
+
"SpinAngle",
|
|
605
|
+
"EnergyStep",
|
|
606
|
+
]
|
|
591
607
|
elif apid == CODICEAPID.COD_HI_PHA:
|
|
592
|
-
|
|
608
|
+
num_priorities = 6
|
|
609
|
+
cdf_fields = [
|
|
610
|
+
"NumEvents",
|
|
611
|
+
"DataQuality",
|
|
612
|
+
"SSDEnergy0,TOF",
|
|
613
|
+
"SSD_ID",
|
|
614
|
+
"ERGE",
|
|
615
|
+
"MultiFlag",
|
|
616
|
+
"Type",
|
|
617
|
+
"SpinAngle",
|
|
618
|
+
"SpinNumber",
|
|
619
|
+
]
|
|
620
|
+
|
|
621
|
+
# Group and decompress the data
|
|
622
|
+
grouped_data = group_data(packets)
|
|
623
|
+
decompressed_data = [
|
|
624
|
+
decompress(group, CoDICECompression.LOSSLESS) for group in grouped_data
|
|
625
|
+
]
|
|
593
626
|
|
|
594
|
-
#
|
|
595
|
-
|
|
627
|
+
# Reshape the packet data into CDF-ready variables
|
|
628
|
+
data = reshape_de_data(packets, decompressed_data, num_priorities)
|
|
596
629
|
|
|
630
|
+
# Gather the CDF attributes
|
|
597
631
|
cdf_attrs = ImapCdfAttributes()
|
|
598
632
|
cdf_attrs.add_instrument_global_attrs("codice")
|
|
599
633
|
cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
|
|
600
|
-
cdf_attrs.add_global_attribute("Data_version", data_version)
|
|
601
634
|
|
|
602
635
|
# Define coordinates
|
|
636
|
+
# For epoch, we take the first epoch from each priority set
|
|
603
637
|
epoch = xr.DataArray(
|
|
604
|
-
|
|
638
|
+
packets.epoch[::num_priorities],
|
|
605
639
|
name="epoch",
|
|
606
640
|
dims=["epoch"],
|
|
607
641
|
attrs=cdf_attrs.get_variable_attributes("epoch"),
|
|
608
642
|
)
|
|
643
|
+
event_num = xr.DataArray(
|
|
644
|
+
np.arange(10000),
|
|
645
|
+
name="event_num",
|
|
646
|
+
dims=["event_num"],
|
|
647
|
+
attrs=cdf_attrs.get_variable_attributes("event_num"),
|
|
648
|
+
)
|
|
609
649
|
|
|
610
650
|
# Create the dataset to hold the data variables
|
|
651
|
+
if apid == CODICEAPID.COD_LO_PHA:
|
|
652
|
+
attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_lo-pha")
|
|
653
|
+
elif apid == CODICEAPID.COD_HI_PHA:
|
|
654
|
+
attrs = cdf_attrs.get_global_attributes("imap_codice_l1a_hi-pha")
|
|
611
655
|
dataset = xr.Dataset(
|
|
612
|
-
coords={
|
|
613
|
-
|
|
614
|
-
},
|
|
615
|
-
attrs=cdf_attrs.get_global_attributes(dataset_name),
|
|
656
|
+
coords={"epoch": epoch, "event_num": event_num},
|
|
657
|
+
attrs=attrs,
|
|
616
658
|
)
|
|
617
659
|
|
|
660
|
+
# Create the CDF data variables for each Priority and Field
|
|
661
|
+
for i in range(num_priorities):
|
|
662
|
+
for field in cdf_fields:
|
|
663
|
+
variable_name = f"P{i}_{field}"
|
|
664
|
+
attrs = cdf_attrs.get_variable_attributes(variable_name)
|
|
665
|
+
if field in ["NumEvents", "DataQuality"]:
|
|
666
|
+
dims = ["epoch"]
|
|
667
|
+
else:
|
|
668
|
+
dims = ["epoch", "event_num"]
|
|
669
|
+
dataset[variable_name] = xr.DataArray(
|
|
670
|
+
np.array(data[variable_name]),
|
|
671
|
+
name=variable_name,
|
|
672
|
+
dims=dims,
|
|
673
|
+
attrs=attrs,
|
|
674
|
+
)
|
|
675
|
+
|
|
618
676
|
return dataset
|
|
619
677
|
|
|
620
678
|
|
|
621
|
-
def create_hskp_dataset(
|
|
622
|
-
packet: xr.Dataset,
|
|
623
|
-
data_version: str,
|
|
624
|
-
) -> xr.Dataset:
|
|
679
|
+
def create_hskp_dataset(packet: xr.Dataset) -> xr.Dataset:
|
|
625
680
|
"""
|
|
626
681
|
Create dataset for each metadata field for housekeeping data.
|
|
627
682
|
|
|
@@ -629,8 +684,6 @@ def create_hskp_dataset(
|
|
|
629
684
|
----------
|
|
630
685
|
packet : xarray.Dataset
|
|
631
686
|
The packet to process.
|
|
632
|
-
data_version : str
|
|
633
|
-
Version of the data product being created.
|
|
634
687
|
|
|
635
688
|
Returns
|
|
636
689
|
-------
|
|
@@ -640,7 +693,6 @@ def create_hskp_dataset(
|
|
|
640
693
|
cdf_attrs = ImapCdfAttributes()
|
|
641
694
|
cdf_attrs.add_instrument_global_attrs("codice")
|
|
642
695
|
cdf_attrs.add_instrument_variable_attrs("codice", "l1a")
|
|
643
|
-
cdf_attrs.add_global_attribute("Data_version", data_version)
|
|
644
696
|
|
|
645
697
|
epoch = xr.DataArray(
|
|
646
698
|
packet.epoch,
|
|
@@ -719,6 +771,69 @@ def get_params(dataset: xr.Dataset) -> tuple[int, int, int, int]:
|
|
|
719
771
|
return table_id, plan_id, plan_step, view_id
|
|
720
772
|
|
|
721
773
|
|
|
774
|
+
def group_data(packets: xr.Dataset) -> list[bytes]:
|
|
775
|
+
"""
|
|
776
|
+
Organize continuation packets into appropriate groups.
|
|
777
|
+
|
|
778
|
+
Some packets are continuation packets, as in, they are packets that are
|
|
779
|
+
part of a group of packets. These packets are marked by the `seq_flgs` field
|
|
780
|
+
in the CCSDS header of the packet. For CoDICE, the values are defined as
|
|
781
|
+
follows:
|
|
782
|
+
|
|
783
|
+
3 = Packet is not part of a group
|
|
784
|
+
1 = Packet is the first packet of the group
|
|
785
|
+
0 = Packet is in the middle of the group
|
|
786
|
+
2 = Packet is the last packet of the group
|
|
787
|
+
|
|
788
|
+
For packets that are part of a group, the byte count associated with the
|
|
789
|
+
first packet of the group signifies the byte count for the entire group.
|
|
790
|
+
|
|
791
|
+
Parameters
|
|
792
|
+
----------
|
|
793
|
+
packets : xarray.Dataset
|
|
794
|
+
Dataset containing the packets to group.
|
|
795
|
+
|
|
796
|
+
Returns
|
|
797
|
+
-------
|
|
798
|
+
grouped_data : list[bytes]
|
|
799
|
+
The packet data, converted to bytes and grouped appropriately.
|
|
800
|
+
"""
|
|
801
|
+
grouped_data = [] # Holds the properly grouped data to be decompressed
|
|
802
|
+
current_group = bytearray() # Temporary storage for current group
|
|
803
|
+
group_byte_count = None # Temporary storage for current group byte count
|
|
804
|
+
|
|
805
|
+
for packet_data, group_code, byte_count in zip(
|
|
806
|
+
packets.event_data.data, packets.seq_flgs.data, packets.byte_count.data
|
|
807
|
+
):
|
|
808
|
+
# If the group code is 3, this means the data is not part of a group
|
|
809
|
+
# and can be decompressed as-is
|
|
810
|
+
if group_code == 3:
|
|
811
|
+
values_to_decompress = packet_data[:byte_count]
|
|
812
|
+
grouped_data.append(values_to_decompress)
|
|
813
|
+
|
|
814
|
+
# If the group code is 1, this means the data is the first data in a
|
|
815
|
+
# group. Also, set the byte count for the group
|
|
816
|
+
elif group_code == 1:
|
|
817
|
+
group_byte_count = byte_count
|
|
818
|
+
current_group = packet_data
|
|
819
|
+
|
|
820
|
+
# If the group code is 0, this means the data is part of the middle of
|
|
821
|
+
# the group
|
|
822
|
+
elif group_code == 0:
|
|
823
|
+
current_group += packet_data
|
|
824
|
+
|
|
825
|
+
# If the group code is 2, this means the data is the last data in the
|
|
826
|
+
# group
|
|
827
|
+
elif group_code == 2:
|
|
828
|
+
current_group += packet_data
|
|
829
|
+
values_to_decompress = current_group[:group_byte_count]
|
|
830
|
+
grouped_data.append(values_to_decompress)
|
|
831
|
+
current_group = bytearray()
|
|
832
|
+
group_byte_count = None
|
|
833
|
+
|
|
834
|
+
return grouped_data
|
|
835
|
+
|
|
836
|
+
|
|
722
837
|
def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
|
|
723
838
|
"""
|
|
724
839
|
Log info about the input data to help with tracking and/or debugging.
|
|
@@ -730,9 +845,9 @@ def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
|
|
|
730
845
|
"""
|
|
731
846
|
launch_time = np.datetime64("2010-01-01T00:01:06.184", "ns")
|
|
732
847
|
logger.info("\nThis input file contains the following APIDs:\n")
|
|
733
|
-
for apid in datasets:
|
|
734
|
-
num_packets = len(
|
|
735
|
-
time_deltas = [np.timedelta64(item, "ns") for item in
|
|
848
|
+
for apid, ds in datasets.items():
|
|
849
|
+
num_packets = len(ds.epoch.data)
|
|
850
|
+
time_deltas = [np.timedelta64(item, "ns") for item in ds.epoch.data]
|
|
736
851
|
times = [launch_time + delta for delta in time_deltas]
|
|
737
852
|
start = np.datetime_as_string(times[0])
|
|
738
853
|
end = np.datetime_as_string(times[-1])
|
|
@@ -741,7 +856,102 @@ def log_dataset_info(datasets: dict[int, xr.Dataset]) -> None:
|
|
|
741
856
|
)
|
|
742
857
|
|
|
743
858
|
|
|
744
|
-
def
|
|
859
|
+
def reshape_de_data(
|
|
860
|
+
packets: xr.Dataset, decompressed_data: list[list[int]], num_priorities: int
|
|
861
|
+
) -> dict[str, np.ndarray]:
|
|
862
|
+
"""
|
|
863
|
+
Reshape the decompressed direct event data into CDF-ready arrays.
|
|
864
|
+
|
|
865
|
+
Parameters
|
|
866
|
+
----------
|
|
867
|
+
packets : xarray.Dataset
|
|
868
|
+
Dataset containing the packets, needed to determine priority order
|
|
869
|
+
and data quality.
|
|
870
|
+
decompressed_data : list[list[int]]
|
|
871
|
+
The decompressed data to reshape, in the format <epoch>[<priority>[<event>]].
|
|
872
|
+
num_priorities : int
|
|
873
|
+
The number of priorities in the data product (differs between CoDICE-Lo
|
|
874
|
+
and CoDICE-Hi).
|
|
875
|
+
|
|
876
|
+
Returns
|
|
877
|
+
-------
|
|
878
|
+
data : dict[str, numpy.ndarray]
|
|
879
|
+
The reshaped, CDF-ready arrays. The keys of the dictionary represent the
|
|
880
|
+
CDF variable names, and the values represent the data.
|
|
881
|
+
"""
|
|
882
|
+
# Dictionary to hold all the (soon to be restructured) direct event data
|
|
883
|
+
data: dict[str, np.ndarray] = {}
|
|
884
|
+
|
|
885
|
+
# Determine the number of epochs to help with data array initialization
|
|
886
|
+
# There is one epoch per set of priorities
|
|
887
|
+
num_epochs = len(packets.epoch.data) // num_priorities
|
|
888
|
+
|
|
889
|
+
# Initialize data arrays for each priority and field to store the data
|
|
890
|
+
# We also need arrays to hold number of events and data quality
|
|
891
|
+
for priority_num in range(num_priorities):
|
|
892
|
+
for field in constants.LO_DE_BIT_STRUCTURE:
|
|
893
|
+
if field not in ["Priority", "Spare"]:
|
|
894
|
+
data[f"P{priority_num}_{field}"] = np.full(
|
|
895
|
+
(num_epochs, 10000), 255, dtype=np.uint16
|
|
896
|
+
)
|
|
897
|
+
data[f"P{priority_num}_NumEvents"] = np.full(num_epochs, 255, dtype=np.uint16)
|
|
898
|
+
data[f"P{priority_num}_DataQuality"] = np.full(num_epochs, 255, dtype=np.uint16)
|
|
899
|
+
|
|
900
|
+
# decompressed_data is one large list of values of length
|
|
901
|
+
# (<number of epochs> * <8 priorities>)
|
|
902
|
+
# Chunk the data into each epoch
|
|
903
|
+
for epoch_index in range(num_epochs):
|
|
904
|
+
# Determine the starting and ending indices of the epoch
|
|
905
|
+
epoch_start = epoch_index * num_priorities
|
|
906
|
+
epoch_end = epoch_start + num_priorities
|
|
907
|
+
|
|
908
|
+
# Extract the data for the epoch
|
|
909
|
+
epoch_data = decompressed_data[epoch_start:epoch_end]
|
|
910
|
+
|
|
911
|
+
# The order of the priorities and data quality flags are unique to each
|
|
912
|
+
# epoch and can be gathered from the packet data
|
|
913
|
+
priority_order = packets.priority[epoch_start:epoch_end].data
|
|
914
|
+
data_quality = packets.suspect[epoch_start:epoch_end].data
|
|
915
|
+
|
|
916
|
+
# For each epoch/priority combo, iterate over each event
|
|
917
|
+
for i, priority_num in enumerate(priority_order):
|
|
918
|
+
priority_data = epoch_data[i]
|
|
919
|
+
|
|
920
|
+
# Number of events and data quality can be determined at this stage
|
|
921
|
+
num_events = len(priority_data) // num_priorities
|
|
922
|
+
data[f"P{priority_num}_NumEvents"][epoch_index] = num_events
|
|
923
|
+
data[f"P{priority_num}_DataQuality"][epoch_index] = data_quality[i]
|
|
924
|
+
|
|
925
|
+
# Iterate over each event
|
|
926
|
+
for event_index in range(num_events):
|
|
927
|
+
event_start = event_index * num_priorities
|
|
928
|
+
event_end = event_start + num_priorities
|
|
929
|
+
event = priority_data[event_start:event_end]
|
|
930
|
+
# Separate out each individual field from the bit string
|
|
931
|
+
# The fields are packed into the bit string in reverse order, so
|
|
932
|
+
# we need to back them out in reverse order
|
|
933
|
+
bit_string = (
|
|
934
|
+
f"{int.from_bytes(event, byteorder='big'):0{len(event) * 8}b}"
|
|
935
|
+
)
|
|
936
|
+
bit_position = 0
|
|
937
|
+
for field_name, bit_length in reversed(
|
|
938
|
+
constants.LO_DE_BIT_STRUCTURE.items()
|
|
939
|
+
):
|
|
940
|
+
if field_name in ["Priority", "Spare"]:
|
|
941
|
+
bit_position += bit_length
|
|
942
|
+
continue
|
|
943
|
+
value = int(bit_string[bit_position : bit_position + bit_length], 2)
|
|
944
|
+
data[f"P{priority_num}_{field_name}"][epoch_index, event_index] = (
|
|
945
|
+
value
|
|
946
|
+
)
|
|
947
|
+
bit_position += bit_length
|
|
948
|
+
|
|
949
|
+
# TODO: Implement specific np.dtype and fill_val per field
|
|
950
|
+
|
|
951
|
+
return data
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
def process_codice_l1a(file_path: Path) -> list[xr.Dataset]:
|
|
745
955
|
"""
|
|
746
956
|
Will process CoDICE l0 data to create l1a data products.
|
|
747
957
|
|
|
@@ -749,8 +959,6 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
|
|
|
749
959
|
----------
|
|
750
960
|
file_path : pathlib.Path | str
|
|
751
961
|
Path to the CoDICE L0 file to process.
|
|
752
|
-
data_version : str
|
|
753
|
-
Version of the data product being created.
|
|
754
962
|
|
|
755
963
|
Returns
|
|
756
964
|
-------
|
|
@@ -774,14 +982,19 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
|
|
|
774
982
|
|
|
775
983
|
# Housekeeping data
|
|
776
984
|
if apid == CODICEAPID.COD_NHK:
|
|
777
|
-
processed_dataset = create_hskp_dataset(dataset
|
|
985
|
+
processed_dataset = create_hskp_dataset(dataset)
|
|
778
986
|
logger.info(f"\nFinal data product:\n{processed_dataset}\n")
|
|
779
987
|
|
|
780
988
|
# Event data
|
|
781
|
-
elif apid
|
|
782
|
-
processed_dataset =
|
|
989
|
+
elif apid == CODICEAPID.COD_LO_PHA:
|
|
990
|
+
processed_dataset = create_direct_event_dataset(apid, dataset)
|
|
783
991
|
logger.info(f"\nFinal data product:\n{processed_dataset}\n")
|
|
784
992
|
|
|
993
|
+
# TODO: Still need to implement
|
|
994
|
+
elif apid == CODICEAPID.COD_HI_PHA:
|
|
995
|
+
logger.info("\tStill need to properly implement")
|
|
996
|
+
processed_dataset = None
|
|
997
|
+
|
|
785
998
|
# Everything else
|
|
786
999
|
elif apid in constants.APIDS_FOR_SCIENCE_PROCESSING:
|
|
787
1000
|
# Extract the data
|
|
@@ -792,7 +1005,7 @@ def process_codice_l1a(file_path: Path, data_version: str) -> list[xr.Dataset]:
|
|
|
792
1005
|
|
|
793
1006
|
# Run the pipeline to create a dataset for the product
|
|
794
1007
|
pipeline = CoDICEL1aPipeline(table_id, plan_id, plan_step, view_id)
|
|
795
|
-
pipeline.set_data_product_config(apid, dataset
|
|
1008
|
+
pipeline.set_data_product_config(apid, dataset)
|
|
796
1009
|
pipeline.decompress_data(science_values)
|
|
797
1010
|
pipeline.reshape_data()
|
|
798
1011
|
pipeline.define_coordinates()
|
|
@@ -1,194 +1,93 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Perform CoDICE l1b processing.
|
|
3
3
|
|
|
4
|
-
This module processes CoDICE l1a files and creates
|
|
4
|
+
This module processes CoDICE l1a files and creates L1b data products.
|
|
5
5
|
|
|
6
6
|
Notes
|
|
7
7
|
-----
|
|
8
|
-
from imap_processing.codice.codice_l0 import decom_packets
|
|
9
8
|
from imap_processing.codice.codice_l1b import process_codice_l1b
|
|
10
|
-
dataset = process_codice_l1b(
|
|
9
|
+
dataset = process_codice_l1b(l1a_filenanme)
|
|
11
10
|
"""
|
|
12
11
|
|
|
13
12
|
import logging
|
|
13
|
+
from pathlib import Path
|
|
14
14
|
|
|
15
15
|
import xarray as xr
|
|
16
16
|
|
|
17
17
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
18
|
+
from imap_processing.cdf.utils import load_cdf
|
|
19
|
+
from imap_processing.codice import constants
|
|
18
20
|
|
|
19
21
|
logger = logging.getLogger(__name__)
|
|
20
22
|
logger.setLevel(logging.INFO)
|
|
21
23
|
|
|
22
|
-
# TODO: Fix ISTP compliance issues (revealed in SKTEditor)
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
def create_hskp_dataset(
|
|
26
|
-
l1a_dataset: xr.Dataset, cdf_attrs: ImapCdfAttributes
|
|
27
|
-
) -> xr.Dataset:
|
|
28
|
-
"""
|
|
29
|
-
Create an ``xarray`` dataset for the housekeeping data.
|
|
30
|
-
|
|
31
|
-
The dataset can then be written to a CDF file.
|
|
32
|
-
|
|
33
|
-
Parameters
|
|
34
|
-
----------
|
|
35
|
-
l1a_dataset : xr.Dataset
|
|
36
|
-
The L1a dataset that is being processed.
|
|
37
|
-
cdf_attrs : ImapCdfAttributes
|
|
38
|
-
The CDF attributes for the dataset.
|
|
39
|
-
|
|
40
|
-
Returns
|
|
41
|
-
-------
|
|
42
|
-
l1b_dataset : xarray.Dataset
|
|
43
|
-
The ``xarray`` dataset containing the science data and supporting metadata.
|
|
44
|
-
"""
|
|
45
|
-
epoch = l1a_dataset.coords["epoch"]
|
|
46
|
-
l1b_dataset = xr.Dataset(
|
|
47
|
-
coords={"epoch": epoch},
|
|
48
|
-
attrs=cdf_attrs.get_global_attributes("imap_codice_l1b_hskp"),
|
|
49
|
-
)
|
|
50
|
-
for variable_name in l1a_dataset:
|
|
51
|
-
# Get the data array from the L1a data product
|
|
52
|
-
values = l1a_dataset[variable_name].values
|
|
53
|
-
|
|
54
|
-
# Convert data array to "rates"
|
|
55
|
-
# TODO: For SIT-3, just convert value to float. Revisit after SIT-3.
|
|
56
|
-
variable_data_arr = values.astype(float)
|
|
57
|
-
|
|
58
|
-
# TODO: Change 'TBD' catdesc and fieldname
|
|
59
|
-
# Once packet definition files are re-generated, can get this info from
|
|
60
|
-
# something like this:
|
|
61
|
-
# for key, value in (packet.header | packet.data).items():
|
|
62
|
-
# fieldname = value.short_description
|
|
63
|
-
# catdesc = value.short_description
|
|
64
|
-
# I am holding off making this change until I acquire updated housekeeping
|
|
65
|
-
# packets/validation data that match the latest telemetry definitions
|
|
66
|
-
attrs = cdf_attrs.get_variable_attributes("codice_support_attrs")
|
|
67
|
-
attrs["CATDESC"] = "TBD"
|
|
68
|
-
attrs["DEPEND_0"] = "epoch"
|
|
69
|
-
attrs["FIELDNAM"] = "TBD"
|
|
70
|
-
attrs["LABLAXIS"] = variable_name
|
|
71
|
-
|
|
72
|
-
# Put the new data array into the dataset
|
|
73
|
-
l1b_dataset[variable_name] = xr.DataArray(
|
|
74
|
-
variable_data_arr,
|
|
75
|
-
name=variable_name,
|
|
76
|
-
dims=["epoch"],
|
|
77
|
-
attrs=attrs,
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
return l1b_dataset
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def create_science_dataset(
|
|
84
|
-
l1a_dataset: xr.Dataset, cdf_attrs: ImapCdfAttributes, dataset_name: str
|
|
85
|
-
) -> xr.Dataset:
|
|
86
|
-
"""
|
|
87
|
-
Create an ``xarray`` dataset for the science data.
|
|
88
|
-
|
|
89
|
-
The dataset can then be written to a CDF file.
|
|
90
|
-
|
|
91
|
-
Parameters
|
|
92
|
-
----------
|
|
93
|
-
l1a_dataset : xr.Dataset
|
|
94
|
-
The L1a dataset that is being processed.
|
|
95
|
-
cdf_attrs : ImapCdfAttributes
|
|
96
|
-
The CDF attributes for the dataset.
|
|
97
|
-
dataset_name : str
|
|
98
|
-
The name that is used to construct the data variable name and reference
|
|
99
|
-
the CDF attributes (e.g. ``imap_codice_l1b_hi_omni``).
|
|
100
|
-
|
|
101
|
-
Returns
|
|
102
|
-
-------
|
|
103
|
-
l1b_dataset : xarray.Dataset
|
|
104
|
-
The ``xarray`` dataset containing the science data and supporting metadata.
|
|
105
|
-
"""
|
|
106
|
-
# Retrieve the coordinates from the l1a dataset
|
|
107
|
-
epoch = l1a_dataset.coords["epoch"]
|
|
108
|
-
energy = l1a_dataset.coords["energy"]
|
|
109
|
-
energy_label = l1a_dataset.coords["energy_label"]
|
|
110
|
-
|
|
111
|
-
# Create empty l1b dataset
|
|
112
|
-
l1b_dataset = xr.Dataset(
|
|
113
|
-
coords={"epoch": epoch, "energy": energy, "energy_label": energy_label},
|
|
114
|
-
attrs=cdf_attrs.get_global_attributes(dataset_name),
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
# Get the data variables from l1a dataset
|
|
118
|
-
for variable_name in l1a_dataset:
|
|
119
|
-
if variable_name == "esa_sweep_values":
|
|
120
|
-
values = l1a_dataset["esa_sweep_values"]
|
|
121
|
-
l1b_dataset["esa_sweep_values"] = xr.DataArray(
|
|
122
|
-
values,
|
|
123
|
-
dims=["energy"],
|
|
124
|
-
attrs=cdf_attrs.get_variable_attributes("esa_sweep_attrs"),
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
elif variable_name == "acquisition_times":
|
|
128
|
-
values = l1a_dataset["acquisition_times"]
|
|
129
|
-
l1b_dataset["acquisition_times"] = xr.DataArray(
|
|
130
|
-
values,
|
|
131
|
-
dims=["energy"],
|
|
132
|
-
attrs=cdf_attrs.get_variable_attributes("acquisition_times_attrs"),
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
else:
|
|
136
|
-
# Get the data array from the L1a data product
|
|
137
|
-
values = l1a_dataset[variable_name].values
|
|
138
|
-
|
|
139
|
-
# Convert data array to "rates"
|
|
140
|
-
# TODO: For SIT-3, just convert value to float. Revisit after SIT-3.
|
|
141
|
-
variable_data_arr = values.astype(float)
|
|
142
|
-
|
|
143
|
-
# Put the new data array into the dataset
|
|
144
|
-
cdf_attrs_key = (
|
|
145
|
-
f"{dataset_name.split('imap_codice_l1b_')[-1]}-{variable_name}"
|
|
146
|
-
)
|
|
147
|
-
l1b_dataset[variable_name] = xr.DataArray(
|
|
148
|
-
variable_data_arr,
|
|
149
|
-
name=variable_name,
|
|
150
|
-
dims=["epoch", "energy"],
|
|
151
|
-
attrs=cdf_attrs.get_variable_attributes(cdf_attrs_key),
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
return l1b_dataset
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def process_codice_l1b(l1a_dataset: xr.Dataset, data_version: str) -> xr.Dataset:
|
|
25
|
+
def process_codice_l1b(file_path: Path) -> xr.Dataset:
|
|
158
26
|
"""
|
|
159
27
|
Will process CoDICE l1a data to create l1b data products.
|
|
160
28
|
|
|
161
29
|
Parameters
|
|
162
30
|
----------
|
|
163
|
-
|
|
164
|
-
CoDICE L1a
|
|
165
|
-
data_version : str
|
|
166
|
-
Version of the data product being created.
|
|
31
|
+
file_path : pathlib.Path
|
|
32
|
+
Path to the CoDICE L1a file to process.
|
|
167
33
|
|
|
168
34
|
Returns
|
|
169
35
|
-------
|
|
170
36
|
l1b_dataset : xarray.Dataset
|
|
171
37
|
The``xarray`` dataset containing the science data and supporting metadata.
|
|
172
38
|
"""
|
|
173
|
-
logger.info(f"\nProcessing {
|
|
39
|
+
logger.info(f"\nProcessing {file_path}")
|
|
174
40
|
|
|
175
|
-
#
|
|
41
|
+
# Open the l1a file
|
|
42
|
+
l1a_dataset = load_cdf(file_path)
|
|
43
|
+
|
|
44
|
+
# Use the logical source as a way to distinguish between data products and
|
|
45
|
+
# set some useful distinguishing variables
|
|
46
|
+
dataset_name = l1a_dataset.attrs["Logical_source"].replace("_l1a_", "_l1b_")
|
|
47
|
+
descriptor = dataset_name.removeprefix("imap_codice_l1b_")
|
|
48
|
+
apid = constants.CODICEAPID_MAPPING[descriptor]
|
|
49
|
+
|
|
50
|
+
# Get the L1b CDF attributes
|
|
176
51
|
cdf_attrs = ImapCdfAttributes()
|
|
177
52
|
cdf_attrs.add_instrument_global_attrs("codice")
|
|
178
53
|
cdf_attrs.add_instrument_variable_attrs("codice", "l1b")
|
|
179
|
-
cdf_attrs.add_global_attribute("Data_version", data_version)
|
|
180
54
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
55
|
+
# Use the L1a data product as a starting point for L1b
|
|
56
|
+
l1b_dataset = l1a_dataset.copy()
|
|
184
57
|
|
|
185
|
-
|
|
186
|
-
|
|
58
|
+
# Update the global attributes
|
|
59
|
+
l1b_dataset.attrs = cdf_attrs.get_global_attributes(dataset_name)
|
|
187
60
|
|
|
61
|
+
# Determine which variables need to be converted from counts to rates
|
|
62
|
+
# TODO: Figure out exactly which hskp variables need to be converted
|
|
63
|
+
if descriptor == "hskp":
|
|
64
|
+
data_variables = []
|
|
65
|
+
support_variables = ["cmdexe", "cmdrjct"]
|
|
66
|
+
variables_to_convert = support_variables
|
|
188
67
|
else:
|
|
189
|
-
|
|
68
|
+
data_variables = getattr(
|
|
69
|
+
constants, f"{descriptor.upper().replace('-', '_')}_VARIABLE_NAMES"
|
|
70
|
+
)
|
|
71
|
+
support_variables = constants.DATA_PRODUCT_CONFIGURATIONS[apid][
|
|
72
|
+
"support_variables"
|
|
73
|
+
]
|
|
74
|
+
variables_to_convert = data_variables + support_variables
|
|
75
|
+
|
|
76
|
+
for variable_name in variables_to_convert:
|
|
77
|
+
# Apply conversion of data from counts to rates
|
|
78
|
+
# TODO: Properly implement conversion factors on a per-data-product basis
|
|
79
|
+
# For now, just divide by 100 to get float values
|
|
80
|
+
l1b_dataset[variable_name].data = l1b_dataset[variable_name].data / 100
|
|
81
|
+
|
|
82
|
+
# Set the variable attributes
|
|
83
|
+
if variable_name in data_variables:
|
|
84
|
+
cdf_attrs_key = f"{descriptor}-{variable_name}"
|
|
85
|
+
elif variable_name in support_variables:
|
|
86
|
+
cdf_attrs_key = variable_name
|
|
87
|
+
l1b_dataset[variable_name].attrs = cdf_attrs.get_variable_attributes(
|
|
88
|
+
cdf_attrs_key
|
|
89
|
+
)
|
|
190
90
|
|
|
191
|
-
# Write the dataset to CDF
|
|
192
91
|
logger.info(f"\nFinal data product:\n{l1b_dataset}\n")
|
|
193
92
|
|
|
194
93
|
return l1b_dataset
|