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
imap_processing/hit/l2/hit_l2.py
CHANGED
|
@@ -2,22 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import NamedTuple
|
|
6
5
|
|
|
7
6
|
import numpy as np
|
|
8
7
|
import pandas as pd
|
|
9
8
|
import xarray as xr
|
|
10
9
|
|
|
11
10
|
from imap_processing.hit.hit_utils import (
|
|
12
|
-
|
|
11
|
+
add_summed_particle_data_to_dataset,
|
|
13
12
|
get_attribute_manager,
|
|
14
|
-
initialize_particle_data_arrays,
|
|
15
|
-
sum_particle_data,
|
|
16
13
|
)
|
|
17
14
|
from imap_processing.hit.l2.constants import (
|
|
15
|
+
FILLVAL_FLOAT32,
|
|
16
|
+
L2_SECTORED_ANCILLARY_PATH_PREFIX,
|
|
18
17
|
L2_STANDARD_ANCILLARY_PATH_PREFIX,
|
|
19
18
|
L2_SUMMED_ANCILLARY_PATH_PREFIX,
|
|
19
|
+
N_AZIMUTH,
|
|
20
|
+
SECONDS_PER_10_MIN,
|
|
21
|
+
SECONDS_PER_MIN,
|
|
20
22
|
STANDARD_PARTICLE_ENERGY_RANGE_MAPPING,
|
|
23
|
+
VALID_SECTORED_SPECIES,
|
|
24
|
+
VALID_SPECIES,
|
|
21
25
|
)
|
|
22
26
|
|
|
23
27
|
logger = logging.getLogger(__name__)
|
|
@@ -27,7 +31,7 @@ logger = logging.getLogger(__name__)
|
|
|
27
31
|
# - determine where to pull ancillary data. Storing it locally for now
|
|
28
32
|
|
|
29
33
|
|
|
30
|
-
def hit_l2(dependency: xr.Dataset
|
|
34
|
+
def hit_l2(dependency: xr.Dataset) -> list[xr.Dataset]:
|
|
31
35
|
"""
|
|
32
36
|
Will process HIT data to L2.
|
|
33
37
|
|
|
@@ -38,8 +42,6 @@ def hit_l2(dependency: xr.Dataset, data_version: str) -> list[xr.Dataset]:
|
|
|
38
42
|
dependency : xr.Dataset
|
|
39
43
|
L1B xarray science dataset that is either summed rates
|
|
40
44
|
standard rates or sector rates.
|
|
41
|
-
data_version : str
|
|
42
|
-
Version of the data product being created.
|
|
43
45
|
|
|
44
46
|
Returns
|
|
45
47
|
-------
|
|
@@ -47,11 +49,9 @@ def hit_l2(dependency: xr.Dataset, data_version: str) -> list[xr.Dataset]:
|
|
|
47
49
|
List of one L2 dataset.
|
|
48
50
|
"""
|
|
49
51
|
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
52
|
|
|
53
|
-
#
|
|
54
|
-
|
|
53
|
+
# Create the attribute manager for this data level
|
|
54
|
+
attr_mgr = get_attribute_manager("l2")
|
|
55
55
|
|
|
56
56
|
l2_datasets: dict = {}
|
|
57
57
|
|
|
@@ -68,6 +68,12 @@ def hit_l2(dependency: xr.Dataset, data_version: str) -> list[xr.Dataset]:
|
|
|
68
68
|
)
|
|
69
69
|
logger.info("HIT L2 standard intensity dataset created")
|
|
70
70
|
|
|
71
|
+
if "imap_hit_l1b_sectored-rates" in dependency.attrs["Logical_source"]:
|
|
72
|
+
l2_datasets["imap_hit_l2_macropixel-intensity"] = (
|
|
73
|
+
process_sectored_intensity_data(dependency)
|
|
74
|
+
)
|
|
75
|
+
logger.info("HIT L2 macropixel intensity dataset created")
|
|
76
|
+
|
|
71
77
|
# Update attributes and dimensions
|
|
72
78
|
for logical_source, dataset in l2_datasets.items():
|
|
73
79
|
dataset.attrs = attr_mgr.get_global_attributes(logical_source)
|
|
@@ -102,149 +108,241 @@ def hit_l2(dependency: xr.Dataset, data_version: str) -> list[xr.Dataset]:
|
|
|
102
108
|
return list(l2_datasets.values())
|
|
103
109
|
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
def calculate_intensities(
|
|
112
|
+
rates: xr.DataArray,
|
|
113
|
+
factors: xr.Dataset,
|
|
114
|
+
) -> xr.DataArray:
|
|
115
|
+
"""
|
|
116
|
+
Calculate the intensities for given rates and equation factors.
|
|
117
|
+
|
|
118
|
+
Uses vectorization to calculate the intensities for an array of rates
|
|
119
|
+
for all epochs.
|
|
120
|
+
|
|
121
|
+
This function uses equation 9 and 12 from the HIT algorithm document:
|
|
122
|
+
((Summed L1B Rates) / (Delta Time * Delta E * Geometry Factor * Efficiency)) - b
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
rates : xr.DataArray
|
|
127
|
+
The L1B rates to be converted to intensities.
|
|
128
|
+
factors : xr.Dataset
|
|
129
|
+
The ancillary data factors needed to calculate the intensity.
|
|
130
|
+
This includes delta_e, geometry_factor, efficiency, and b.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
xr.DataArray
|
|
135
|
+
The calculated intensities for all epochs.
|
|
136
|
+
"""
|
|
137
|
+
# Calculate the intensity using vectorized operations
|
|
138
|
+
intensity = (
|
|
139
|
+
rates
|
|
140
|
+
/ (
|
|
141
|
+
factors.delta_time
|
|
142
|
+
* factors.delta_e
|
|
143
|
+
* factors.geometry_factor
|
|
144
|
+
* factors.efficiency
|
|
145
|
+
)
|
|
146
|
+
) - factors.b
|
|
147
|
+
|
|
148
|
+
# Apply intensity where rates are not equal to the fill value
|
|
149
|
+
intensity = xr.where(rates == FILLVAL_FLOAT32, FILLVAL_FLOAT32, intensity)
|
|
107
150
|
|
|
108
|
-
|
|
109
|
-
geometry_factor: np.ndarray
|
|
110
|
-
efficiency: np.ndarray
|
|
111
|
-
b: np.ndarray
|
|
151
|
+
return intensity
|
|
112
152
|
|
|
113
153
|
|
|
114
|
-
def
|
|
115
|
-
energy_min: np.ndarray, species_ancillary_data: pd.DataFrame
|
|
116
|
-
) -> IntensityFactors:
|
|
154
|
+
def reshape_for_sectored(arr: np.ndarray) -> np.ndarray:
|
|
117
155
|
"""
|
|
118
|
-
|
|
156
|
+
Reshape the ancillary data for sectored rates.
|
|
119
157
|
|
|
120
|
-
|
|
121
|
-
|
|
158
|
+
Reshape the 3D arrays (epoch, energy, declination) to 4D arrays
|
|
159
|
+
(epoch, energy, azimuth, declination) by repeating the data
|
|
160
|
+
along the azimuth dimension. This is done to match the dimensions
|
|
161
|
+
of the sectored rates data to allow for proper calculation of
|
|
162
|
+
intensities.
|
|
122
163
|
|
|
123
164
|
Parameters
|
|
124
165
|
----------
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
species_ancillary_data : pd.DataFrame
|
|
128
|
-
The subset of ancillary data for the given species.
|
|
166
|
+
arr : np.ndarray
|
|
167
|
+
The ancillary data array to reshape.
|
|
129
168
|
|
|
130
169
|
Returns
|
|
131
170
|
-------
|
|
132
|
-
|
|
133
|
-
The
|
|
134
|
-
for the given species.
|
|
171
|
+
np.ndarray
|
|
172
|
+
The reshaped array.
|
|
135
173
|
"""
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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,
|
|
174
|
+
return np.repeat(
|
|
175
|
+
arr.reshape((arr.shape[0], arr.shape[1], arr.shape[2]))[:, :, np.newaxis, :],
|
|
176
|
+
N_AZIMUTH,
|
|
177
|
+
axis=2,
|
|
147
178
|
)
|
|
148
179
|
|
|
149
180
|
|
|
150
|
-
def
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
efficiency: np.ndarray,
|
|
181
|
+
def build_ancillary_dataset(
|
|
182
|
+
delta_e: np.ndarray,
|
|
183
|
+
geometry_factors: np.ndarray,
|
|
184
|
+
efficiencies: np.ndarray,
|
|
155
185
|
b: np.ndarray,
|
|
156
|
-
|
|
186
|
+
species_array: xr.DataArray,
|
|
187
|
+
) -> xr.Dataset:
|
|
157
188
|
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
Uses vectorization to calculate the intensities for an array of rates
|
|
161
|
-
at an epoch.
|
|
189
|
+
Build a xarray Dataset containing ancillary data for calculating intensity.
|
|
162
190
|
|
|
163
|
-
|
|
164
|
-
|
|
191
|
+
This function builds a dataset containing the factors needed for calculating
|
|
192
|
+
intensity for a given species. The dataset is built based on the dimensions
|
|
193
|
+
and coordinates of the species data to align data along the epoch dimension.
|
|
165
194
|
|
|
166
195
|
Parameters
|
|
167
196
|
----------
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
efficiency : np.ndarray
|
|
175
|
-
The efficiency factors for an epoch.
|
|
197
|
+
delta_e : np.ndarray
|
|
198
|
+
Delta E values which are energy bin widths.
|
|
199
|
+
geometry_factors : np.ndarray
|
|
200
|
+
Geometry factor values.
|
|
201
|
+
efficiencies : np.ndarray
|
|
202
|
+
Efficiency values.
|
|
176
203
|
b : np.ndarray
|
|
177
|
-
|
|
204
|
+
Background intensity values.
|
|
205
|
+
species_array : xr.Dataset
|
|
206
|
+
Data array for the species to extract coordinates from.
|
|
178
207
|
|
|
179
208
|
Returns
|
|
180
209
|
-------
|
|
181
|
-
xr.
|
|
182
|
-
|
|
210
|
+
ancillary_ds : xr.Dataset
|
|
211
|
+
A dataset containing all ancillary data variables and coordinates that
|
|
212
|
+
align with the L2 dataset.
|
|
183
213
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
214
|
+
data_vars = {}
|
|
215
|
+
|
|
216
|
+
# Check if this is sectored data (i.e., has azimuth and declination dims)
|
|
217
|
+
is_sectored = (
|
|
218
|
+
"declination" in species_array.dims or "declination" in species_array.coords
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Build variables
|
|
222
|
+
data_vars["delta_e"] = (species_array.dims, delta_e)
|
|
223
|
+
data_vars["geometry_factor"] = (
|
|
224
|
+
species_array.dims,
|
|
225
|
+
geometry_factors,
|
|
226
|
+
)
|
|
227
|
+
data_vars["efficiency"] = (
|
|
228
|
+
species_array.dims,
|
|
229
|
+
efficiencies,
|
|
230
|
+
)
|
|
231
|
+
data_vars["b"] = (species_array.dims, b)
|
|
232
|
+
data_vars["delta_time"] = (
|
|
233
|
+
["epoch"],
|
|
234
|
+
np.full(
|
|
235
|
+
len(species_array.epoch),
|
|
236
|
+
SECONDS_PER_10_MIN if is_sectored else SECONDS_PER_MIN,
|
|
237
|
+
),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
return xr.Dataset(data_vars, coords=species_array.coords)
|
|
186
241
|
|
|
187
242
|
|
|
188
243
|
def calculate_intensities_for_a_species(
|
|
189
244
|
species_variable: str, l2_dataset: xr.Dataset, ancillary_data_frames: dict
|
|
190
|
-
) ->
|
|
245
|
+
) -> xr.Dataset:
|
|
191
246
|
"""
|
|
192
247
|
Calculate the intensity for a given species in the dataset.
|
|
193
248
|
|
|
249
|
+
This function orchestrates calculating the intensity for a given species
|
|
250
|
+
in the L2 dataset using ancillary data determined by the dynamic threshold
|
|
251
|
+
state (0-3).
|
|
252
|
+
|
|
253
|
+
The intensity is calculated using the equation:
|
|
254
|
+
(L1B Rates) / (Delta Time * Delta E * Geometry Factor * Efficiency) - b
|
|
255
|
+
|
|
256
|
+
where the equation factors are retrieved from the ancillary data for
|
|
257
|
+
the given species and dynamic threshold states.
|
|
258
|
+
|
|
194
259
|
Parameters
|
|
195
260
|
----------
|
|
196
261
|
species_variable : str
|
|
197
|
-
The species variable to calculate the intensity for which is either the species
|
|
198
|
-
or a statistical uncertainty.
|
|
262
|
+
The species variable to calculate the intensity for, which is either the species
|
|
263
|
+
or a statistical uncertainty.
|
|
264
|
+
(i.e. "h", "h_stat_uncert_minus", or "h_stat_uncert_plus").
|
|
199
265
|
l2_dataset : xr.Dataset
|
|
200
|
-
The L2 dataset containing the
|
|
266
|
+
The L2 dataset containing the L1B rates needed to calculate the intensity.
|
|
201
267
|
ancillary_data_frames : dict
|
|
202
268
|
Dictionary containing ancillary data for each dynamic threshold state where
|
|
203
269
|
the key is the dynamic threshold state and the value is a pandas DataFrame
|
|
204
|
-
containing the ancillary data.
|
|
270
|
+
containing the ancillary data for all species.
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
-------
|
|
274
|
+
updated_ds : xr.Dataset
|
|
275
|
+
The updated dataset with intensities calculated for the given species.
|
|
205
276
|
"""
|
|
206
|
-
|
|
277
|
+
updated_ds = l2_dataset.copy()
|
|
278
|
+
dynamic_threshold_states = updated_ds["dynamic_threshold_state"].values
|
|
279
|
+
unique_states = np.unique(dynamic_threshold_states)
|
|
280
|
+
species_name = (
|
|
207
281
|
species_variable.split("_")[0]
|
|
208
|
-
if "
|
|
282
|
+
if "_uncert_" in species_variable
|
|
209
283
|
else species_variable
|
|
210
284
|
)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
285
|
+
|
|
286
|
+
# Subset ancillary data for this species
|
|
287
|
+
species_ancillary_by_state = {
|
|
288
|
+
state: get_species_ancillary_data(state, ancillary_data_frames, species_name)
|
|
289
|
+
for state in unique_states
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
# Extract parameters - 3D arrays (num_states, energy bins, values)
|
|
293
|
+
delta_e = np.stack(
|
|
294
|
+
[
|
|
295
|
+
species_ancillary_by_state[state]["delta_e"]
|
|
296
|
+
for state in dynamic_threshold_states
|
|
297
|
+
]
|
|
298
|
+
)
|
|
299
|
+
geometry_factors = np.stack(
|
|
300
|
+
[
|
|
301
|
+
species_ancillary_by_state[state]["geometry_factor"]
|
|
302
|
+
for state in dynamic_threshold_states
|
|
303
|
+
]
|
|
304
|
+
)
|
|
305
|
+
efficiencies = np.stack(
|
|
306
|
+
[
|
|
307
|
+
species_ancillary_by_state[state]["efficiency"]
|
|
308
|
+
for state in dynamic_threshold_states
|
|
309
|
+
]
|
|
310
|
+
)
|
|
311
|
+
b = np.stack(
|
|
312
|
+
[species_ancillary_by_state[state]["b"] for state in dynamic_threshold_states]
|
|
214
313
|
)
|
|
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
314
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
)
|
|
315
|
+
# Reshape parameters for sectored rates to 4D arrays
|
|
316
|
+
if "declination" in updated_ds[species_variable].dims:
|
|
317
|
+
delta_e = reshape_for_sectored(delta_e)
|
|
318
|
+
geometry_factors = reshape_for_sectored(geometry_factors)
|
|
319
|
+
efficiencies = reshape_for_sectored(efficiencies)
|
|
320
|
+
b = reshape_for_sectored(b)
|
|
321
|
+
|
|
322
|
+
# Reshape parameters for summed and standard rates to 2D arrays
|
|
323
|
+
# by removing last dimension of size one, (n, n, 1)
|
|
324
|
+
else:
|
|
325
|
+
delta_e = np.squeeze(delta_e, axis=-1)
|
|
326
|
+
geometry_factors = np.squeeze(geometry_factors, axis=-1)
|
|
327
|
+
efficiencies = np.squeeze(efficiencies, axis=-1)
|
|
328
|
+
b = np.squeeze(b, axis=-1)
|
|
329
|
+
|
|
330
|
+
# Build ancillary xarray dataset
|
|
331
|
+
ancillary_ds = build_ancillary_dataset(
|
|
332
|
+
delta_e, geometry_factors, efficiencies, b, l2_dataset[species_name]
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Calculate intensities
|
|
336
|
+
updated_ds[species_variable] = calculate_intensities(
|
|
337
|
+
updated_ds[species_variable], ancillary_ds
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
return updated_ds
|
|
243
341
|
|
|
244
342
|
|
|
245
343
|
def calculate_intensities_for_all_species(
|
|
246
|
-
l2_dataset: xr.Dataset, ancillary_data_frames: dict
|
|
247
|
-
) ->
|
|
344
|
+
l2_dataset: xr.Dataset, ancillary_data_frames: dict, valid_data_variables: list
|
|
345
|
+
) -> xr.Dataset:
|
|
248
346
|
"""
|
|
249
347
|
Calculate the intensity for each species in the dataset.
|
|
250
348
|
|
|
@@ -256,39 +354,28 @@ def calculate_intensities_for_all_species(
|
|
|
256
354
|
Dictionary containing ancillary data for each dynamic threshold state
|
|
257
355
|
where the key is the dynamic threshold state and the value is a pandas
|
|
258
356
|
DataFrame containing the ancillary data.
|
|
357
|
+
valid_data_variables : list
|
|
358
|
+
A list of valid data variables to calculate intensity for.
|
|
359
|
+
|
|
360
|
+
Returns
|
|
361
|
+
-------
|
|
362
|
+
updated_ds : xr.Dataset
|
|
363
|
+
The updated dataset with the intensity calculated for each species.
|
|
259
364
|
"""
|
|
260
|
-
|
|
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
|
-
]
|
|
365
|
+
updated_ds = l2_dataset.copy()
|
|
281
366
|
|
|
282
367
|
# Add statistical uncertainty variables to the list of valid variables
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
368
|
+
data_variables = (
|
|
369
|
+
valid_data_variables
|
|
370
|
+
+ [f"{var}_stat_uncert_minus" for var in valid_data_variables]
|
|
371
|
+
+ [f"{var}_stat_uncert_plus" for var in valid_data_variables]
|
|
372
|
+
)
|
|
286
373
|
|
|
287
374
|
# Calculate the intensity for each valid data variable
|
|
288
|
-
for species_variable in
|
|
289
|
-
if species_variable in
|
|
290
|
-
calculate_intensities_for_a_species(
|
|
291
|
-
species_variable,
|
|
375
|
+
for species_variable in data_variables:
|
|
376
|
+
if species_variable in updated_ds.data_vars:
|
|
377
|
+
updated_ds = calculate_intensities_for_a_species(
|
|
378
|
+
species_variable, updated_ds, ancillary_data_frames
|
|
292
379
|
)
|
|
293
380
|
else:
|
|
294
381
|
logger.warning(
|
|
@@ -296,10 +383,10 @@ def calculate_intensities_for_all_species(
|
|
|
296
383
|
f"Skipping intensity calculation."
|
|
297
384
|
)
|
|
298
385
|
|
|
386
|
+
return updated_ds
|
|
299
387
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
) -> None:
|
|
388
|
+
|
|
389
|
+
def add_systematic_uncertainties(dataset: xr.Dataset, particle: str) -> xr.Dataset:
|
|
303
390
|
"""
|
|
304
391
|
Add systematic uncertainties to the dataset.
|
|
305
392
|
|
|
@@ -309,94 +396,83 @@ def add_systematic_uncertainties(
|
|
|
309
396
|
Parameters
|
|
310
397
|
----------
|
|
311
398
|
dataset : xr.Dataset
|
|
312
|
-
The dataset to add the systematic uncertainties to
|
|
399
|
+
The dataset to add the systematic uncertainties to
|
|
400
|
+
which contain the particle data variables.
|
|
313
401
|
particle : str
|
|
314
402
|
The particle name.
|
|
315
|
-
|
|
316
|
-
|
|
403
|
+
|
|
404
|
+
Returns
|
|
405
|
+
-------
|
|
406
|
+
updated_ds : xr.Dataset
|
|
407
|
+
The dataset with the systematic uncertainties added.
|
|
317
408
|
"""
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
409
|
+
updated_ds = dataset.copy()
|
|
410
|
+
|
|
411
|
+
updated_ds[f"{particle}_sys_err_minus"] = xr.DataArray(
|
|
412
|
+
data=np.zeros(updated_ds[particle].shape, dtype=np.float32),
|
|
413
|
+
dims=updated_ds[particle].dims,
|
|
414
|
+
name=f"{particle}_sys_err_minus",
|
|
322
415
|
)
|
|
323
|
-
|
|
324
|
-
data=np.zeros(
|
|
325
|
-
dims=[
|
|
326
|
-
name=f"{particle}
|
|
416
|
+
updated_ds[f"{particle}_sys_err_plus"] = xr.DataArray(
|
|
417
|
+
data=np.zeros(updated_ds[particle].shape, dtype=np.float32),
|
|
418
|
+
dims=updated_ds[particle].dims,
|
|
419
|
+
name=f"{particle}_sys_err_plus",
|
|
327
420
|
)
|
|
328
421
|
|
|
422
|
+
return updated_ds
|
|
329
423
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
l1b_standard_rates_dataset: xr.Dataset,
|
|
333
|
-
particle: str,
|
|
334
|
-
energy_ranges: list,
|
|
335
|
-
) -> None:
|
|
424
|
+
|
|
425
|
+
def add_total_uncertainties(dataset: xr.Dataset, particle: str) -> xr.Dataset:
|
|
336
426
|
"""
|
|
337
|
-
Add
|
|
427
|
+
Add total uncertainties to the dataset.
|
|
338
428
|
|
|
339
|
-
This function
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
and energy range.
|
|
429
|
+
This function calculates the total uncertainties for a given particle
|
|
430
|
+
by combining the statistical uncertainties and systematic uncertainties.
|
|
431
|
+
|
|
432
|
+
The total uncertainties are calculated as the square root of the sum
|
|
433
|
+
of the squares of the statistical and systematic uncertainties.
|
|
345
434
|
|
|
346
435
|
Parameters
|
|
347
436
|
----------
|
|
348
|
-
|
|
349
|
-
The
|
|
350
|
-
l1b_standard_rates_dataset : xr.Dataset
|
|
351
|
-
The L1B standard rates dataset containing rates to sum.
|
|
437
|
+
dataset : xr.Dataset
|
|
438
|
+
The dataset to add the total uncertainties to.
|
|
352
439
|
particle : str
|
|
353
440
|
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
441
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
)
|
|
442
|
+
Returns
|
|
443
|
+
-------
|
|
444
|
+
updated_ds : xr.Dataset
|
|
445
|
+
The dataset with the total uncertainties added.
|
|
446
|
+
"""
|
|
447
|
+
updated_ds = dataset.copy()
|
|
387
448
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
449
|
+
# Calculate the total uncertainties
|
|
450
|
+
total_minus = np.sqrt(
|
|
451
|
+
np.square(updated_ds[f"{particle}_stat_uncert_minus"])
|
|
452
|
+
+ np.square(updated_ds[f"{particle}_sys_err_minus"])
|
|
453
|
+
)
|
|
454
|
+
total_plus = np.sqrt(
|
|
455
|
+
np.square(updated_ds[f"{particle}_stat_uncert_plus"])
|
|
456
|
+
+ np.square(updated_ds[f"{particle}_sys_err_plus"])
|
|
457
|
+
)
|
|
391
458
|
|
|
392
|
-
|
|
393
|
-
|
|
459
|
+
updated_ds[f"{particle}_total_uncert_minus"] = xr.DataArray(
|
|
460
|
+
data=total_minus.astype(np.float32),
|
|
461
|
+
dims=updated_ds[particle].dims,
|
|
462
|
+
name=f"{particle}_total_uncert_minus",
|
|
394
463
|
)
|
|
464
|
+
updated_ds[f"{particle}_total_uncert_plus"] = xr.DataArray(
|
|
465
|
+
data=total_plus.astype(np.float32),
|
|
466
|
+
dims=updated_ds[particle].dims,
|
|
467
|
+
name=f"{particle}_total_uncert_plus",
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
return updated_ds
|
|
395
471
|
|
|
396
472
|
|
|
397
473
|
def get_species_ancillary_data(
|
|
398
474
|
dynamic_threshold_state: int, ancillary_data_frames: dict, species: str
|
|
399
|
-
) ->
|
|
475
|
+
) -> dict:
|
|
400
476
|
"""
|
|
401
477
|
Get the ancillary data for a given species and dynamic threshold state.
|
|
402
478
|
|
|
@@ -413,14 +489,25 @@ def get_species_ancillary_data(
|
|
|
413
489
|
|
|
414
490
|
Returns
|
|
415
491
|
-------
|
|
416
|
-
|
|
492
|
+
dict
|
|
417
493
|
The ancillary data for the species and dynamic threshold state.
|
|
418
494
|
"""
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
#
|
|
422
|
-
|
|
423
|
-
|
|
495
|
+
ancillary_df = ancillary_data_frames[dynamic_threshold_state]
|
|
496
|
+
|
|
497
|
+
# Remove any trailing spaces from all values in the DataFrame
|
|
498
|
+
ancillary_df = ancillary_df.map(lambda x: x.strip() if isinstance(x, str) else x)
|
|
499
|
+
|
|
500
|
+
# Get the ancillary data for the species and group by lower energy
|
|
501
|
+
species_ancillary_df = ancillary_df[ancillary_df["species"] == species]
|
|
502
|
+
grouped = species_ancillary_df.groupby("lower energy (mev)")
|
|
503
|
+
return {
|
|
504
|
+
"delta_e": np.array(grouped["delta e (mev)"].apply(list).tolist()),
|
|
505
|
+
"geometry_factor": np.array(
|
|
506
|
+
grouped["geometry factor (cm2 sr)"].apply(list).tolist()
|
|
507
|
+
),
|
|
508
|
+
"efficiency": np.array(grouped["efficiency"].apply(list).tolist()),
|
|
509
|
+
"b": np.array(grouped["b"].apply(list).tolist()),
|
|
510
|
+
}
|
|
424
511
|
|
|
425
512
|
|
|
426
513
|
def load_ancillary_data(dynamic_threshold_states: set, path_prefix: Path) -> dict:
|
|
@@ -488,51 +575,21 @@ def process_summed_intensity_data(l1b_summed_rates_dataset: xr.Dataset) -> xr.Da
|
|
|
488
575
|
L2_SUMMED_ANCILLARY_PATH_PREFIX,
|
|
489
576
|
)
|
|
490
577
|
|
|
491
|
-
#
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
)
|
|
578
|
+
# Calculate the intensity for each species
|
|
579
|
+
l2_summed_intensity_dataset = calculate_intensities_for_all_species(
|
|
580
|
+
l2_summed_intensity_dataset, ancillary_data_frames, VALID_SPECIES
|
|
581
|
+
)
|
|
502
582
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
l2_summed_intensity_dataset =
|
|
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,
|
|
583
|
+
# Add total and systematic uncertainties to the dataset
|
|
584
|
+
for var in l2_summed_intensity_dataset.data_vars:
|
|
585
|
+
if var in VALID_SPECIES:
|
|
586
|
+
l2_summed_intensity_dataset = add_systematic_uncertainties(
|
|
587
|
+
l2_summed_intensity_dataset, var
|
|
511
588
|
)
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
]
|
|
589
|
+
l2_summed_intensity_dataset = add_total_uncertainties(
|
|
590
|
+
l2_summed_intensity_dataset, var
|
|
530
591
|
)
|
|
531
592
|
|
|
532
|
-
calculate_intensities_for_all_species(
|
|
533
|
-
l2_summed_intensity_dataset, ancillary_data_frames
|
|
534
|
-
)
|
|
535
|
-
|
|
536
593
|
return l2_summed_intensity_dataset
|
|
537
594
|
|
|
538
595
|
|
|
@@ -554,9 +611,9 @@ def process_standard_intensity_data(
|
|
|
554
611
|
STANDARD_PARTICLE_ENERGY_RANGE_MAPPING dictionary are included in this
|
|
555
612
|
product.
|
|
556
613
|
|
|
557
|
-
Intensity is then calculated from the summed rates
|
|
614
|
+
Intensity is then calculated from the summed standard rates:
|
|
558
615
|
|
|
559
|
-
Equation
|
|
616
|
+
Equation 9 from the HIT algorithm document:
|
|
560
617
|
Standard Intensity = (Summed L1B Standard Rates) /
|
|
561
618
|
(60 * Delta E * Geometry Factor * Efficiency) - b
|
|
562
619
|
|
|
@@ -582,9 +639,6 @@ def process_standard_intensity_data(
|
|
|
582
639
|
l2_standard_intensity_dataset["dynamic_threshold_state"] = (
|
|
583
640
|
l1b_standard_rates_dataset["dynamic_threshold_state"]
|
|
584
641
|
)
|
|
585
|
-
l2_standard_intensity_dataset[
|
|
586
|
-
"dynamic_threshold_state"
|
|
587
|
-
].attrs = l1b_standard_rates_dataset["dynamic_threshold_state"].attrs
|
|
588
642
|
|
|
589
643
|
# Load ancillary data for each dynamic threshold state into a dictionary
|
|
590
644
|
ancillary_data_frames = load_ancillary_data(
|
|
@@ -592,23 +646,78 @@ def process_standard_intensity_data(
|
|
|
592
646
|
L2_STANDARD_ANCILLARY_PATH_PREFIX,
|
|
593
647
|
)
|
|
594
648
|
|
|
595
|
-
# Process each particle type and
|
|
596
|
-
# to the dataset
|
|
649
|
+
# Process each particle type and add rates and uncertainties to the dataset
|
|
597
650
|
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
651
|
# Add standard particle rates and statistical uncertainties to the dataset
|
|
604
|
-
|
|
652
|
+
l2_standard_intensity_dataset = add_summed_particle_data_to_dataset(
|
|
605
653
|
l2_standard_intensity_dataset,
|
|
606
654
|
l1b_standard_rates_dataset,
|
|
607
655
|
particle,
|
|
608
656
|
energy_ranges,
|
|
609
657
|
)
|
|
610
|
-
|
|
611
|
-
|
|
658
|
+
|
|
659
|
+
l2_standard_intensity_dataset = calculate_intensities_for_all_species(
|
|
660
|
+
l2_standard_intensity_dataset, ancillary_data_frames, VALID_SPECIES
|
|
612
661
|
)
|
|
613
662
|
|
|
663
|
+
# Add total and systematic uncertainties to the dataset
|
|
664
|
+
for particle in STANDARD_PARTICLE_ENERGY_RANGE_MAPPING.keys():
|
|
665
|
+
l2_standard_intensity_dataset = add_systematic_uncertainties(
|
|
666
|
+
l2_standard_intensity_dataset, particle
|
|
667
|
+
)
|
|
668
|
+
l2_standard_intensity_dataset = add_total_uncertainties(
|
|
669
|
+
l2_standard_intensity_dataset, particle
|
|
670
|
+
)
|
|
671
|
+
|
|
614
672
|
return l2_standard_intensity_dataset
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def process_sectored_intensity_data(
|
|
676
|
+
l1b_sectored_rates_dataset: xr.Dataset,
|
|
677
|
+
) -> xr.Dataset:
|
|
678
|
+
"""
|
|
679
|
+
Will process L2 HIT sectored intensity data from L1B sectored rates data.
|
|
680
|
+
|
|
681
|
+
This function converts the L1B sectored rates to L2 sectored intensities
|
|
682
|
+
using ancillary tables containing factors needed to calculate the
|
|
683
|
+
intensity (energy bin width, geometry factor, efficiency, and b).
|
|
684
|
+
|
|
685
|
+
Equation 12 from the HIT algorithm document:
|
|
686
|
+
Sectored Intensity = (Summed L1B Sectored Rates) /
|
|
687
|
+
(600 * Delta E * Geometry Factor * Efficiency) - b
|
|
688
|
+
|
|
689
|
+
Parameters
|
|
690
|
+
----------
|
|
691
|
+
l1b_sectored_rates_dataset : xr.Dataset
|
|
692
|
+
The L1B sectored rates dataset.
|
|
693
|
+
|
|
694
|
+
Returns
|
|
695
|
+
-------
|
|
696
|
+
xr.Dataset
|
|
697
|
+
The processed L2 sectored intensity dataset.
|
|
698
|
+
"""
|
|
699
|
+
# Create a new dataset to store the L2 sectored intensity data
|
|
700
|
+
l2_sectored_intensity_dataset = l1b_sectored_rates_dataset.copy(deep=True)
|
|
701
|
+
|
|
702
|
+
# Load ancillary data for each dynamic threshold state into a dictionary
|
|
703
|
+
ancillary_data_frames = load_ancillary_data(
|
|
704
|
+
set(l2_sectored_intensity_dataset["dynamic_threshold_state"].values),
|
|
705
|
+
L2_SECTORED_ANCILLARY_PATH_PREFIX,
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
# Calculate the intensity for each species
|
|
709
|
+
l2_sectored_intensity_dataset = calculate_intensities_for_all_species(
|
|
710
|
+
l2_sectored_intensity_dataset, ancillary_data_frames, VALID_SECTORED_SPECIES
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
# Add total and systematic uncertainties to the dataset
|
|
714
|
+
for var in l2_sectored_intensity_dataset.data_vars:
|
|
715
|
+
if var in VALID_SECTORED_SPECIES:
|
|
716
|
+
l2_sectored_intensity_dataset = add_systematic_uncertainties(
|
|
717
|
+
l2_sectored_intensity_dataset, var
|
|
718
|
+
)
|
|
719
|
+
l2_sectored_intensity_dataset = add_total_uncertainties(
|
|
720
|
+
l2_sectored_intensity_dataset, var
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
return l2_sectored_intensity_dataset
|