imap-processing 0.9.0__py3-none-any.whl → 0.11.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/_version.py +2 -2
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +749 -442
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +7 -0
- imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +8 -2
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +0 -1
- imap_processing/cdf/config/imap_glows_l2_variable_attrs.yaml +358 -0
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +59 -25
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +22 -0
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +32 -8
- imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +94 -5
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +65 -37
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +16 -1
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +7 -0
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +14 -14
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +25 -24
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +238 -0
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +100 -92
- imap_processing/cdf/utils.py +2 -2
- imap_processing/cli.py +45 -9
- imap_processing/codice/codice_l1a.py +104 -58
- imap_processing/codice/constants.py +111 -155
- imap_processing/codice/data/esa_sweep_values.csv +256 -256
- imap_processing/codice/data/lo_stepping_values.csv +128 -128
- imap_processing/ena_maps/ena_maps.py +519 -0
- imap_processing/ena_maps/utils/map_utils.py +145 -0
- imap_processing/ena_maps/utils/spatial_utils.py +226 -0
- imap_processing/glows/__init__.py +3 -0
- imap_processing/glows/ancillary/imap_glows_pipeline_settings_v001.json +52 -0
- imap_processing/glows/l1a/glows_l1a.py +72 -14
- imap_processing/glows/l1b/glows_l1b.py +2 -1
- imap_processing/glows/l1b/glows_l1b_data.py +25 -1
- imap_processing/glows/l2/glows_l2.py +324 -0
- imap_processing/glows/l2/glows_l2_data.py +156 -51
- imap_processing/hi/l1a/science_direct_event.py +57 -51
- imap_processing/hi/l1b/hi_l1b.py +43 -28
- imap_processing/hi/l1c/hi_l1c.py +225 -42
- imap_processing/hi/utils.py +20 -3
- imap_processing/hit/l0/constants.py +2 -2
- imap_processing/hit/l0/decom_hit.py +1 -1
- imap_processing/hit/l1a/hit_l1a.py +94 -13
- imap_processing/hit/l1b/hit_l1b.py +158 -9
- imap_processing/ialirt/l0/process_codicehi.py +156 -0
- imap_processing/ialirt/l0/process_codicelo.py +5 -2
- imap_processing/ialirt/packet_definitions/ialirt.xml +28 -20
- imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +241 -0
- imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +170 -0
- imap_processing/ialirt/packet_definitions/ialirt_swe.xml +258 -0
- imap_processing/ialirt/process_ephemeris.py +72 -40
- imap_processing/idex/decode.py +241 -0
- imap_processing/idex/idex_l1a.py +143 -81
- imap_processing/idex/idex_l1b.py +244 -10
- imap_processing/lo/l0/lo_science.py +61 -0
- imap_processing/lo/l1a/lo_l1a.py +98 -10
- imap_processing/lo/l1b/lo_l1b.py +2 -2
- imap_processing/lo/l1c/lo_l1c.py +2 -2
- imap_processing/lo/packet_definitions/lo_xtce.xml +1082 -9178
- imap_processing/mag/l0/decom_mag.py +2 -2
- imap_processing/mag/l1a/mag_l1a.py +7 -7
- imap_processing/mag/l1a/mag_l1a_data.py +62 -30
- imap_processing/mag/l1b/mag_l1b.py +11 -6
- imap_processing/quality_flags.py +18 -3
- imap_processing/spice/geometry.py +149 -177
- imap_processing/spice/kernels.py +26 -26
- imap_processing/spice/spin.py +233 -0
- imap_processing/spice/time.py +96 -31
- imap_processing/swapi/l1/swapi_l1.py +60 -31
- imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +363 -384
- imap_processing/swe/l1a/swe_l1a.py +8 -3
- imap_processing/swe/l1a/swe_science.py +24 -24
- imap_processing/swe/l1b/swe_l1b.py +2 -1
- imap_processing/swe/l1b/swe_l1b_science.py +181 -122
- imap_processing/swe/l2/swe_l2.py +337 -70
- imap_processing/swe/utils/swe_utils.py +28 -0
- imap_processing/tests/cdf/test_utils.py +2 -2
- imap_processing/tests/codice/conftest.py +20 -17
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hskp_20241110193622_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/test_codice_l0.py +55 -121
- imap_processing/tests/codice/test_codice_l1a.py +147 -59
- imap_processing/tests/conftest.py +81 -22
- imap_processing/tests/ena_maps/test_ena_maps.py +309 -0
- imap_processing/tests/ena_maps/test_map_utils.py +286 -0
- imap_processing/tests/ena_maps/test_spatial_utils.py +161 -0
- imap_processing/tests/glows/conftest.py +7 -1
- imap_processing/tests/glows/test_glows_l1a_cdf.py +3 -7
- imap_processing/tests/glows/test_glows_l1a_data.py +34 -6
- imap_processing/tests/glows/test_glows_l1b_data.py +29 -17
- imap_processing/tests/glows/test_glows_l2.py +101 -0
- imap_processing/tests/hi/conftest.py +3 -3
- imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
- imap_processing/tests/hi/data/l1/imap_his_pset-calibration-prod-config_20240101_v001.csv +31 -0
- imap_processing/tests/hi/test_hi_l1b.py +14 -9
- imap_processing/tests/hi/test_hi_l1c.py +136 -36
- imap_processing/tests/hi/test_l1a.py +0 -2
- imap_processing/tests/hi/test_science_direct_event.py +18 -14
- imap_processing/tests/hi/test_utils.py +16 -11
- imap_processing/tests/hit/helpers/__init__.py +0 -0
- imap_processing/tests/hit/helpers/l1_validation.py +405 -0
- imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
- imap_processing/tests/hit/test_decom_hit.py +8 -10
- imap_processing/tests/hit/test_hit_l1a.py +117 -180
- imap_processing/tests/hit/test_hit_l1b.py +149 -55
- imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -0
- imap_processing/tests/hit/validation_data/sci_sample_raw.csv +62 -0
- imap_processing/tests/ialirt/test_data/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/eu_SWP_IAL_20240826_152033.csv +644 -0
- imap_processing/tests/ialirt/test_data/l0/hi_fsw_view_1_ccsds.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +914 -0
- imap_processing/tests/ialirt/test_data/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
- imap_processing/tests/ialirt/unit/test_process_codicehi.py +106 -0
- imap_processing/tests/ialirt/unit/test_process_ephemeris.py +33 -5
- imap_processing/tests/ialirt/unit/test_process_swapi.py +85 -0
- imap_processing/tests/ialirt/unit/test_process_swe.py +106 -0
- imap_processing/tests/idex/conftest.py +29 -1
- imap_processing/tests/idex/test_data/compressed_2023_102_14_24_55.pkts +0 -0
- imap_processing/tests/idex/test_data/non_compressed_2023_102_14_22_26.pkts +0 -0
- imap_processing/tests/idex/test_idex_l0.py +6 -3
- imap_processing/tests/idex/test_idex_l1a.py +151 -1
- imap_processing/tests/idex/test_idex_l1b.py +124 -2
- imap_processing/tests/lo/test_lo_l1a.py +62 -2
- imap_processing/tests/lo/test_lo_science.py +85 -0
- imap_processing/tests/lo/validation_data/Instrument_FM1_T104_R129_20240803_ILO_SPIN_EU.csv +2 -0
- imap_processing/tests/mag/conftest.py +16 -0
- imap_processing/tests/mag/test_mag_decom.py +6 -4
- imap_processing/tests/mag/test_mag_l1a.py +36 -7
- imap_processing/tests/mag/test_mag_l1b.py +55 -4
- imap_processing/tests/mag/test_mag_validation.py +148 -0
- imap_processing/tests/mag/validation/L1a/T001/all_p_ones.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T002/all_n_ones.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T003/field_like.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T004/field_like.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T005/field_like_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T006/hdr_field.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T007/hdr_field_and_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T008/field_like_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T009/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T010/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T011/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +17 -0
- imap_processing/tests/spice/test_geometry.py +128 -133
- imap_processing/tests/spice/test_kernels.py +37 -37
- imap_processing/tests/spice/test_spin.py +184 -0
- imap_processing/tests/spice/test_time.py +43 -20
- imap_processing/tests/swapi/test_swapi_l1.py +11 -10
- imap_processing/tests/swapi/test_swapi_l2.py +13 -3
- imap_processing/tests/swe/test_swe_l1a.py +1 -1
- imap_processing/tests/swe/test_swe_l1b.py +20 -3
- imap_processing/tests/swe/test_swe_l1b_science.py +54 -35
- imap_processing/tests/swe/test_swe_l2.py +148 -5
- imap_processing/tests/test_cli.py +39 -7
- imap_processing/tests/test_quality_flags.py +19 -19
- imap_processing/tests/test_utils.py +3 -2
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -3314
- imap_processing/tests/ultra/test_data/mock_data.py +161 -0
- imap_processing/tests/ultra/unit/conftest.py +73 -0
- imap_processing/tests/ultra/unit/test_badtimes.py +58 -0
- imap_processing/tests/ultra/unit/test_cullingmask.py +87 -0
- imap_processing/tests/ultra/unit/test_de.py +61 -60
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +3 -3
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +51 -77
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +5 -5
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +114 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -26
- imap_processing/tests/ultra/unit/test_ultra_l1c.py +1 -1
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +3 -3
- imap_processing/ultra/constants.py +11 -1
- imap_processing/ultra/l1a/ultra_l1a.py +2 -2
- imap_processing/ultra/l1b/badtimes.py +22 -5
- imap_processing/ultra/l1b/cullingmask.py +31 -5
- imap_processing/ultra/l1b/de.py +32 -37
- imap_processing/ultra/l1b/extendedspin.py +44 -20
- imap_processing/ultra/l1b/ultra_l1b.py +21 -22
- imap_processing/ultra/l1b/ultra_l1b_culling.py +190 -0
- imap_processing/ultra/l1b/ultra_l1b_extended.py +81 -30
- imap_processing/ultra/l1c/histogram.py +6 -2
- imap_processing/ultra/l1c/pset.py +6 -2
- imap_processing/ultra/l1c/ultra_l1c.py +2 -3
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +4 -3
- imap_processing/ultra/utils/ultra_l1_utils.py +70 -14
- imap_processing/utils.py +2 -2
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/METADATA +7 -2
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/RECORD +235 -152
- imap_processing/tests/codice/data/eu_unit_lookup_table.csv +0 -101
- imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +0 -100
- imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +0 -100
- imap_processing/tests/codice/data/imap_codice_l0_raw_20241110_v001.pkts +0 -0
- imap_processing/tests/hi/test_data/l1a/imap_hi_l1a_45sensor-de_20250415_v000.cdf +0 -0
- imap_processing/tests/hit/test_data/sci_sample1.ccsds +0 -0
- imap_processing/tests/ultra/unit/test_spatial_utils.py +0 -125
- imap_processing/ultra/utils/spatial_utils.py +0 -221
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.csv +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_CNT.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_DE.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_NHK_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_cnt_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_de_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/README.txt +0 -0
- /imap_processing/tests/idex/{imap_idex_l0_raw_20231214_v001.pkts → test_data/imap_idex_l0_raw_20231214_v001.pkts} +0 -0
- /imap_processing/tests/idex/{impact_14_tof_high_data.txt → test_data/impact_14_tof_high_data.txt} +0 -0
- /imap_processing/tests/mag/{imap_mag_l1a_norm-magi_20251017_v001.cdf → validation/imap_mag_l1a_norm-magi_20251017_v001.cdf} +0 -0
- /imap_processing/tests/mag/{mag_l0_test_data.pkts → validation/mag_l0_test_data.pkts} +0 -0
- /imap_processing/tests/mag/{mag_l0_test_output.csv → validation/mag_l0_test_output.csv} +0 -0
- /imap_processing/tests/mag/{mag_l1_test_data.pkts → validation/mag_l1_test_data.pkts} +0 -0
- /imap_processing/tests/mag/{mag_l1a_test_output.csv → validation/mag_l1a_test_output.csv} +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Functions for retrieving spin-table data."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from numpy import typing as npt
|
|
10
|
+
|
|
11
|
+
from imap_processing.spice.geometry import (
|
|
12
|
+
SpiceFrame,
|
|
13
|
+
get_spacecraft_to_instrument_spin_phase_offset,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_spin_data() -> pd.DataFrame:
|
|
18
|
+
"""
|
|
19
|
+
Read spin file using environment variable and return spin data.
|
|
20
|
+
|
|
21
|
+
SPIN_DATA_FILEPATH environment variable would be a fixed value.
|
|
22
|
+
It could be s3 filepath that can be used to download the data
|
|
23
|
+
through API or it could be path EFS or Batch volume mount path.
|
|
24
|
+
|
|
25
|
+
Spin data should contain the following fields:
|
|
26
|
+
* spin_number
|
|
27
|
+
* spin_start_sec
|
|
28
|
+
* spin_start_subsec
|
|
29
|
+
* spin_period_sec
|
|
30
|
+
* spin_period_valid
|
|
31
|
+
* spin_phase_valid
|
|
32
|
+
* spin_period_source
|
|
33
|
+
* thruster_firing
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
spin_data : pandas.DataFrame
|
|
38
|
+
Spin data.
|
|
39
|
+
"""
|
|
40
|
+
spin_data_filepath = os.getenv("SPIN_DATA_FILEPATH")
|
|
41
|
+
if spin_data_filepath is not None:
|
|
42
|
+
path_to_spin_file = Path(spin_data_filepath)
|
|
43
|
+
else:
|
|
44
|
+
# Handle the case where the environment variable is not set
|
|
45
|
+
raise ValueError("SPIN_DATA_FILEPATH environment variable is not set.")
|
|
46
|
+
|
|
47
|
+
spin_df = pd.read_csv(path_to_spin_file, comment="#")
|
|
48
|
+
# Combine spin_start_sec and spin_start_subsec to get the spin start
|
|
49
|
+
# time in seconds. The spin start subseconds are in milliseconds.
|
|
50
|
+
spin_df["spin_start_time"] = (
|
|
51
|
+
spin_df["spin_start_sec"] + spin_df["spin_start_subsec"] / 1e3
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return spin_df
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.DataFrame:
|
|
58
|
+
"""
|
|
59
|
+
Interpolate spin table data to the queried MET times.
|
|
60
|
+
|
|
61
|
+
All columns in the spin table csv file are interpolated to the previous
|
|
62
|
+
table entry. A sc_spin_phase column is added that is the computed spacecraft
|
|
63
|
+
spin phase at the queried MET times. Note that spin phase is by definition,
|
|
64
|
+
in the interval [0, 1) where 1 is equivalent to 360 degrees.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
query_met_times : float or np.ndarray
|
|
69
|
+
Query times in Mission Elapsed Time (MET).
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
spin_df : pandas.DataFrame
|
|
74
|
+
Spin table data with the spin-phase column added and one row
|
|
75
|
+
interpolated for each queried MET time. Output columns are:
|
|
76
|
+
* spin_number
|
|
77
|
+
* spin_start_sec
|
|
78
|
+
* spin_start_subsec
|
|
79
|
+
* spin_period_sec
|
|
80
|
+
* spin_period_valid
|
|
81
|
+
* spin_phase_valid
|
|
82
|
+
* spin_period_source
|
|
83
|
+
* thruster_firing
|
|
84
|
+
* spin_start_met
|
|
85
|
+
* sc_spin_phase
|
|
86
|
+
"""
|
|
87
|
+
spin_df = get_spin_data()
|
|
88
|
+
|
|
89
|
+
# Ensure query_met_times is an array
|
|
90
|
+
query_met_times = np.asarray(query_met_times)
|
|
91
|
+
is_scalar = query_met_times.ndim == 0
|
|
92
|
+
if is_scalar:
|
|
93
|
+
# Force scalar to array because np.asarray() will not
|
|
94
|
+
# convert scalar to array
|
|
95
|
+
query_met_times = np.atleast_1d(query_met_times)
|
|
96
|
+
|
|
97
|
+
# Make sure input times are within the bounds of spin data
|
|
98
|
+
spin_df_start_time = spin_df["spin_start_time"].values[0]
|
|
99
|
+
spin_df_end_time = (
|
|
100
|
+
spin_df["spin_start_time"].values[-1] + spin_df["spin_period_sec"].values[-1]
|
|
101
|
+
)
|
|
102
|
+
input_start_time = query_met_times.min()
|
|
103
|
+
input_end_time = query_met_times.max()
|
|
104
|
+
if input_start_time < spin_df_start_time or input_end_time >= spin_df_end_time:
|
|
105
|
+
raise ValueError(
|
|
106
|
+
f"Query times, {query_met_times} are outside of the spin data range, "
|
|
107
|
+
f"{spin_df_start_time, spin_df_end_time}."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Find all spin time that are less or equal to query_met_times.
|
|
111
|
+
# To do that, use side right, a[i-1] <= v < a[i], in the searchsorted.
|
|
112
|
+
# Eg.
|
|
113
|
+
# >>> df['a']
|
|
114
|
+
# array([0, 15, 30, 45, 60])
|
|
115
|
+
# >>> np.searchsorted(df['a'], [0, 13, 15, 32, 70], side='right')
|
|
116
|
+
# array([1, 1, 2, 3, 5])
|
|
117
|
+
last_spin_indices = (
|
|
118
|
+
np.searchsorted(spin_df["spin_start_time"], query_met_times, side="right") - 1
|
|
119
|
+
)
|
|
120
|
+
# Generate a dataframe with one row per query time
|
|
121
|
+
out_df = spin_df.iloc[last_spin_indices]
|
|
122
|
+
|
|
123
|
+
# Calculate spin phase
|
|
124
|
+
spin_phases = (query_met_times - out_df["spin_start_time"].values) / out_df[
|
|
125
|
+
"spin_period_sec"
|
|
126
|
+
].values
|
|
127
|
+
|
|
128
|
+
# Check for invalid spin phase using below checks:
|
|
129
|
+
# 1. Check that the spin phase is in valid range, [0, 1).
|
|
130
|
+
# 2. Check invalid spin phase using spin_phase_valid,
|
|
131
|
+
# spin_period_valid columns.
|
|
132
|
+
invalid_spin_phase_range = (spin_phases < 0) | (spin_phases >= 1)
|
|
133
|
+
|
|
134
|
+
invalid_spins = (out_df["spin_phase_valid"].values == 0) | (
|
|
135
|
+
out_df["spin_period_valid"].values == 0
|
|
136
|
+
)
|
|
137
|
+
bad_spin_phases = invalid_spin_phase_range | invalid_spins
|
|
138
|
+
spin_phases[bad_spin_phases] = np.nan
|
|
139
|
+
|
|
140
|
+
# Add spin_phase column to output dataframe
|
|
141
|
+
out_df["sc_spin_phase"] = spin_phases
|
|
142
|
+
|
|
143
|
+
return out_df
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_spin_angle(
|
|
147
|
+
spin_phases: Union[float, npt.NDArray],
|
|
148
|
+
degrees: bool = False,
|
|
149
|
+
) -> Union[float, npt.NDArray]:
|
|
150
|
+
"""
|
|
151
|
+
Convert spin_phases to radians or degrees.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
spin_phases : float or np.ndarray
|
|
156
|
+
Instrument or spacecraft spin phases. Spin phase is a
|
|
157
|
+
floating point number in the range [0, 1) corresponding to the
|
|
158
|
+
spin angle / 360.
|
|
159
|
+
degrees : bool
|
|
160
|
+
If degrees parameter is True, return angle in degrees otherwise return angle in
|
|
161
|
+
radians. Default is False.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
spin_phases : float or np.ndarray
|
|
166
|
+
Spin angle in degrees or radians for the input query times.
|
|
167
|
+
"""
|
|
168
|
+
if np.any(spin_phases < 0) or np.any(spin_phases >= 1):
|
|
169
|
+
raise ValueError(
|
|
170
|
+
f"Spin phases, {spin_phases} are outside of the expected spin phase range, "
|
|
171
|
+
f"[0, 1) "
|
|
172
|
+
)
|
|
173
|
+
if degrees:
|
|
174
|
+
# Convert to degrees
|
|
175
|
+
return spin_phases * 360
|
|
176
|
+
else:
|
|
177
|
+
# Convert to radians
|
|
178
|
+
return spin_phases * 2 * np.pi
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def get_spacecraft_spin_phase(
|
|
182
|
+
query_met_times: Union[float, npt.NDArray],
|
|
183
|
+
) -> Union[float, npt.NDArray]:
|
|
184
|
+
"""
|
|
185
|
+
Get the spacecraft spin phase for the input query times.
|
|
186
|
+
|
|
187
|
+
Formula to calculate spin phase:
|
|
188
|
+
spin_phase = (query_met_times - spin_start_time) / spin_period_sec
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
query_met_times : float or np.ndarray
|
|
193
|
+
Query times in Mission Elapsed Time (MET).
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
spin_phase : float or np.ndarray
|
|
198
|
+
Spin phase for the input query times.
|
|
199
|
+
"""
|
|
200
|
+
spin_df = interpolate_spin_data(query_met_times)
|
|
201
|
+
if np.asarray(query_met_times).ndim == 0:
|
|
202
|
+
return spin_df["sc_spin_phase"].values[0]
|
|
203
|
+
return spin_df["sc_spin_phase"].values
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_instrument_spin_phase(
|
|
207
|
+
query_met_times: Union[float, npt.NDArray], instrument: SpiceFrame
|
|
208
|
+
) -> Union[float, npt.NDArray]:
|
|
209
|
+
"""
|
|
210
|
+
Get the instrument spin phase for the input query times.
|
|
211
|
+
|
|
212
|
+
Formula to calculate spin phase:
|
|
213
|
+
instrument_spin_phase = (spacecraft_spin_phase + instrument_spin_offset) % 1
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
query_met_times : float or np.ndarray
|
|
218
|
+
Query times in Mission Elapsed Time (MET).
|
|
219
|
+
instrument : SpiceFrame
|
|
220
|
+
Instrument frame to calculate spin phase for.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
spin_phase : float or np.ndarray
|
|
225
|
+
Instrument spin phase for the input query times. Spin phase is a
|
|
226
|
+
floating point number in the range [0, 1) corresponding to the
|
|
227
|
+
spin angle / 360.
|
|
228
|
+
"""
|
|
229
|
+
spacecraft_spin_phase = get_spacecraft_spin_phase(query_met_times)
|
|
230
|
+
instrument_spin_phase_offset = get_spacecraft_to_instrument_spin_phase_offset(
|
|
231
|
+
instrument
|
|
232
|
+
)
|
|
233
|
+
return (spacecraft_spin_phase + instrument_spin_phase_offset) % 1
|
imap_processing/spice/time.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Time conversion functions that rely on
|
|
1
|
+
"""Time conversion functions that rely on SPICEYPY."""
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
4
|
from collections.abc import Collection, Iterable
|
|
@@ -6,7 +6,7 @@ from typing import Union
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import numpy.typing as npt
|
|
9
|
-
import spiceypy
|
|
9
|
+
import spiceypy
|
|
10
10
|
|
|
11
11
|
from imap_processing.spice import IMAP_SC_ID
|
|
12
12
|
from imap_processing.spice.kernels import ensure_spice
|
|
@@ -19,8 +19,38 @@ TICK_DURATION = 2e-5 # 20 microseconds as defined in imap_sclk_0000.tsc
|
|
|
19
19
|
# TODO: Implement a function for converting CDF epoch to UTC correctly.
|
|
20
20
|
# see github ticket #1208
|
|
21
21
|
# The UTC string was generated by:
|
|
22
|
-
# >>> spiceypy.et2utc(0, "ISOC", 9)
|
|
23
|
-
|
|
22
|
+
# >>> spiceypy.et2utc(spiceypy.unitim(0, "TT", "ET"), "ISOC", 9)
|
|
23
|
+
TTJ2000_EPOCH = np.datetime64("2000-01-01T11:58:55.816", "ns")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@typing.no_type_check
|
|
27
|
+
def _vectorize(pyfunc: typing.Callable, **vectorize_kwargs) -> typing.Callable:
|
|
28
|
+
"""
|
|
29
|
+
Convert 0-D arrays from numpy.vectorize to scalars.
|
|
30
|
+
|
|
31
|
+
For details on numpy.vectorize, see
|
|
32
|
+
https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
pyfunc : callable
|
|
37
|
+
A python function or method.
|
|
38
|
+
**vectorize_kwargs :
|
|
39
|
+
Keyword arguments to pass to numpy.vectorize.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
out : callable
|
|
44
|
+
A vectorized function.
|
|
45
|
+
"""
|
|
46
|
+
vectorized_func = np.vectorize(pyfunc, **vectorize_kwargs)
|
|
47
|
+
|
|
48
|
+
def wrapper(*args, **kwargs): # numpydoc ignore=GL08
|
|
49
|
+
# Calling the vectorized function with [()] will convert 0-D arrays
|
|
50
|
+
# to scalars
|
|
51
|
+
return vectorized_func(*args, **kwargs)[()]
|
|
52
|
+
|
|
53
|
+
return wrapper
|
|
24
54
|
|
|
25
55
|
|
|
26
56
|
def met_to_sclkticks(met: npt.ArrayLike) -> npt.NDArray[float]:
|
|
@@ -40,11 +70,11 @@ def met_to_sclkticks(met: npt.ArrayLike) -> npt.NDArray[float]:
|
|
|
40
70
|
return np.asarray(met, dtype=float) / TICK_DURATION
|
|
41
71
|
|
|
42
72
|
|
|
43
|
-
def
|
|
73
|
+
def met_to_ttj2000ns(
|
|
44
74
|
met: npt.ArrayLike,
|
|
45
75
|
) -> npt.NDArray[np.int64]:
|
|
46
76
|
"""
|
|
47
|
-
Convert mission elapsed time (MET) to nanoseconds since J2000.
|
|
77
|
+
Convert mission elapsed time (MET) to terrestrial time nanoseconds since J2000.
|
|
48
78
|
|
|
49
79
|
Parameters
|
|
50
80
|
----------
|
|
@@ -54,7 +84,8 @@ def met_to_j2000ns(
|
|
|
54
84
|
Returns
|
|
55
85
|
-------
|
|
56
86
|
numpy.ndarray[numpy.int64]
|
|
57
|
-
The mission elapsed time converted to nanoseconds since the J2000 epoch
|
|
87
|
+
The mission elapsed time converted to nanoseconds since the J2000 epoch
|
|
88
|
+
in the terrestrial time (TT) timescale.
|
|
58
89
|
|
|
59
90
|
Notes
|
|
60
91
|
-----
|
|
@@ -67,27 +98,35 @@ def met_to_j2000ns(
|
|
|
67
98
|
it is preferable to use the higher accuracy method.
|
|
68
99
|
"""
|
|
69
100
|
sclk_ticks = met_to_sclkticks(met)
|
|
70
|
-
return np.asarray(
|
|
101
|
+
return np.asarray(sct_to_ttj2000s(sclk_ticks) * 1e9, dtype=np.int64)
|
|
71
102
|
|
|
72
103
|
|
|
73
|
-
|
|
104
|
+
@typing.no_type_check
|
|
105
|
+
@ensure_spice
|
|
106
|
+
def ttj2000ns_to_et(tt_ns: npt.ArrayLike) -> npt.NDArray[float]:
|
|
74
107
|
"""
|
|
75
|
-
Convert
|
|
108
|
+
Convert TT J2000 epoch nanoseconds to TDB J2000 epoch seconds.
|
|
76
109
|
|
|
77
|
-
The common CDF coordinate `epoch` stores
|
|
78
|
-
|
|
110
|
+
The common CDF coordinate `epoch` stores terrestrial time (TT) J2000
|
|
111
|
+
nanoseconds. SPICE requires Barycentric Dynamical Time (TDB, aka ET) J2000
|
|
112
|
+
floating point seconds for most geometry related functions. This is a common
|
|
113
|
+
function to do that conversion.
|
|
79
114
|
|
|
80
115
|
Parameters
|
|
81
116
|
----------
|
|
82
|
-
|
|
83
|
-
Number of nanoseconds since the J2000 epoch.
|
|
117
|
+
tt_ns : float, numpy.ndarray
|
|
118
|
+
Number of nanoseconds since the J2000 epoch in the TT timescale.
|
|
84
119
|
|
|
85
120
|
Returns
|
|
86
121
|
-------
|
|
87
122
|
numpy.ndarray[float]
|
|
88
|
-
Number of seconds since the J2000 epoch.
|
|
123
|
+
Number of seconds since the J2000 epoch in the TDB timescale.
|
|
89
124
|
"""
|
|
90
|
-
|
|
125
|
+
tt_seconds = np.asarray(tt_ns, dtype=np.float64) / 1e9
|
|
126
|
+
vectorized_unitim = _vectorize(
|
|
127
|
+
spiceypy.unitim, otypes=[float], excluded=["insys", "outsys"]
|
|
128
|
+
)
|
|
129
|
+
return vectorized_unitim(tt_seconds, "TT", "ET")
|
|
91
130
|
|
|
92
131
|
|
|
93
132
|
@typing.no_type_check
|
|
@@ -112,8 +151,8 @@ def met_to_utc(met: npt.ArrayLike, precision: int = 9) -> npt.NDArray[str]:
|
|
|
112
151
|
fractional seconds precision as specified by the precision keyword.
|
|
113
152
|
"""
|
|
114
153
|
sclk_ticks = met_to_sclkticks(met)
|
|
115
|
-
et =
|
|
116
|
-
return
|
|
154
|
+
et = sct_to_et(sclk_ticks)
|
|
155
|
+
return spiceypy.et2utc(et, "ISOC", prec=precision)
|
|
117
156
|
|
|
118
157
|
|
|
119
158
|
def met_to_datetime64(
|
|
@@ -132,14 +171,12 @@ def met_to_datetime64(
|
|
|
132
171
|
numpy.ndarray[str]
|
|
133
172
|
The mission elapsed time converted to UTC string.
|
|
134
173
|
"""
|
|
135
|
-
|
|
136
|
-
return np.asarray([np.datetime64(utc) for utc in met_to_utc(met)])
|
|
137
|
-
return np.datetime64(met_to_utc(met))
|
|
174
|
+
return np.array(met_to_utc(met), dtype=np.datetime64)[()]
|
|
138
175
|
|
|
139
176
|
|
|
140
177
|
@typing.no_type_check
|
|
141
178
|
@ensure_spice
|
|
142
|
-
def
|
|
179
|
+
def sct_to_et(
|
|
143
180
|
sclk_ticks: Union[float, Collection[float]],
|
|
144
181
|
) -> Union[float, np.ndarray]:
|
|
145
182
|
"""
|
|
@@ -159,10 +196,40 @@ def _sct2e_wrapper(
|
|
|
159
196
|
ephemeris_time: np.ndarray
|
|
160
197
|
Ephemeris time, seconds past J2000.
|
|
161
198
|
"""
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
199
|
+
vectorized_sct2e = _vectorize(spiceypy.sct2e, otypes=[float], excluded=[0])
|
|
200
|
+
return vectorized_sct2e(IMAP_SC_ID, sclk_ticks)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@typing.no_type_check
|
|
204
|
+
@ensure_spice
|
|
205
|
+
def sct_to_ttj2000s(
|
|
206
|
+
sclk_ticks: Union[float, Iterable[float]],
|
|
207
|
+
) -> Union[float, np.ndarray]:
|
|
208
|
+
"""
|
|
209
|
+
Convert encoded spacecraft clock "ticks" to terrestrial time (TT).
|
|
210
|
+
|
|
211
|
+
Decorated wrapper for chained spiceypy functions `unitim(sct2e(), "ET", "TT")`
|
|
212
|
+
that vectorizes the functions in addition to wrapping with the @ensure_spice
|
|
213
|
+
automatic kernel furnishing functionality.
|
|
214
|
+
https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sct2e_c.html
|
|
215
|
+
https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unitim_c.html
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
sclk_ticks : Union[float, Iterable[float]]
|
|
220
|
+
Input sclk ticks value(s) to be converted to ephemeris time.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
terrestrial_time: np.ndarray[float]
|
|
225
|
+
Terrestrial time, seconds past J2000.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def conversion(sclk_ticks): # numpydoc ignore=GL08
|
|
229
|
+
return spiceypy.unitim(spiceypy.sct2e(IMAP_SC_ID, sclk_ticks), "ET", "TT")
|
|
230
|
+
|
|
231
|
+
vectorized_func = _vectorize(conversion, otypes=[float])
|
|
232
|
+
return vectorized_func(sclk_ticks)
|
|
166
233
|
|
|
167
234
|
|
|
168
235
|
@typing.no_type_check
|
|
@@ -187,10 +254,8 @@ def str_to_et(
|
|
|
187
254
|
ephemeris_time: np.ndarray
|
|
188
255
|
Ephemeris time, seconds past J2000.
|
|
189
256
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
else:
|
|
193
|
-
return np.array([spice.str2et(t) for t in time_str])
|
|
257
|
+
vectorized_str2et = _vectorize(spiceypy.str2et, otypes=[float])
|
|
258
|
+
return vectorized_str2et(time_str)
|
|
194
259
|
|
|
195
260
|
|
|
196
261
|
@typing.no_type_check
|
|
@@ -231,4 +296,4 @@ def et_to_utc(
|
|
|
231
296
|
utc_time : str or np.ndarray
|
|
232
297
|
UTC time(s).
|
|
233
298
|
"""
|
|
234
|
-
return
|
|
299
|
+
return spiceypy.et2utc(et, format_str, precision, utclen)
|
|
@@ -9,6 +9,7 @@ import xarray as xr
|
|
|
9
9
|
|
|
10
10
|
from imap_processing import imap_module_directory
|
|
11
11
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
12
|
+
from imap_processing.cdf.utils import load_cdf
|
|
12
13
|
from imap_processing.quality_flags import SWAPIFlags
|
|
13
14
|
from imap_processing.swapi.swapi_utils import SWAPIAPID, SWAPIMODE
|
|
14
15
|
from imap_processing.utils import packet_file_to_datasets
|
|
@@ -485,12 +486,19 @@ def process_swapi_science(
|
|
|
485
486
|
# ===================================================================
|
|
486
487
|
# Quality flags
|
|
487
488
|
# ===================================================================
|
|
488
|
-
quality_flags_data = np.zeros((total_full_sweeps, 72), np.uint16)
|
|
489
|
+
quality_flags_data = np.zeros((total_full_sweeps, 72), dtype=np.uint16)
|
|
489
490
|
|
|
490
491
|
# Add science data quality flags
|
|
491
|
-
|
|
492
|
-
quality_flags_data[
|
|
493
|
-
|
|
492
|
+
# Have to match datatype to bitwise OR
|
|
493
|
+
quality_flags_data[pcem_compression_flags == 1] |= np.uint16(
|
|
494
|
+
SWAPIFlags.SWP_PCEM_COMP
|
|
495
|
+
)
|
|
496
|
+
quality_flags_data[scem_compression_flags == 1] |= np.uint16(
|
|
497
|
+
SWAPIFlags.SWP_SCEM_COMP
|
|
498
|
+
)
|
|
499
|
+
quality_flags_data[coin_compression_flags == 1] |= np.uint16(
|
|
500
|
+
SWAPIFlags.SWP_COIN_COMP
|
|
501
|
+
)
|
|
494
502
|
|
|
495
503
|
# Add housekeeping-derived quality flags
|
|
496
504
|
# --------------------------------------
|
|
@@ -536,10 +544,10 @@ def process_swapi_science(
|
|
|
536
544
|
# Use getattr to dynamically access the flag in SWAPIFlags class
|
|
537
545
|
flag_to_set = getattr(SWAPIFlags, flag_name)
|
|
538
546
|
# set the quality flag for each data
|
|
539
|
-
quality_flags_data[current_flag == 1] |= flag_to_set
|
|
547
|
+
quality_flags_data[current_flag == 1] |= np.uint16(flag_to_set)
|
|
540
548
|
|
|
541
549
|
swp_flags = xr.DataArray(
|
|
542
|
-
quality_flags_data,
|
|
550
|
+
quality_flags_data.astype(np.uint16),
|
|
543
551
|
dims=["epoch", "energy"],
|
|
544
552
|
attrs=cdf_manager.get_variable_attributes("flags_default"),
|
|
545
553
|
)
|
|
@@ -555,7 +563,7 @@ def process_swapi_science(
|
|
|
555
563
|
epoch_values,
|
|
556
564
|
name="epoch",
|
|
557
565
|
dims=["epoch"],
|
|
558
|
-
attrs=cdf_manager.get_variable_attributes("epoch"),
|
|
566
|
+
attrs=cdf_manager.get_variable_attributes("epoch", check_schema=False),
|
|
559
567
|
)
|
|
560
568
|
|
|
561
569
|
# There are 72 energy steps
|
|
@@ -563,14 +571,14 @@ def process_swapi_science(
|
|
|
563
571
|
np.arange(72),
|
|
564
572
|
name="energy",
|
|
565
573
|
dims=["energy"],
|
|
566
|
-
attrs=cdf_manager.get_variable_attributes("energy"),
|
|
574
|
+
attrs=cdf_manager.get_variable_attributes("energy", check_schema=False),
|
|
567
575
|
)
|
|
568
576
|
# LABL_PTR_1 should be CDF_CHAR.
|
|
569
577
|
energy_label = xr.DataArray(
|
|
570
578
|
energy.values.astype(str),
|
|
571
579
|
name="energy_label",
|
|
572
580
|
dims=["energy_label"],
|
|
573
|
-
attrs=cdf_manager.get_variable_attributes("energy_label"),
|
|
581
|
+
attrs=cdf_manager.get_variable_attributes("energy_label", check_schema=False),
|
|
574
582
|
)
|
|
575
583
|
|
|
576
584
|
# Add other global attributes
|
|
@@ -691,14 +699,14 @@ def process_swapi_science(
|
|
|
691
699
|
return dataset
|
|
692
700
|
|
|
693
701
|
|
|
694
|
-
def swapi_l1(
|
|
702
|
+
def swapi_l1(dependencies: list, data_version: str) -> xr.Dataset:
|
|
695
703
|
"""
|
|
696
704
|
Will process SWAPI level 0 data to level 1.
|
|
697
705
|
|
|
698
706
|
Parameters
|
|
699
707
|
----------
|
|
700
|
-
|
|
701
|
-
|
|
708
|
+
dependencies : list
|
|
709
|
+
Input dependencies needed for L1 processing.
|
|
702
710
|
data_version : str
|
|
703
711
|
Version of the data product being created.
|
|
704
712
|
|
|
@@ -710,27 +718,48 @@ def swapi_l1(file_path: str, data_version: str) -> xr.Dataset:
|
|
|
710
718
|
xtce_definition = (
|
|
711
719
|
f"{imap_module_directory}/swapi/packet_definitions/swapi_packet_definition.xml"
|
|
712
720
|
)
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
721
|
+
l0_unpacked_dict = {}
|
|
722
|
+
l1_hk_ds = None
|
|
723
|
+
for file_path in dependencies:
|
|
724
|
+
if file_path.suffix == ".pkts":
|
|
725
|
+
l0_unpacked_dict = packet_file_to_datasets(
|
|
726
|
+
file_path, xtce_definition, use_derived_value=False
|
|
727
|
+
)
|
|
728
|
+
if file_path.suffix == ".cdf":
|
|
729
|
+
l1_hk_ds = load_cdf(file_path)
|
|
730
|
+
|
|
716
731
|
processed_data = []
|
|
717
732
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
733
|
+
# Right now, we only process SWP_HK and SWP_SCI.
|
|
734
|
+
# Other apId are not processed in this processing pipeline.
|
|
735
|
+
|
|
736
|
+
# Len of dependencies is 2 and l0_unpacked_dict[SWAPIAPID.SWP_HK] is not None
|
|
737
|
+
if (
|
|
738
|
+
len(dependencies) == 2
|
|
739
|
+
and l0_unpacked_dict.get(SWAPIAPID.SWP_SCI, None) is not None
|
|
740
|
+
):
|
|
741
|
+
# process science data
|
|
742
|
+
sci_dataset = process_swapi_science(
|
|
743
|
+
l0_unpacked_dict[SWAPIAPID.SWP_SCI], l1_hk_ds, data_version
|
|
744
|
+
)
|
|
745
|
+
processed_data.append(sci_dataset)
|
|
746
|
+
|
|
747
|
+
elif len(dependencies) == 1 and l0_unpacked_dict[SWAPIAPID.SWP_HK]:
|
|
748
|
+
hk_ds = l0_unpacked_dict[SWAPIAPID.SWP_HK]
|
|
749
|
+
# Add HK datalevel attrs
|
|
750
|
+
imap_attrs = ImapCdfAttributes()
|
|
751
|
+
imap_attrs.add_instrument_global_attrs("swapi")
|
|
752
|
+
imap_attrs.add_global_attribute("Data_version", data_version)
|
|
753
|
+
imap_attrs.add_instrument_variable_attrs(instrument="swapi", level=None)
|
|
754
|
+
hk_ds.attrs.update(imap_attrs.get_global_attributes("imap_swapi_l1_hk"))
|
|
755
|
+
hk_common_attrs = imap_attrs.get_variable_attributes("hk_attrs")
|
|
756
|
+
hk_ds["epoch"].attrs.update(
|
|
757
|
+
imap_attrs.get_variable_attributes("epoch", check_schema=False)
|
|
758
|
+
)
|
|
722
759
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
processed_data.append(sci_dataset)
|
|
728
|
-
if apid == SWAPIAPID.SWP_HK.value:
|
|
729
|
-
# Add HK datalevel attrs
|
|
730
|
-
hk_attrs = ImapCdfAttributes()
|
|
731
|
-
hk_attrs.add_instrument_global_attrs("swapi")
|
|
732
|
-
hk_attrs.add_global_attribute("Data_version", data_version)
|
|
733
|
-
ds_data.attrs.update(hk_attrs.get_global_attributes("imap_swapi_l1_hk"))
|
|
734
|
-
processed_data.append(ds_data)
|
|
760
|
+
# Add attrs to HK data variables
|
|
761
|
+
for var_name in hk_ds.data_vars:
|
|
762
|
+
hk_ds[var_name].attrs.update(hk_common_attrs)
|
|
763
|
+
processed_data.append(hk_ds)
|
|
735
764
|
|
|
736
765
|
return processed_data
|