imap-processing 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/__init__.py +10 -11
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/excel_to_xtce.py +65 -16
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -28
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +365 -42
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
- imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +26 -13
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +6 -9
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +9 -21
- imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
- imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
- imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
- imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +48 -52
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +2 -14
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +51 -2
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +29 -14
- imap_processing/cdf/utils.py +13 -7
- imap_processing/cli.py +23 -8
- imap_processing/codice/codice_l1a.py +207 -85
- imap_processing/codice/constants.py +1322 -568
- imap_processing/codice/decompress.py +2 -6
- imap_processing/ena_maps/ena_maps.py +480 -116
- imap_processing/ena_maps/utils/coordinates.py +19 -0
- imap_processing/ena_maps/utils/map_utils.py +14 -17
- imap_processing/ena_maps/utils/spatial_utils.py +45 -47
- imap_processing/hi/l1a/hi_l1a.py +24 -18
- imap_processing/hi/l1a/histogram.py +0 -1
- imap_processing/hi/l1a/science_direct_event.py +6 -8
- imap_processing/hi/l1b/hi_l1b.py +31 -39
- imap_processing/hi/l1c/hi_l1c.py +405 -17
- imap_processing/hi/utils.py +58 -12
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
- imap_processing/hit/hit_utils.py +173 -1
- imap_processing/hit/l0/constants.py +20 -11
- imap_processing/hit/l0/decom_hit.py +18 -4
- imap_processing/hit/l1a/hit_l1a.py +45 -54
- imap_processing/hit/l1b/constants.py +317 -0
- imap_processing/hit/l1b/hit_l1b.py +367 -18
- imap_processing/hit/l2/constants.py +281 -0
- imap_processing/hit/l2/hit_l2.py +614 -0
- imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
- imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
- imap_processing/ialirt/l0/parse_mag.py +246 -0
- imap_processing/ialirt/l0/process_swe.py +252 -0
- imap_processing/ialirt/packet_definitions/ialirt.xml +7 -3
- imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
- imap_processing/ialirt/utils/grouping.py +114 -0
- imap_processing/ialirt/utils/time.py +29 -0
- imap_processing/idex/atomic_masses.csv +22 -0
- imap_processing/idex/decode.py +2 -2
- imap_processing/idex/idex_constants.py +25 -0
- imap_processing/idex/idex_l1a.py +6 -7
- imap_processing/idex/idex_l1b.py +4 -31
- imap_processing/idex/idex_l2a.py +789 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +39 -33
- imap_processing/lo/l0/lo_science.py +6 -0
- imap_processing/lo/l1a/lo_l1a.py +0 -1
- imap_processing/lo/l1b/lo_l1b.py +177 -25
- imap_processing/mag/constants.py +8 -0
- imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +6 -0
- imap_processing/mag/l0/decom_mag.py +10 -3
- imap_processing/mag/l1a/mag_l1a.py +22 -11
- imap_processing/mag/l1a/mag_l1a_data.py +28 -3
- imap_processing/mag/l1b/mag_l1b.py +190 -48
- imap_processing/mag/l1c/interpolation_methods.py +211 -0
- imap_processing/mag/l1c/mag_l1c.py +447 -9
- imap_processing/quality_flags.py +1 -0
- imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
- imap_processing/spacecraft/quaternions.py +123 -0
- imap_processing/spice/geometry.py +16 -19
- imap_processing/spice/repoint.py +120 -0
- imap_processing/swapi/l1/swapi_l1.py +4 -0
- imap_processing/swapi/l2/swapi_l2.py +0 -1
- imap_processing/swe/l1a/swe_l1a.py +47 -8
- imap_processing/swe/l1a/swe_science.py +5 -2
- imap_processing/swe/l1b/swe_l1b_science.py +103 -56
- imap_processing/swe/l2/swe_l2.py +60 -65
- imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
- imap_processing/swe/utils/swe_constants.py +63 -0
- imap_processing/swe/utils/swe_utils.py +85 -28
- imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
- imap_processing/tests/ccsds/test_excel_to_xtce.py +23 -20
- imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
- imap_processing/tests/codice/conftest.py +1 -1
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/test_codice_l1a.py +110 -46
- imap_processing/tests/codice/test_decompress.py +4 -4
- imap_processing/tests/conftest.py +166 -10
- imap_processing/tests/ena_maps/conftest.py +51 -0
- imap_processing/tests/ena_maps/test_ena_maps.py +638 -109
- imap_processing/tests/ena_maps/test_map_utils.py +66 -43
- imap_processing/tests/ena_maps/test_spatial_utils.py +16 -20
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
- imap_processing/tests/hi/test_hi_l1b.py +12 -15
- imap_processing/tests/hi/test_hi_l1c.py +234 -6
- imap_processing/tests/hi/test_l1a.py +30 -0
- imap_processing/tests/hi/test_science_direct_event.py +1 -1
- imap_processing/tests/hi/test_utils.py +24 -2
- imap_processing/tests/hit/helpers/l1_validation.py +39 -39
- imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
- imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
- imap_processing/tests/hit/test_decom_hit.py +4 -0
- imap_processing/tests/hit/test_hit_l1a.py +24 -28
- imap_processing/tests/hit/test_hit_l1b.py +304 -40
- imap_processing/tests/hit/test_hit_l2.py +454 -0
- imap_processing/tests/hit/test_hit_utils.py +112 -2
- imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
- imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
- imap_processing/tests/ialirt/test_data/l0/461971383-404.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971384-405.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971385-406.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971386-407.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971387-408.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971388-409.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971389-410.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971390-411.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971391-412.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/sample_decoded_i-alirt_data.csv +383 -0
- imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
- imap_processing/tests/ialirt/unit/test_parse_mag.py +168 -0
- imap_processing/tests/ialirt/unit/test_process_swe.py +208 -3
- imap_processing/tests/ialirt/unit/test_time.py +16 -0
- imap_processing/tests/idex/conftest.py +62 -6
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
- imap_processing/tests/idex/test_idex_l1a.py +48 -4
- imap_processing/tests/idex/test_idex_l1b.py +3 -3
- imap_processing/tests/idex/test_idex_l2a.py +383 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_lo_l1b.py +148 -4
- imap_processing/tests/lo/test_lo_science.py +1 -0
- imap_processing/tests/mag/conftest.py +69 -0
- imap_processing/tests/mag/test_mag_decom.py +1 -1
- imap_processing/tests/mag/test_mag_l1a.py +38 -0
- imap_processing/tests/mag/test_mag_l1b.py +34 -53
- imap_processing/tests/mag/test_mag_l1c.py +251 -20
- imap_processing/tests/mag/test_mag_validation.py +109 -25
- imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/imap_calibration_mag_20240229_v01.cdf +0 -0
- imap_processing/tests/spacecraft/__init__.py +0 -0
- imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
- imap_processing/tests/spacecraft/test_quaternions.py +71 -0
- imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
- imap_processing/tests/spice/test_geometry.py +6 -9
- imap_processing/tests/spice/test_repoint.py +111 -0
- imap_processing/tests/swapi/test_swapi_l1.py +7 -3
- imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
- imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
- imap_processing/tests/swe/test_swe_l1a.py +18 -0
- imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
- imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
- imap_processing/tests/swe/test_swe_l1b_science.py +23 -4
- imap_processing/tests/swe/test_swe_l2.py +112 -30
- imap_processing/tests/test_cli.py +2 -2
- imap_processing/tests/test_utils.py +138 -16
- imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
- imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
- imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3243 -3243
- imap_processing/tests/ultra/data/mock_data.py +341 -0
- imap_processing/tests/ultra/unit/conftest.py +69 -26
- imap_processing/tests/ultra/unit/test_badtimes.py +2 -0
- imap_processing/tests/ultra/unit/test_cullingmask.py +4 -0
- imap_processing/tests/ultra/unit/test_de.py +12 -4
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +44 -0
- imap_processing/tests/ultra/unit/test_spacecraft_pset.py +78 -0
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +28 -12
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +34 -6
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +22 -26
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -51
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +94 -52
- imap_processing/ultra/l0/decom_tools.py +6 -5
- imap_processing/ultra/l1a/ultra_l1a.py +28 -56
- imap_processing/ultra/l1b/de.py +72 -28
- imap_processing/ultra/l1b/extendedspin.py +12 -14
- imap_processing/ultra/l1b/ultra_l1b.py +34 -9
- imap_processing/ultra/l1b/ultra_l1b_culling.py +65 -29
- imap_processing/ultra/l1b/ultra_l1b_extended.py +64 -19
- imap_processing/ultra/l1c/spacecraft_pset.py +86 -0
- imap_processing/ultra/l1c/ultra_l1c.py +7 -4
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +112 -61
- imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
- imap_processing/ultra/utils/ultra_l1_utils.py +20 -2
- imap_processing/utils.py +68 -28
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/METADATA +8 -5
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/RECORD +250 -199
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
- imap_processing/hi/l1a/housekeeping.py +0 -27
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
- imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
- imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
- imap_processing/tests/ultra/test_data/mock_data.py +0 -161
- imap_processing/ultra/l1c/pset.py +0 -40
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
"""IMAP-HIT L2 data processing."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import NamedTuple
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import xarray as xr
|
|
10
|
+
|
|
11
|
+
from imap_processing.hit.hit_utils import (
|
|
12
|
+
add_energy_variables,
|
|
13
|
+
get_attribute_manager,
|
|
14
|
+
initialize_particle_data_arrays,
|
|
15
|
+
sum_particle_data,
|
|
16
|
+
)
|
|
17
|
+
from imap_processing.hit.l2.constants import (
|
|
18
|
+
L2_STANDARD_ANCILLARY_PATH_PREFIX,
|
|
19
|
+
L2_SUMMED_ANCILLARY_PATH_PREFIX,
|
|
20
|
+
STANDARD_PARTICLE_ENERGY_RANGE_MAPPING,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# TODO:
|
|
26
|
+
# - review logging levels to use (debug vs. info)
|
|
27
|
+
# - determine where to pull ancillary data. Storing it locally for now
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def hit_l2(dependency: xr.Dataset, data_version: str) -> list[xr.Dataset]:
|
|
31
|
+
"""
|
|
32
|
+
Will process HIT data to L2.
|
|
33
|
+
|
|
34
|
+
Processes dependencies needed to create L2 data products.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
dependency : xr.Dataset
|
|
39
|
+
L1B xarray science dataset that is either summed rates
|
|
40
|
+
standard rates or sector rates.
|
|
41
|
+
data_version : str
|
|
42
|
+
Version of the data product being created.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
processed_data : list[xarray.Dataset]
|
|
47
|
+
List of one L2 dataset.
|
|
48
|
+
"""
|
|
49
|
+
logger.info("Creating HIT L2 science datasets")
|
|
50
|
+
# Create the attribute manager for this data level
|
|
51
|
+
attr_mgr = get_attribute_manager(data_version, "l2")
|
|
52
|
+
|
|
53
|
+
# TODO: Write functions to process sectored rates dataset
|
|
54
|
+
# with logical source: "imap_hit_l2_macropixel-intensity"
|
|
55
|
+
|
|
56
|
+
l2_datasets: dict = {}
|
|
57
|
+
|
|
58
|
+
# Process science data to L2 datasets
|
|
59
|
+
if "imap_hit_l1b_summed-rates" in dependency.attrs["Logical_source"]:
|
|
60
|
+
l2_datasets["imap_hit_l2_summed-intensity"] = process_summed_intensity_data(
|
|
61
|
+
dependency
|
|
62
|
+
)
|
|
63
|
+
logger.info("HIT L2 summed intensity dataset created")
|
|
64
|
+
|
|
65
|
+
if "imap_hit_l1b_standard-rates" in dependency.attrs["Logical_source"]:
|
|
66
|
+
l2_datasets["imap_hit_l2_standard-intensity"] = process_standard_intensity_data(
|
|
67
|
+
dependency
|
|
68
|
+
)
|
|
69
|
+
logger.info("HIT L2 standard intensity dataset created")
|
|
70
|
+
|
|
71
|
+
# Update attributes and dimensions
|
|
72
|
+
for logical_source, dataset in l2_datasets.items():
|
|
73
|
+
dataset.attrs = attr_mgr.get_global_attributes(logical_source)
|
|
74
|
+
|
|
75
|
+
# TODO: Add CDF attributes to yaml once they're defined for L2 science data
|
|
76
|
+
# consider moving attribute handling to hit_utils.py
|
|
77
|
+
# Assign attributes and dimensions to each data array in the Dataset
|
|
78
|
+
for field in dataset.data_vars.keys():
|
|
79
|
+
try:
|
|
80
|
+
# Create a dict of dimensions using the DEPEND_I keys in the
|
|
81
|
+
# attributes
|
|
82
|
+
dims = {
|
|
83
|
+
key: value
|
|
84
|
+
for key, value in attr_mgr.get_variable_attributes(field).items()
|
|
85
|
+
if "DEPEND" in key
|
|
86
|
+
}
|
|
87
|
+
dataset[field].attrs = attr_mgr.get_variable_attributes(field)
|
|
88
|
+
dataset[field].assign_coords(dims)
|
|
89
|
+
except KeyError:
|
|
90
|
+
# TODO: consider raising an error after L2 attributes are defined.
|
|
91
|
+
# Until then, continue with processing and log warning
|
|
92
|
+
logger.warning(f"Field {field} not found in attribute manager.")
|
|
93
|
+
|
|
94
|
+
# Skip schema check for epoch to prevent attr_mgr from adding the
|
|
95
|
+
# DEPEND_0 attribute which isn't required for epoch
|
|
96
|
+
dataset.epoch.attrs = attr_mgr.get_variable_attributes(
|
|
97
|
+
"epoch", check_schema=False
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
logger.info(f"HIT L2 dataset created for {logical_source}")
|
|
101
|
+
|
|
102
|
+
return list(l2_datasets.values())
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class IntensityFactors(NamedTuple):
|
|
106
|
+
"""A namedtuple to store factors for the intensity equation."""
|
|
107
|
+
|
|
108
|
+
delta_e_factor: np.ndarray
|
|
109
|
+
geometry_factor: np.ndarray
|
|
110
|
+
efficiency: np.ndarray
|
|
111
|
+
b: np.ndarray
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_intensity_factors(
|
|
115
|
+
energy_min: np.ndarray, species_ancillary_data: pd.DataFrame
|
|
116
|
+
) -> IntensityFactors:
|
|
117
|
+
"""
|
|
118
|
+
Get the intensity factors for all energy bins of the given species ancillary data.
|
|
119
|
+
|
|
120
|
+
This function gets the factors needed for the equation to convert rates to
|
|
121
|
+
intensities for all energy bins for the given species.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
energy_min : np.ndarray
|
|
126
|
+
All energy min values for the species.
|
|
127
|
+
species_ancillary_data : pd.DataFrame
|
|
128
|
+
The subset of ancillary data for the given species.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
IntensityFactors
|
|
133
|
+
The factors needed to convert rates to intensities for all energy bins
|
|
134
|
+
for the given species.
|
|
135
|
+
"""
|
|
136
|
+
# Get factors needed to convert rates to intensities for
|
|
137
|
+
# all energy bins for the given species ancillary data
|
|
138
|
+
intensity_factors = species_ancillary_data.set_index(
|
|
139
|
+
species_ancillary_data["lower energy (mev)"].astype(np.float32)
|
|
140
|
+
).loc[energy_min]
|
|
141
|
+
|
|
142
|
+
return IntensityFactors(
|
|
143
|
+
delta_e_factor=intensity_factors["delta e (mev)"].values,
|
|
144
|
+
geometry_factor=intensity_factors["geometry factor (cm2 sr)"].values,
|
|
145
|
+
efficiency=intensity_factors["efficiency"].values,
|
|
146
|
+
b=intensity_factors["b"].values,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def calculate_intensities(
|
|
151
|
+
rate: xr.DataArray,
|
|
152
|
+
delta_e_factor: np.ndarray,
|
|
153
|
+
geometry_factor: np.ndarray,
|
|
154
|
+
efficiency: np.ndarray,
|
|
155
|
+
b: np.ndarray,
|
|
156
|
+
) -> xr.DataArray:
|
|
157
|
+
"""
|
|
158
|
+
Calculate the intensities for given arrays of rates and ancillary factors.
|
|
159
|
+
|
|
160
|
+
Uses vectorization to calculate the intensities for an array of rates
|
|
161
|
+
at an epoch.
|
|
162
|
+
|
|
163
|
+
This function uses equation 9 and 11 from the HIT algorithm document:
|
|
164
|
+
(Summed L1B Rates) / (60 * Delta E * Geometry Factor * Efficiency) - b
|
|
165
|
+
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
rate : xr.DataArray
|
|
169
|
+
The L1B rates to be converted to intensities for an epoch.
|
|
170
|
+
delta_e_factor : np.ndarray
|
|
171
|
+
The energy bin width factors for an epoch.
|
|
172
|
+
geometry_factor : np.ndarray
|
|
173
|
+
The geometry factors for an epoch.
|
|
174
|
+
efficiency : np.ndarray
|
|
175
|
+
The efficiency factors for an epoch.
|
|
176
|
+
b : np.ndarray
|
|
177
|
+
The b factors for an epoch.
|
|
178
|
+
|
|
179
|
+
Returns
|
|
180
|
+
-------
|
|
181
|
+
xr.DataArray
|
|
182
|
+
The calculated intensities for an epoch.
|
|
183
|
+
"""
|
|
184
|
+
# Calculate the intensities for this energy bin using vectorization
|
|
185
|
+
return (rate / (60 * delta_e_factor * geometry_factor * efficiency)) - b
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def calculate_intensities_for_a_species(
|
|
189
|
+
species_variable: str, l2_dataset: xr.Dataset, ancillary_data_frames: dict
|
|
190
|
+
) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Calculate the intensity for a given species in the dataset.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
species_variable : str
|
|
197
|
+
The species variable to calculate the intensity for which is either the species
|
|
198
|
+
or a statistical uncertainty. (i.e. "h", "h_delta_minus", or "h_delta_plus").
|
|
199
|
+
l2_dataset : xr.Dataset
|
|
200
|
+
The L2 dataset containing the summed L1B rates to calculate the intensity.
|
|
201
|
+
ancillary_data_frames : dict
|
|
202
|
+
Dictionary containing ancillary data for each dynamic threshold state where
|
|
203
|
+
the key is the dynamic threshold state and the value is a pandas DataFrame
|
|
204
|
+
containing the ancillary data.
|
|
205
|
+
"""
|
|
206
|
+
species = (
|
|
207
|
+
species_variable.split("_")[0]
|
|
208
|
+
if "_delta_" in species_variable
|
|
209
|
+
else species_variable
|
|
210
|
+
)
|
|
211
|
+
energy_min = (
|
|
212
|
+
l2_dataset[f"{species}_energy_mean"].values
|
|
213
|
+
- l2_dataset[f"{species}_energy_delta_minus"].values
|
|
214
|
+
)
|
|
215
|
+
# TODO: Add check for energy max after ancillary file is updated
|
|
216
|
+
# to fix errors
|
|
217
|
+
|
|
218
|
+
# Calculate the intensity for each epoch and energy bin since the
|
|
219
|
+
# dynamic threshold state can vary by epoch and that determines the
|
|
220
|
+
# ancillary data to use.
|
|
221
|
+
for epoch in range(l2_dataset[species_variable].shape[0]):
|
|
222
|
+
# Get ancillary data using the dynamic threshold state for this epoch
|
|
223
|
+
species_ancillary_data = get_species_ancillary_data(
|
|
224
|
+
int(l2_dataset["dynamic_threshold_state"][epoch].values),
|
|
225
|
+
ancillary_data_frames,
|
|
226
|
+
species,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Calculate the intensity for this energy bin using vectorization
|
|
230
|
+
# and replace rates with intensities in the dataset
|
|
231
|
+
factors: IntensityFactors = get_intensity_factors(
|
|
232
|
+
energy_min, species_ancillary_data
|
|
233
|
+
)
|
|
234
|
+
rates: xr.DataArray = l2_dataset[species_variable][epoch]
|
|
235
|
+
|
|
236
|
+
l2_dataset[species_variable][epoch] = calculate_intensities(
|
|
237
|
+
rates,
|
|
238
|
+
factors.delta_e_factor,
|
|
239
|
+
factors.geometry_factor,
|
|
240
|
+
factors.efficiency,
|
|
241
|
+
factors.b,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def calculate_intensities_for_all_species(
|
|
246
|
+
l2_dataset: xr.Dataset, ancillary_data_frames: dict
|
|
247
|
+
) -> None:
|
|
248
|
+
"""
|
|
249
|
+
Calculate the intensity for each species in the dataset.
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
l2_dataset : xr.Dataset
|
|
254
|
+
The L2 dataset.
|
|
255
|
+
ancillary_data_frames : dict
|
|
256
|
+
Dictionary containing ancillary data for each dynamic threshold state
|
|
257
|
+
where the key is the dynamic threshold state and the value is a pandas
|
|
258
|
+
DataFrame containing the ancillary data.
|
|
259
|
+
"""
|
|
260
|
+
# TODO: update to also calculate intensity for sectorates?
|
|
261
|
+
# List of valid species data variables to calculate intensity for
|
|
262
|
+
valid_data_variables = [
|
|
263
|
+
"h",
|
|
264
|
+
"he3",
|
|
265
|
+
"he4",
|
|
266
|
+
"he",
|
|
267
|
+
"c",
|
|
268
|
+
"n",
|
|
269
|
+
"o",
|
|
270
|
+
"ne",
|
|
271
|
+
"na",
|
|
272
|
+
"mg",
|
|
273
|
+
"al",
|
|
274
|
+
"si",
|
|
275
|
+
"s",
|
|
276
|
+
"ar",
|
|
277
|
+
"ca",
|
|
278
|
+
"fe",
|
|
279
|
+
"ni",
|
|
280
|
+
]
|
|
281
|
+
|
|
282
|
+
# Add statistical uncertainty variables to the list of valid variables
|
|
283
|
+
valid_data_variables += [f"{var}_delta_minus" for var in valid_data_variables] + [
|
|
284
|
+
f"{var}_delta_plus" for var in valid_data_variables
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
# Calculate the intensity for each valid data variable
|
|
288
|
+
for species_variable in valid_data_variables:
|
|
289
|
+
if species_variable in l2_dataset.data_vars:
|
|
290
|
+
calculate_intensities_for_a_species(
|
|
291
|
+
species_variable, l2_dataset, ancillary_data_frames
|
|
292
|
+
)
|
|
293
|
+
else:
|
|
294
|
+
logger.warning(
|
|
295
|
+
f"Variable {species_variable} not found in dataset. "
|
|
296
|
+
f"Skipping intensity calculation."
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def add_systematic_uncertainties(
|
|
301
|
+
dataset: xr.Dataset, particle: str, energy_bins: int
|
|
302
|
+
) -> None:
|
|
303
|
+
"""
|
|
304
|
+
Add systematic uncertainties to the dataset.
|
|
305
|
+
|
|
306
|
+
Add systematic uncertainties to the dataset. Just zeros for now.
|
|
307
|
+
To change if/when HIT determines there are systematic uncertainties.
|
|
308
|
+
|
|
309
|
+
Parameters
|
|
310
|
+
----------
|
|
311
|
+
dataset : xr.Dataset
|
|
312
|
+
The dataset to add the systematic uncertainties to.
|
|
313
|
+
particle : str
|
|
314
|
+
The particle name.
|
|
315
|
+
energy_bins : int
|
|
316
|
+
Number of energy bins for the particle.
|
|
317
|
+
"""
|
|
318
|
+
dataset[f"{particle}_sys_delta_minus"] = xr.DataArray(
|
|
319
|
+
data=np.zeros(energy_bins, dtype=np.float32),
|
|
320
|
+
dims=[f"{particle}_energy_mean"],
|
|
321
|
+
name=f"{particle}_sys_delta_minus",
|
|
322
|
+
)
|
|
323
|
+
dataset[f"{particle}_sys_delta_plus"] = xr.DataArray(
|
|
324
|
+
data=np.zeros(energy_bins, dtype=np.float32),
|
|
325
|
+
dims=[f"{particle}_energy_mean"],
|
|
326
|
+
name=f"{particle}_sys_delta_plus",
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def add_standard_particle_rates_to_dataset(
|
|
331
|
+
l2_standard_intensity_dataset: xr.Dataset,
|
|
332
|
+
l1b_standard_rates_dataset: xr.Dataset,
|
|
333
|
+
particle: str,
|
|
334
|
+
energy_ranges: list,
|
|
335
|
+
) -> None:
|
|
336
|
+
"""
|
|
337
|
+
Add summed standard particle rates to the dataset.
|
|
338
|
+
|
|
339
|
+
This function performs the following steps:
|
|
340
|
+
1) sum the standard rates, including statistical uncertainties,
|
|
341
|
+
from the l2fgrates, l3fgrates, and penfgrates data variables in the L1B
|
|
342
|
+
standard rates data.
|
|
343
|
+
2) add the summed rates to the L2 standard intensity dataset by particle type
|
|
344
|
+
and energy range.
|
|
345
|
+
|
|
346
|
+
Parameters
|
|
347
|
+
----------
|
|
348
|
+
l2_standard_intensity_dataset : xr.Dataset
|
|
349
|
+
The L2 standard intensity dataset to add the rates to.
|
|
350
|
+
l1b_standard_rates_dataset : xr.Dataset
|
|
351
|
+
The L1B standard rates dataset containing rates to sum.
|
|
352
|
+
particle : str
|
|
353
|
+
The particle name.
|
|
354
|
+
energy_ranges : list
|
|
355
|
+
A list of energy range dictionaries for the particle.
|
|
356
|
+
For example:
|
|
357
|
+
{'energy_min': 1.8, 'energy_max': 2.2, "R2": [1], "R3": [], "R4": []}.
|
|
358
|
+
"""
|
|
359
|
+
# Initialize arrays to store summed rates and statistical uncertainties
|
|
360
|
+
l2_standard_intensity_dataset = initialize_particle_data_arrays(
|
|
361
|
+
l2_standard_intensity_dataset,
|
|
362
|
+
particle,
|
|
363
|
+
len(energy_ranges),
|
|
364
|
+
l1b_standard_rates_dataset.sizes["epoch"],
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# initialize arrays to store energy min and max values
|
|
368
|
+
energy_min = np.zeros(len(energy_ranges), dtype=np.float32)
|
|
369
|
+
energy_max = np.zeros(len(energy_ranges), dtype=np.float32)
|
|
370
|
+
|
|
371
|
+
# Sum particle rates and statistical uncertainties for each energy range
|
|
372
|
+
# and add them to the dataset
|
|
373
|
+
for i, energy_range_dict in enumerate(energy_ranges):
|
|
374
|
+
summed_rates, summed_rates_delta_minus, summed_rates_delta_plus = (
|
|
375
|
+
sum_particle_data(l1b_standard_rates_dataset, energy_range_dict)
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
l2_standard_intensity_dataset[f"{particle}"][:, i] = summed_rates.astype(
|
|
379
|
+
np.float32
|
|
380
|
+
)
|
|
381
|
+
l2_standard_intensity_dataset[f"{particle}_delta_minus"][:, i] = (
|
|
382
|
+
summed_rates_delta_minus.astype(np.float32)
|
|
383
|
+
)
|
|
384
|
+
l2_standard_intensity_dataset[f"{particle}_delta_plus"][:, i] = (
|
|
385
|
+
summed_rates_delta_plus.astype(np.float32)
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# Fill energy min and max values for each energy range
|
|
389
|
+
energy_min[i] = energy_range_dict["energy_min"]
|
|
390
|
+
energy_max[i] = energy_range_dict["energy_max"]
|
|
391
|
+
|
|
392
|
+
l2_standard_intensity_dataset = add_energy_variables(
|
|
393
|
+
l2_standard_intensity_dataset, particle, energy_min, energy_max
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def get_species_ancillary_data(
|
|
398
|
+
dynamic_threshold_state: int, ancillary_data_frames: dict, species: str
|
|
399
|
+
) -> pd.DataFrame:
|
|
400
|
+
"""
|
|
401
|
+
Get the ancillary data for a given species and dynamic threshold state.
|
|
402
|
+
|
|
403
|
+
Parameters
|
|
404
|
+
----------
|
|
405
|
+
dynamic_threshold_state : int
|
|
406
|
+
The dynamic threshold state for the ancillary data (0-3).
|
|
407
|
+
ancillary_data_frames : dict
|
|
408
|
+
Dictionary containing ancillary data for each dynamic threshold state
|
|
409
|
+
where the key is the dynamic threshold state and the value is a pandas
|
|
410
|
+
DataFrame containing the ancillary data.
|
|
411
|
+
species : str
|
|
412
|
+
The species to get the ancillary data for.
|
|
413
|
+
|
|
414
|
+
Returns
|
|
415
|
+
-------
|
|
416
|
+
pd.DataFrame
|
|
417
|
+
The ancillary data for the species and dynamic threshold state.
|
|
418
|
+
"""
|
|
419
|
+
ancillary_data = ancillary_data_frames[dynamic_threshold_state]
|
|
420
|
+
|
|
421
|
+
# Get the ancillary data for the species
|
|
422
|
+
species_ancillary_data = ancillary_data[ancillary_data["species"] == species]
|
|
423
|
+
return species_ancillary_data
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def load_ancillary_data(dynamic_threshold_states: set, path_prefix: Path) -> dict:
|
|
427
|
+
"""
|
|
428
|
+
Load ancillary data based on the dynamic threshold state.
|
|
429
|
+
|
|
430
|
+
The dynamic threshold state (0-3) determines which ancillary file to use.
|
|
431
|
+
This function returns a dictionary with ancillary data for each state in
|
|
432
|
+
the dataset.
|
|
433
|
+
|
|
434
|
+
Parameters
|
|
435
|
+
----------
|
|
436
|
+
dynamic_threshold_states : set
|
|
437
|
+
A set of dynamic threshold states in the L2 dataset.
|
|
438
|
+
path_prefix : Path
|
|
439
|
+
The path prefix for ancillary data files.
|
|
440
|
+
|
|
441
|
+
Returns
|
|
442
|
+
-------
|
|
443
|
+
dict
|
|
444
|
+
A dictionary with ancillary data for each dynamic threshold state.
|
|
445
|
+
"""
|
|
446
|
+
# Load ancillary data
|
|
447
|
+
ancillary_data_frames = {
|
|
448
|
+
int(state): pd.read_csv(f"{path_prefix}{state}-factors_20250219_v002.csv")
|
|
449
|
+
for state in dynamic_threshold_states
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
# Convert column names and species values to lowercase
|
|
453
|
+
for df in ancillary_data_frames.values():
|
|
454
|
+
df.columns = df.columns.str.lower().str.strip()
|
|
455
|
+
df["species"] = df["species"].str.lower()
|
|
456
|
+
|
|
457
|
+
return ancillary_data_frames
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def process_summed_intensity_data(l1b_summed_rates_dataset: xr.Dataset) -> xr.Dataset:
|
|
461
|
+
"""
|
|
462
|
+
Will process L2 HIT summed intensity data from L1B summed rates.
|
|
463
|
+
|
|
464
|
+
This function converts the L1B summed rates to L2 summed intensities
|
|
465
|
+
using ancillary tables containing factors needed to calculate the
|
|
466
|
+
intensity (energy bin width, geometry factor, efficiency, and b).
|
|
467
|
+
|
|
468
|
+
Equation 12 from the HIT algorithm document:
|
|
469
|
+
Summed Intensity = (L1B Summed Rate) /
|
|
470
|
+
(60 * Delta E * Geometry Factor * Efficiency) - b
|
|
471
|
+
|
|
472
|
+
Parameters
|
|
473
|
+
----------
|
|
474
|
+
l1b_summed_rates_dataset : xarray.Dataset
|
|
475
|
+
HIT L1B summed rates dataset.
|
|
476
|
+
|
|
477
|
+
Returns
|
|
478
|
+
-------
|
|
479
|
+
xr.Dataset
|
|
480
|
+
The processed L2 summed intensity dataset.
|
|
481
|
+
"""
|
|
482
|
+
# Create a new dataset to store the L2 summed intensity data
|
|
483
|
+
l2_summed_intensity_dataset = l1b_summed_rates_dataset.copy(deep=True)
|
|
484
|
+
|
|
485
|
+
# Load ancillary data for each dynamic threshold state into a dictionary
|
|
486
|
+
ancillary_data_frames = load_ancillary_data(
|
|
487
|
+
set(l2_summed_intensity_dataset["dynamic_threshold_state"].values),
|
|
488
|
+
L2_SUMMED_ANCILLARY_PATH_PREFIX,
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
# Add systematic uncertainties and energy variables to the dataset
|
|
492
|
+
for var in l2_summed_intensity_dataset.data_vars:
|
|
493
|
+
if "_" not in var:
|
|
494
|
+
particle = str(var)
|
|
495
|
+
# Add systematic uncertainties to the dataset. These will not have the
|
|
496
|
+
# intensity calculation applied to them and values will be zeros
|
|
497
|
+
add_systematic_uncertainties(
|
|
498
|
+
l2_summed_intensity_dataset,
|
|
499
|
+
particle,
|
|
500
|
+
l2_summed_intensity_dataset[var].shape[1],
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
# TODO: remove this code after L1B is updated to have energy mean and deltas
|
|
504
|
+
# instead of energy index, min, and max
|
|
505
|
+
# Add energy variables to the dataset (energy mean and deltas)
|
|
506
|
+
l2_summed_intensity_dataset = add_energy_variables(
|
|
507
|
+
l2_summed_intensity_dataset,
|
|
508
|
+
particle,
|
|
509
|
+
l2_summed_intensity_dataset[f"{particle}_energy_min"].values,
|
|
510
|
+
l2_summed_intensity_dataset[f"{particle}_energy_max"].values,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Replace energy index with energy mean as a coordinate
|
|
514
|
+
l2_summed_intensity_dataset = l2_summed_intensity_dataset.assign_coords(
|
|
515
|
+
{
|
|
516
|
+
f"{particle}_energy_mean": (
|
|
517
|
+
f"{particle}_energy_index",
|
|
518
|
+
l2_summed_intensity_dataset[f"{particle}_energy_mean"].values,
|
|
519
|
+
)
|
|
520
|
+
}
|
|
521
|
+
).swap_dims({f"{particle}_energy_index": f"{particle}_energy_mean"})
|
|
522
|
+
|
|
523
|
+
# Drop energy min, max, and index variables
|
|
524
|
+
l2_summed_intensity_dataset = l2_summed_intensity_dataset.drop_vars(
|
|
525
|
+
[
|
|
526
|
+
f"{particle}_energy_min",
|
|
527
|
+
f"{particle}_energy_max",
|
|
528
|
+
f"{particle}_energy_index",
|
|
529
|
+
]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
calculate_intensities_for_all_species(
|
|
533
|
+
l2_summed_intensity_dataset, ancillary_data_frames
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
return l2_summed_intensity_dataset
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def process_standard_intensity_data(
|
|
540
|
+
l1b_standard_rates_dataset: xr.Dataset,
|
|
541
|
+
) -> xr.Dataset:
|
|
542
|
+
"""
|
|
543
|
+
Will process L2 standard intensity data from L1B standard rates data.
|
|
544
|
+
|
|
545
|
+
This function converts L1B standard rates to L2 standard intensities for each
|
|
546
|
+
particle type and energy range using ancillary tables containing factors
|
|
547
|
+
needed to calculate the intensity (energy bin width, geometry factor, efficiency
|
|
548
|
+
and b).
|
|
549
|
+
|
|
550
|
+
First, rates from the l2fgrates, l3fgrates, and penfgrates data variables
|
|
551
|
+
in the L1B standard rates data are summed. These variables represent rates
|
|
552
|
+
for different detector penetration ranges (Range 2, Range 3, and Range 4
|
|
553
|
+
respectively). Only the energy ranges specified in the
|
|
554
|
+
STANDARD_PARTICLE_ENERGY_RANGE_MAPPING dictionary are included in this
|
|
555
|
+
product.
|
|
556
|
+
|
|
557
|
+
Intensity is then calculated from the summed rates using the following equation:
|
|
558
|
+
|
|
559
|
+
Equation 10 from the HIT algorithm document:
|
|
560
|
+
Standard Intensity = (Summed L1B Standard Rates) /
|
|
561
|
+
(60 * Delta E * Geometry Factor * Efficiency) - b
|
|
562
|
+
|
|
563
|
+
Parameters
|
|
564
|
+
----------
|
|
565
|
+
l1b_standard_rates_dataset : xr.Dataset
|
|
566
|
+
The L1B standard rates dataset.
|
|
567
|
+
|
|
568
|
+
Returns
|
|
569
|
+
-------
|
|
570
|
+
xr.Dataset
|
|
571
|
+
The L2 standard intensity dataset.
|
|
572
|
+
"""
|
|
573
|
+
# Create a new dataset to store the L2 standard intensity data
|
|
574
|
+
l2_standard_intensity_dataset = xr.Dataset()
|
|
575
|
+
|
|
576
|
+
# Assign the epoch coordinate from the l1B dataset
|
|
577
|
+
l2_standard_intensity_dataset = l2_standard_intensity_dataset.assign_coords(
|
|
578
|
+
{"epoch": l1b_standard_rates_dataset.coords["epoch"]}
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
# Add dynamic threshold state to the dataset
|
|
582
|
+
l2_standard_intensity_dataset["dynamic_threshold_state"] = (
|
|
583
|
+
l1b_standard_rates_dataset["dynamic_threshold_state"]
|
|
584
|
+
)
|
|
585
|
+
l2_standard_intensity_dataset[
|
|
586
|
+
"dynamic_threshold_state"
|
|
587
|
+
].attrs = l1b_standard_rates_dataset["dynamic_threshold_state"].attrs
|
|
588
|
+
|
|
589
|
+
# Load ancillary data for each dynamic threshold state into a dictionary
|
|
590
|
+
ancillary_data_frames = load_ancillary_data(
|
|
591
|
+
set(l2_standard_intensity_dataset["dynamic_threshold_state"].values),
|
|
592
|
+
L2_STANDARD_ANCILLARY_PATH_PREFIX,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
# Process each particle type and energy range and add rates and uncertainties
|
|
596
|
+
# to the dataset
|
|
597
|
+
for particle, energy_ranges in STANDARD_PARTICLE_ENERGY_RANGE_MAPPING.items():
|
|
598
|
+
# Add systematic uncertainties to the dataset. These will not have the intensity
|
|
599
|
+
# calculation applied to them and values will be zeros
|
|
600
|
+
add_systematic_uncertainties(
|
|
601
|
+
l2_standard_intensity_dataset, particle, len(energy_ranges)
|
|
602
|
+
)
|
|
603
|
+
# Add standard particle rates and statistical uncertainties to the dataset
|
|
604
|
+
add_standard_particle_rates_to_dataset(
|
|
605
|
+
l2_standard_intensity_dataset,
|
|
606
|
+
l1b_standard_rates_dataset,
|
|
607
|
+
particle,
|
|
608
|
+
energy_ranges,
|
|
609
|
+
)
|
|
610
|
+
calculate_intensities_for_all_species(
|
|
611
|
+
l2_standard_intensity_dataset, ancillary_data_frames
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
return l2_standard_intensity_dataset
|