imap-processing 0.9.0__py3-none-any.whl → 0.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/_version.py +2 -2
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +749 -442
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +7 -0
- imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +8 -2
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +0 -1
- imap_processing/cdf/config/imap_glows_l2_variable_attrs.yaml +358 -0
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +59 -25
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +22 -0
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +32 -8
- imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +94 -5
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +65 -37
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +16 -1
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +7 -0
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +14 -14
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +25 -24
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +238 -0
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +100 -92
- imap_processing/cdf/utils.py +2 -2
- imap_processing/cli.py +45 -9
- imap_processing/codice/codice_l1a.py +104 -58
- imap_processing/codice/constants.py +111 -155
- imap_processing/codice/data/esa_sweep_values.csv +256 -256
- imap_processing/codice/data/lo_stepping_values.csv +128 -128
- imap_processing/ena_maps/ena_maps.py +519 -0
- imap_processing/ena_maps/utils/map_utils.py +145 -0
- imap_processing/ena_maps/utils/spatial_utils.py +226 -0
- imap_processing/glows/__init__.py +3 -0
- imap_processing/glows/ancillary/imap_glows_pipeline_settings_v001.json +52 -0
- imap_processing/glows/l1a/glows_l1a.py +72 -14
- imap_processing/glows/l1b/glows_l1b.py +2 -1
- imap_processing/glows/l1b/glows_l1b_data.py +25 -1
- imap_processing/glows/l2/glows_l2.py +324 -0
- imap_processing/glows/l2/glows_l2_data.py +156 -51
- imap_processing/hi/l1a/science_direct_event.py +57 -51
- imap_processing/hi/l1b/hi_l1b.py +43 -28
- imap_processing/hi/l1c/hi_l1c.py +225 -42
- imap_processing/hi/utils.py +20 -3
- imap_processing/hit/l0/constants.py +2 -2
- imap_processing/hit/l0/decom_hit.py +1 -1
- imap_processing/hit/l1a/hit_l1a.py +94 -13
- imap_processing/hit/l1b/hit_l1b.py +158 -9
- imap_processing/ialirt/l0/process_codicehi.py +156 -0
- imap_processing/ialirt/l0/process_codicelo.py +5 -2
- imap_processing/ialirt/packet_definitions/ialirt.xml +28 -20
- imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +241 -0
- imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +170 -0
- imap_processing/ialirt/packet_definitions/ialirt_swe.xml +258 -0
- imap_processing/ialirt/process_ephemeris.py +72 -40
- imap_processing/idex/decode.py +241 -0
- imap_processing/idex/idex_l1a.py +143 -81
- imap_processing/idex/idex_l1b.py +244 -10
- imap_processing/lo/l0/lo_science.py +61 -0
- imap_processing/lo/l1a/lo_l1a.py +98 -10
- imap_processing/lo/l1b/lo_l1b.py +2 -2
- imap_processing/lo/l1c/lo_l1c.py +2 -2
- imap_processing/lo/packet_definitions/lo_xtce.xml +1082 -9178
- imap_processing/mag/l0/decom_mag.py +2 -2
- imap_processing/mag/l1a/mag_l1a.py +7 -7
- imap_processing/mag/l1a/mag_l1a_data.py +62 -30
- imap_processing/mag/l1b/mag_l1b.py +11 -6
- imap_processing/quality_flags.py +18 -3
- imap_processing/spice/geometry.py +149 -177
- imap_processing/spice/kernels.py +26 -26
- imap_processing/spice/spin.py +233 -0
- imap_processing/spice/time.py +96 -31
- imap_processing/swapi/l1/swapi_l1.py +60 -31
- imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +363 -384
- imap_processing/swe/l1a/swe_l1a.py +8 -3
- imap_processing/swe/l1a/swe_science.py +24 -24
- imap_processing/swe/l1b/swe_l1b.py +2 -1
- imap_processing/swe/l1b/swe_l1b_science.py +181 -122
- imap_processing/swe/l2/swe_l2.py +337 -70
- imap_processing/swe/utils/swe_utils.py +28 -0
- imap_processing/tests/cdf/test_utils.py +2 -2
- imap_processing/tests/codice/conftest.py +20 -17
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hskp_20241110193622_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/test_codice_l0.py +55 -121
- imap_processing/tests/codice/test_codice_l1a.py +147 -59
- imap_processing/tests/conftest.py +81 -22
- imap_processing/tests/ena_maps/test_ena_maps.py +309 -0
- imap_processing/tests/ena_maps/test_map_utils.py +286 -0
- imap_processing/tests/ena_maps/test_spatial_utils.py +161 -0
- imap_processing/tests/glows/conftest.py +7 -1
- imap_processing/tests/glows/test_glows_l1a_cdf.py +3 -7
- imap_processing/tests/glows/test_glows_l1a_data.py +34 -6
- imap_processing/tests/glows/test_glows_l1b_data.py +29 -17
- imap_processing/tests/glows/test_glows_l2.py +101 -0
- imap_processing/tests/hi/conftest.py +3 -3
- imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
- imap_processing/tests/hi/data/l1/imap_his_pset-calibration-prod-config_20240101_v001.csv +31 -0
- imap_processing/tests/hi/test_hi_l1b.py +14 -9
- imap_processing/tests/hi/test_hi_l1c.py +136 -36
- imap_processing/tests/hi/test_l1a.py +0 -2
- imap_processing/tests/hi/test_science_direct_event.py +18 -14
- imap_processing/tests/hi/test_utils.py +16 -11
- imap_processing/tests/hit/helpers/__init__.py +0 -0
- imap_processing/tests/hit/helpers/l1_validation.py +405 -0
- imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
- imap_processing/tests/hit/test_decom_hit.py +8 -10
- imap_processing/tests/hit/test_hit_l1a.py +117 -180
- imap_processing/tests/hit/test_hit_l1b.py +149 -55
- imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -0
- imap_processing/tests/hit/validation_data/sci_sample_raw.csv +62 -0
- imap_processing/tests/ialirt/test_data/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/eu_SWP_IAL_20240826_152033.csv +644 -0
- imap_processing/tests/ialirt/test_data/l0/hi_fsw_view_1_ccsds.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +914 -0
- imap_processing/tests/ialirt/test_data/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
- imap_processing/tests/ialirt/unit/test_process_codicehi.py +106 -0
- imap_processing/tests/ialirt/unit/test_process_ephemeris.py +33 -5
- imap_processing/tests/ialirt/unit/test_process_swapi.py +85 -0
- imap_processing/tests/ialirt/unit/test_process_swe.py +106 -0
- imap_processing/tests/idex/conftest.py +29 -1
- imap_processing/tests/idex/test_data/compressed_2023_102_14_24_55.pkts +0 -0
- imap_processing/tests/idex/test_data/non_compressed_2023_102_14_22_26.pkts +0 -0
- imap_processing/tests/idex/test_idex_l0.py +6 -3
- imap_processing/tests/idex/test_idex_l1a.py +151 -1
- imap_processing/tests/idex/test_idex_l1b.py +124 -2
- imap_processing/tests/lo/test_lo_l1a.py +62 -2
- imap_processing/tests/lo/test_lo_science.py +85 -0
- imap_processing/tests/lo/validation_data/Instrument_FM1_T104_R129_20240803_ILO_SPIN_EU.csv +2 -0
- imap_processing/tests/mag/conftest.py +16 -0
- imap_processing/tests/mag/test_mag_decom.py +6 -4
- imap_processing/tests/mag/test_mag_l1a.py +36 -7
- imap_processing/tests/mag/test_mag_l1b.py +55 -4
- imap_processing/tests/mag/test_mag_validation.py +148 -0
- imap_processing/tests/mag/validation/L1a/T001/all_p_ones.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T002/all_n_ones.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T003/field_like.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T004/field_like.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T005/field_like_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T006/hdr_field.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T007/hdr_field_and_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-out.csv +17 -0
- imap_processing/tests/mag/validation/L1a/T008/field_like_range_change.txt +19200 -0
- imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-in.bin +0 -0
- imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T009/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T010/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T011/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +17 -0
- imap_processing/tests/spice/test_geometry.py +128 -133
- imap_processing/tests/spice/test_kernels.py +37 -37
- imap_processing/tests/spice/test_spin.py +184 -0
- imap_processing/tests/spice/test_time.py +43 -20
- imap_processing/tests/swapi/test_swapi_l1.py +11 -10
- imap_processing/tests/swapi/test_swapi_l2.py +13 -3
- imap_processing/tests/swe/test_swe_l1a.py +1 -1
- imap_processing/tests/swe/test_swe_l1b.py +20 -3
- imap_processing/tests/swe/test_swe_l1b_science.py +54 -35
- imap_processing/tests/swe/test_swe_l2.py +148 -5
- imap_processing/tests/test_cli.py +39 -7
- imap_processing/tests/test_quality_flags.py +19 -19
- imap_processing/tests/test_utils.py +3 -2
- imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -3314
- imap_processing/tests/ultra/test_data/mock_data.py +161 -0
- imap_processing/tests/ultra/unit/conftest.py +73 -0
- imap_processing/tests/ultra/unit/test_badtimes.py +58 -0
- imap_processing/tests/ultra/unit/test_cullingmask.py +87 -0
- imap_processing/tests/ultra/unit/test_de.py +61 -60
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +3 -3
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +51 -77
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +5 -5
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +114 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -26
- imap_processing/tests/ultra/unit/test_ultra_l1c.py +1 -1
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +3 -3
- imap_processing/ultra/constants.py +11 -1
- imap_processing/ultra/l1a/ultra_l1a.py +2 -2
- imap_processing/ultra/l1b/badtimes.py +22 -5
- imap_processing/ultra/l1b/cullingmask.py +31 -5
- imap_processing/ultra/l1b/de.py +32 -37
- imap_processing/ultra/l1b/extendedspin.py +44 -20
- imap_processing/ultra/l1b/ultra_l1b.py +21 -22
- imap_processing/ultra/l1b/ultra_l1b_culling.py +190 -0
- imap_processing/ultra/l1b/ultra_l1b_extended.py +81 -30
- imap_processing/ultra/l1c/histogram.py +6 -2
- imap_processing/ultra/l1c/pset.py +6 -2
- imap_processing/ultra/l1c/ultra_l1c.py +2 -3
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +4 -3
- imap_processing/ultra/utils/ultra_l1_utils.py +70 -14
- imap_processing/utils.py +2 -2
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/METADATA +7 -2
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/RECORD +235 -152
- imap_processing/tests/codice/data/eu_unit_lookup_table.csv +0 -101
- imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +0 -100
- imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +0 -100
- imap_processing/tests/codice/data/imap_codice_l0_raw_20241110_v001.pkts +0 -0
- imap_processing/tests/hi/test_data/l1a/imap_hi_l1a_45sensor-de_20250415_v000.cdf +0 -0
- imap_processing/tests/hit/test_data/sci_sample1.ccsds +0 -0
- imap_processing/tests/ultra/unit/test_spatial_utils.py +0 -125
- imap_processing/ultra/utils/spatial_utils.py +0 -221
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.csv +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_CNT.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_DE.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_NHK_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_cnt_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_de_20241104.bin +0 -0
- /imap_processing/tests/hi/{test_data → data}/l0/README.txt +0 -0
- /imap_processing/tests/idex/{imap_idex_l0_raw_20231214_v001.pkts → test_data/imap_idex_l0_raw_20231214_v001.pkts} +0 -0
- /imap_processing/tests/idex/{impact_14_tof_high_data.txt → test_data/impact_14_tof_high_data.txt} +0 -0
- /imap_processing/tests/mag/{imap_mag_l1a_norm-magi_20251017_v001.cdf → validation/imap_mag_l1a_norm-magi_20251017_v001.cdf} +0 -0
- /imap_processing/tests/mag/{mag_l0_test_data.pkts → validation/mag_l0_test_data.pkts} +0 -0
- /imap_processing/tests/mag/{mag_l0_test_output.csv → validation/mag_l0_test_output.csv} +0 -0
- /imap_processing/tests/mag/{mag_l1_test_data.pkts → validation/mag_l1_test_data.pkts} +0 -0
- /imap_processing/tests/mag/{mag_l1a_test_output.csv → validation/mag_l1a_test_output.csv} +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/entry_points.txt +0 -0
imap_processing/ultra/l1b/de.py
CHANGED
|
@@ -13,6 +13,9 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
13
13
|
determine_species,
|
|
14
14
|
get_coincidence_positions,
|
|
15
15
|
get_ctof,
|
|
16
|
+
get_de_az_el,
|
|
17
|
+
get_de_energy_kev,
|
|
18
|
+
get_de_velocity,
|
|
16
19
|
get_energy_pulse_height,
|
|
17
20
|
get_energy_ssd,
|
|
18
21
|
get_front_x_position,
|
|
@@ -21,12 +24,11 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
21
24
|
get_ph_tof_and_back_positions,
|
|
22
25
|
get_ssd_back_position_and_tof_offset,
|
|
23
26
|
get_ssd_tof,
|
|
24
|
-
get_unit_vector,
|
|
25
27
|
)
|
|
26
28
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
31
|
+
def calculate_de(de_dataset: xr.Dataset, name: str, data_version: str) -> xr.Dataset:
|
|
30
32
|
"""
|
|
31
33
|
Create dataset with defined datatypes for Direct Event Data.
|
|
32
34
|
|
|
@@ -36,6 +38,8 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
36
38
|
L1a dataset containing direct event data.
|
|
37
39
|
name : str
|
|
38
40
|
Name of the l1a dataset.
|
|
41
|
+
data_version : str
|
|
42
|
+
Version of the data.
|
|
39
43
|
|
|
40
44
|
Returns
|
|
41
45
|
-------
|
|
@@ -45,6 +49,11 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
45
49
|
de_dict = {}
|
|
46
50
|
sensor = parse_filename_like(name)["sensor"][0:2]
|
|
47
51
|
|
|
52
|
+
# Drop events with invalid start type.
|
|
53
|
+
de_dataset = de_dataset.where(
|
|
54
|
+
de_dataset["START_TYPE"] != np.iinfo(np.int64).min, drop=True
|
|
55
|
+
)
|
|
56
|
+
|
|
48
57
|
# Instantiate arrays
|
|
49
58
|
yf = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
50
59
|
xb = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
@@ -55,17 +64,13 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
55
64
|
tof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
56
65
|
etof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
57
66
|
ctof = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
67
|
+
magnitude_v = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
58
68
|
energy = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
59
|
-
# TODO: Confirm with Ultra team what fill values and dtype we want.
|
|
60
69
|
species_bin = np.full(len(de_dataset["epoch"]), "UNKNOWN", dtype="U10")
|
|
61
70
|
t2 = np.full(len(de_dataset["epoch"]), np.nan, dtype=np.float32)
|
|
62
71
|
|
|
63
|
-
# Drop events with invalid start type.
|
|
64
|
-
de_dataset = de_dataset.where(
|
|
65
|
-
de_dataset["START_TYPE"] != np.iinfo(np.int64).min, drop=True
|
|
66
|
-
)
|
|
67
72
|
# Define epoch.
|
|
68
|
-
de_dict["epoch"] = de_dataset["epoch"]
|
|
73
|
+
de_dict["epoch"] = de_dataset["epoch"].data
|
|
69
74
|
|
|
70
75
|
xf = get_front_x_position(
|
|
71
76
|
de_dataset["START_TYPE"].data,
|
|
@@ -97,7 +102,9 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
97
102
|
etof[ph_indices], xc[ph_indices] = get_coincidence_positions(
|
|
98
103
|
de_dataset.isel(epoch=ph_indices), t2[ph_indices], f"ultra{sensor}"
|
|
99
104
|
)
|
|
100
|
-
ctof[ph_indices],
|
|
105
|
+
ctof[ph_indices], magnitude_v[ph_indices] = get_ctof(
|
|
106
|
+
tof[ph_indices], r[ph_indices], "PH"
|
|
107
|
+
)
|
|
101
108
|
|
|
102
109
|
# SSD
|
|
103
110
|
ssd_indices = np.nonzero(np.isin(de_dataset["STOP_TYPE"], StopType.SSD.value))[0]
|
|
@@ -118,7 +125,9 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
118
125
|
species_bin[ssd_indices] = determine_species(
|
|
119
126
|
tof[ssd_indices], r[ssd_indices], "SSD"
|
|
120
127
|
)
|
|
121
|
-
ctof[ssd_indices],
|
|
128
|
+
ctof[ssd_indices], magnitude_v[ssd_indices] = get_ctof(
|
|
129
|
+
tof[ssd_indices], r[ssd_indices], "SSD"
|
|
130
|
+
)
|
|
122
131
|
|
|
123
132
|
# Combine ph_yb and ssd_yb along with their indices
|
|
124
133
|
de_dict["x_front"] = xf.astype(np.float32)
|
|
@@ -129,6 +138,7 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
129
138
|
de_dict["tof_start_stop"] = tof
|
|
130
139
|
de_dict["tof_stop_coin"] = etof
|
|
131
140
|
de_dict["tof_corrected"] = ctof
|
|
141
|
+
de_dict["velocity_magnitude"] = magnitude_v
|
|
132
142
|
de_dict["front_back_distance"] = d
|
|
133
143
|
de_dict["path_length"] = r
|
|
134
144
|
|
|
@@ -137,61 +147,46 @@ def calculate_de(de_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
137
147
|
"start_type",
|
|
138
148
|
"event_type",
|
|
139
149
|
"de_event_met",
|
|
150
|
+
"event_times",
|
|
140
151
|
]
|
|
141
|
-
dataset_keys = ["COIN_TYPE", "START_TYPE", "STOP_TYPE", "SHCOARSE"]
|
|
152
|
+
dataset_keys = ["COIN_TYPE", "START_TYPE", "STOP_TYPE", "SHCOARSE", "EVENTTIMES"]
|
|
142
153
|
|
|
143
154
|
de_dict.update(
|
|
144
155
|
{key: de_dataset[dataset_key] for key, dataset_key in zip(keys, dataset_keys)}
|
|
145
156
|
)
|
|
146
157
|
|
|
147
|
-
|
|
158
|
+
v = get_de_velocity(
|
|
148
159
|
(de_dict["x_front"], de_dict["y_front"]),
|
|
149
160
|
(de_dict["x_back"], de_dict["y_back"]),
|
|
150
161
|
de_dict["front_back_distance"],
|
|
151
162
|
de_dict["tof_start_stop"],
|
|
152
163
|
)
|
|
164
|
+
de_dict["direct_event_velocity"] = v.astype(np.float32)
|
|
153
165
|
|
|
154
|
-
de_dict["
|
|
155
|
-
de_dict["
|
|
156
|
-
de_dict["vz_ultra"] = vz_ultra.astype(np.float32)
|
|
166
|
+
de_dict["tof_energy"] = get_de_energy_kev(v, species_bin)
|
|
167
|
+
de_dict["azimuth"], de_dict["elevation"] = get_de_az_el(v)
|
|
157
168
|
de_dict["energy"] = energy
|
|
158
169
|
de_dict["species"] = species_bin
|
|
159
170
|
|
|
160
171
|
# Annotated Events.
|
|
161
|
-
position = np.stack(
|
|
162
|
-
(de_dict["vx_ultra"], de_dict["vy_ultra"], de_dict["vz_ultra"]), axis=-1
|
|
163
|
-
)
|
|
164
|
-
|
|
165
172
|
ultra_frame = getattr(SpiceFrame, f"IMAP_ULTRA_{sensor}")
|
|
166
173
|
sc_velocity, sc_dps_velocity, helio_velocity = get_annotated_particle_velocity(
|
|
167
|
-
de_dataset.data_vars["EVENTTIMES"],
|
|
168
|
-
|
|
174
|
+
de_dataset.data_vars["EVENTTIMES"].values,
|
|
175
|
+
de_dict["direct_event_velocity"],
|
|
169
176
|
ultra_frame,
|
|
170
177
|
SpiceFrame.IMAP_DPS,
|
|
171
178
|
SpiceFrame.IMAP_SPACECRAFT,
|
|
172
179
|
)
|
|
173
180
|
|
|
174
|
-
de_dict["
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
sc_velocity[:, 2],
|
|
178
|
-
)
|
|
179
|
-
de_dict["vx_dps_sc"], de_dict["vy_dps_sc"], de_dict["vz_dps_sc"] = (
|
|
180
|
-
sc_dps_velocity[:, 0],
|
|
181
|
-
sc_dps_velocity[:, 1],
|
|
182
|
-
sc_dps_velocity[:, 2],
|
|
183
|
-
)
|
|
184
|
-
de_dict["vx_dps_helio"], de_dict["vy_dps_helio"], de_dict["vz_dps_helio"] = (
|
|
185
|
-
helio_velocity[:, 0],
|
|
186
|
-
helio_velocity[:, 1],
|
|
187
|
-
helio_velocity[:, 2],
|
|
188
|
-
)
|
|
181
|
+
de_dict["velocity_sc"] = sc_velocity
|
|
182
|
+
de_dict["velocity_dps_sc"] = sc_dps_velocity
|
|
183
|
+
de_dict["velocity_dps_helio"] = helio_velocity
|
|
189
184
|
|
|
190
185
|
# TODO: TBD.
|
|
191
186
|
de_dict["event_efficiency"] = np.full(
|
|
192
187
|
len(de_dataset["epoch"]), np.nan, dtype=np.float32
|
|
193
188
|
)
|
|
194
189
|
|
|
195
|
-
dataset = create_dataset(de_dict, name, "l1b")
|
|
190
|
+
dataset = create_dataset(de_dict, name, "l1b", data_version)
|
|
196
191
|
|
|
197
192
|
return dataset
|
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
"""Calculate Extended Spin."""
|
|
2
2
|
|
|
3
|
-
import numpy as np
|
|
4
3
|
import xarray as xr
|
|
5
4
|
|
|
5
|
+
from imap_processing.ultra.l1b.ultra_l1b_culling import (
|
|
6
|
+
flag_attitude,
|
|
7
|
+
flag_spin,
|
|
8
|
+
get_energy_histogram,
|
|
9
|
+
get_spin,
|
|
10
|
+
)
|
|
6
11
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
7
12
|
|
|
8
13
|
|
|
9
|
-
def calculate_extendedspin(
|
|
14
|
+
def calculate_extendedspin(
|
|
15
|
+
hk_dataset: xr.Dataset,
|
|
16
|
+
rates_dataset: xr.Dataset,
|
|
17
|
+
de_dataset: xr.Dataset,
|
|
18
|
+
name: str,
|
|
19
|
+
data_version: str,
|
|
20
|
+
) -> xr.Dataset:
|
|
10
21
|
"""
|
|
11
22
|
Create dataset with defined datatypes for Extended Spin Data.
|
|
12
23
|
|
|
13
24
|
Parameters
|
|
14
25
|
----------
|
|
26
|
+
hk_dataset : xarray.Dataset
|
|
27
|
+
Dataset containing l1a hk data.
|
|
15
28
|
rates_dataset : xarray.Dataset
|
|
16
|
-
Dataset containing rates data.
|
|
29
|
+
Dataset containing l1a rates data.
|
|
30
|
+
de_dataset : xarray.Dataset
|
|
31
|
+
Dataset containing l1b de data.
|
|
17
32
|
name : str
|
|
18
33
|
Name of the dataset.
|
|
34
|
+
data_version : str
|
|
35
|
+
Version of the data.
|
|
19
36
|
|
|
20
37
|
Returns
|
|
21
38
|
-------
|
|
@@ -23,23 +40,30 @@ def calculate_extendedspin(rates_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
23
40
|
Dataset containing the data.
|
|
24
41
|
"""
|
|
25
42
|
extendedspin_dict = {}
|
|
43
|
+
rates_qf, spin, energy_midpoints, n_sigma_per_energy = flag_spin(
|
|
44
|
+
de_dataset["event_times"].values,
|
|
45
|
+
de_dataset["energy"].values,
|
|
46
|
+
)
|
|
47
|
+
spin_number = get_spin(de_dataset["event_times"].values)
|
|
48
|
+
count_rates, _, counts, _ = get_energy_histogram(
|
|
49
|
+
spin_number, de_dataset["energy"].values
|
|
50
|
+
)
|
|
51
|
+
attitude_qf, spin_rates, spin_period, spin_starttime = flag_attitude(
|
|
52
|
+
de_dataset["event_times"].values
|
|
53
|
+
)
|
|
26
54
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
extendedspin_dict["
|
|
32
|
-
extendedspin_dict["
|
|
33
|
-
extendedspin_dict["
|
|
34
|
-
extendedspin_dict["
|
|
35
|
-
extendedspin_dict["
|
|
36
|
-
extendedspin_dict["
|
|
37
|
-
extendedspin_dict["
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
extendedspin_dict["quality_attitude"] = np.zeros(len(epoch), dtype=np.uint16)
|
|
41
|
-
extendedspin_dict["quality_instruments"] = np.zeros(len(epoch), dtype=np.uint16)
|
|
42
|
-
|
|
43
|
-
extendedspin_dataset = create_dataset(extendedspin_dict, name, "l1b")
|
|
55
|
+
# These will be the coordinates.
|
|
56
|
+
extendedspin_dict["spin_number"] = spin
|
|
57
|
+
extendedspin_dict["energy_bin_geometric_mean"] = energy_midpoints
|
|
58
|
+
|
|
59
|
+
extendedspin_dict["ena_rates"] = count_rates
|
|
60
|
+
extendedspin_dict["ena_rates_threshold"] = n_sigma_per_energy
|
|
61
|
+
extendedspin_dict["spin_start_time"] = spin_starttime
|
|
62
|
+
extendedspin_dict["spin_period"] = spin_period
|
|
63
|
+
extendedspin_dict["spin_rate"] = spin_rates
|
|
64
|
+
extendedspin_dict["quality_attitude"] = attitude_qf
|
|
65
|
+
extendedspin_dict["quality_ena_rates"] = rates_qf
|
|
66
|
+
|
|
67
|
+
extendedspin_dataset = create_dataset(extendedspin_dict, name, "l1b", data_version)
|
|
44
68
|
|
|
45
69
|
return extendedspin_dataset
|
|
@@ -27,38 +27,37 @@ def ultra_l1b(data_dict: dict, data_version: str) -> list[xr.Dataset]:
|
|
|
27
27
|
output_datasets = []
|
|
28
28
|
instrument_id = 45 if any("45" in key for key in data_dict.keys()) else 90
|
|
29
29
|
|
|
30
|
-
if
|
|
30
|
+
if (
|
|
31
|
+
f"imap_ultra_l1a_{instrument_id}sensor-hk" in data_dict
|
|
32
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-de" in data_dict
|
|
33
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
|
|
34
|
+
):
|
|
35
|
+
de_dataset = calculate_de(
|
|
36
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-de"],
|
|
37
|
+
f"imap_ultra_l1b_{instrument_id}sensor-de",
|
|
38
|
+
data_version,
|
|
39
|
+
)
|
|
31
40
|
extendedspin_dataset = calculate_extendedspin(
|
|
41
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-hk"],
|
|
32
42
|
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
43
|
+
de_dataset,
|
|
33
44
|
f"imap_ultra_l1b_{instrument_id}sensor-extendedspin",
|
|
45
|
+
data_version,
|
|
34
46
|
)
|
|
35
|
-
# TODO: move these to use ImapCdfAttributes().add_global_attribute()
|
|
36
|
-
extendedspin_dataset.attrs["Data_version"] = data_version
|
|
37
|
-
|
|
38
47
|
cullingmask_dataset = calculate_cullingmask(
|
|
39
|
-
extendedspin_dataset,
|
|
48
|
+
extendedspin_dataset,
|
|
49
|
+
f"imap_ultra_l1b_{instrument_id}sensor-cullingmask",
|
|
50
|
+
data_version,
|
|
40
51
|
)
|
|
41
|
-
cullingmask_dataset.attrs["Data_version"] = data_version
|
|
42
|
-
|
|
43
52
|
badtimes_dataset = calculate_badtimes(
|
|
44
|
-
extendedspin_dataset,
|
|
53
|
+
extendedspin_dataset,
|
|
54
|
+
cullingmask_dataset["spin_number"].values,
|
|
55
|
+
f"imap_ultra_l1b_{instrument_id}sensor-badtimes",
|
|
56
|
+
data_version,
|
|
45
57
|
)
|
|
46
|
-
badtimes_dataset.attrs["Data_version"] = data_version
|
|
47
|
-
|
|
48
58
|
output_datasets.extend(
|
|
49
|
-
[extendedspin_dataset, cullingmask_dataset, badtimes_dataset]
|
|
50
|
-
)
|
|
51
|
-
elif (
|
|
52
|
-
f"imap_ultra_l1a_{instrument_id}sensor-aux" in data_dict
|
|
53
|
-
and f"imap_ultra_l1a_{instrument_id}sensor-de" in data_dict
|
|
54
|
-
):
|
|
55
|
-
de_dataset = calculate_de(
|
|
56
|
-
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-de"],
|
|
57
|
-
f"imap_ultra_l1b_{instrument_id}sensor-de",
|
|
59
|
+
[de_dataset, extendedspin_dataset, cullingmask_dataset, badtimes_dataset]
|
|
58
60
|
)
|
|
59
|
-
de_dataset.attrs["Data_version"] = data_version
|
|
60
|
-
|
|
61
|
-
output_datasets.append(de_dataset)
|
|
62
61
|
else:
|
|
63
62
|
raise ValueError("Data dictionary does not contain the expected keys.")
|
|
64
63
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Culls Events for ULTRA L1b."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
from imap_processing.quality_flags import ImapAttitudeUltraFlags, ImapRatesUltraFlags
|
|
7
|
+
from imap_processing.spice.spin import get_spin_data, interpolate_spin_data
|
|
8
|
+
from imap_processing.ultra.constants import UltraConstants
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_spin(eventtimes_met: NDArray) -> NDArray:
|
|
12
|
+
"""
|
|
13
|
+
Get spin number for each event.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
eventtimes_met : NDArray
|
|
18
|
+
Event Times in Mission Elapsed Time.
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
spin_number : NDArray
|
|
23
|
+
Spin number at each event derived the from Universal Spin Table.
|
|
24
|
+
"""
|
|
25
|
+
spin_df = interpolate_spin_data(eventtimes_met)
|
|
26
|
+
return spin_df["spin_number"].values
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_energy_histogram(
|
|
30
|
+
spin_number: NDArray, energy: NDArray
|
|
31
|
+
) -> tuple[NDArray, NDArray, NDArray, float]:
|
|
32
|
+
"""
|
|
33
|
+
Compute a 2D histogram of the counts binned by energy and spin number.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
spin_number : NDArray
|
|
38
|
+
Spin number.
|
|
39
|
+
energy : NDArray
|
|
40
|
+
The particle energy.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
hist : NDArray
|
|
45
|
+
A 2D histogram array containing the
|
|
46
|
+
count rate per spin at each energy bin.
|
|
47
|
+
spin_edges : NDArray
|
|
48
|
+
Edges of the spin number bins.
|
|
49
|
+
counts : NDArray
|
|
50
|
+
A 2D histogram array containing the
|
|
51
|
+
counts per spin at each energy bin.
|
|
52
|
+
mean_duration : float
|
|
53
|
+
Mean duration of the spin.
|
|
54
|
+
"""
|
|
55
|
+
spin_df = get_spin_data()
|
|
56
|
+
|
|
57
|
+
spin_edges = np.unique(spin_number)
|
|
58
|
+
spin_edges = np.append(spin_edges, spin_edges.max() + 1)
|
|
59
|
+
|
|
60
|
+
# Counts per spin at each energy bin.
|
|
61
|
+
hist, _ = np.histogramdd(
|
|
62
|
+
sample=(energy, spin_number),
|
|
63
|
+
bins=[UltraConstants.CULLING_ENERGY_BIN_EDGES, spin_edges],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
counts = hist.copy()
|
|
67
|
+
total_spin_duration = 0
|
|
68
|
+
|
|
69
|
+
# Count rate per spin at each energy bin.
|
|
70
|
+
for i in range(hist.shape[1]):
|
|
71
|
+
spin_duration = spin_df.spin_period_sec[spin_df.spin_number == i]
|
|
72
|
+
hist[:, i] /= spin_duration.values[0]
|
|
73
|
+
total_spin_duration += spin_duration.sum()
|
|
74
|
+
|
|
75
|
+
mean_duration = total_spin_duration / hist.shape[1]
|
|
76
|
+
|
|
77
|
+
return hist, spin_edges, counts, mean_duration
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def flag_attitude(eventtimes_met: NDArray) -> tuple[NDArray, NDArray, NDArray, NDArray]:
|
|
81
|
+
"""
|
|
82
|
+
Flag data based on attitude.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
eventtimes_met : NDArray
|
|
87
|
+
Event Times in Mission Elapsed Time.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
quality_flags : NDArray
|
|
92
|
+
Quality flags.
|
|
93
|
+
spin_rates : NDArray
|
|
94
|
+
Spin rates.
|
|
95
|
+
spin_period : NDArray
|
|
96
|
+
Spin period.
|
|
97
|
+
spin_starttime : NDArray
|
|
98
|
+
Spin start time.
|
|
99
|
+
"""
|
|
100
|
+
spins = np.unique(get_spin(eventtimes_met)) # Get unique spins
|
|
101
|
+
spin_df = get_spin_data() # Load spin data
|
|
102
|
+
|
|
103
|
+
spin_period = spin_df.loc[spin_df.spin_number.isin(spins), "spin_period_sec"]
|
|
104
|
+
spin_starttime = spin_df.loc[spin_df.spin_number.isin(spins), "spin_start_time"]
|
|
105
|
+
spin_rates = 60 / spin_period # 60 seconds in a minute
|
|
106
|
+
bad_spin_rate_indices = (spin_rates < UltraConstants.CULLING_RPM_MIN) | (
|
|
107
|
+
spin_rates > UltraConstants.CULLING_RPM_MAX
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
quality_flags = np.full(
|
|
111
|
+
spin_rates.shape, ImapAttitudeUltraFlags.NONE.value, dtype=np.uint16
|
|
112
|
+
)
|
|
113
|
+
quality_flags[bad_spin_rate_indices] |= ImapAttitudeUltraFlags.SPINRATE.value
|
|
114
|
+
|
|
115
|
+
return quality_flags, spin_rates, spin_period, spin_starttime
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_n_sigma(count_rates: NDArray, mean_duration: float, sigma: int = 6) -> NDArray:
|
|
119
|
+
"""
|
|
120
|
+
Calculate the threshold for the HIGHRATES flag.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
count_rates : NDArray
|
|
125
|
+
A 2D histogram array containing the
|
|
126
|
+
count rates per spin at each energy bin.
|
|
127
|
+
mean_duration : float
|
|
128
|
+
Mean duration of the spins.
|
|
129
|
+
sigma : int (default=6)
|
|
130
|
+
The number of sigma.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
threshold : NDArray
|
|
135
|
+
Threshold for applying HIGHRATES flag.
|
|
136
|
+
"""
|
|
137
|
+
sigma_per_energy = np.std(count_rates, axis=1)
|
|
138
|
+
n_sigma_per_energy = sigma * sigma_per_energy
|
|
139
|
+
mean_per_energy = np.mean(count_rates, axis=1)
|
|
140
|
+
# Must have a HIGHRATES threshold of at least 3 counts per spin.
|
|
141
|
+
threshold = np.maximum(mean_per_energy + n_sigma_per_energy, 3 / mean_duration)
|
|
142
|
+
|
|
143
|
+
return threshold
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def flag_spin(
|
|
147
|
+
eventtimes_met: NDArray, energy: NDArray, sigma: int = 6
|
|
148
|
+
) -> tuple[NDArray, NDArray, NDArray, NDArray]:
|
|
149
|
+
"""
|
|
150
|
+
Flag data based on counts and negative energies.
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
eventtimes_met : NDArray
|
|
155
|
+
Event Times in Mission Elapsed Time.
|
|
156
|
+
energy : NDArray
|
|
157
|
+
Energy data.
|
|
158
|
+
sigma : int (default=6)
|
|
159
|
+
The number of sigma.
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
quality_flags : NDArray
|
|
164
|
+
Quality flags.
|
|
165
|
+
spin : NDArray
|
|
166
|
+
Spin data.
|
|
167
|
+
energy_midpoints : NDArray
|
|
168
|
+
Energy midpoint data.
|
|
169
|
+
n_sigma_per_energy_reshape : NDArray
|
|
170
|
+
N sigma per energy.
|
|
171
|
+
"""
|
|
172
|
+
spin = get_spin(eventtimes_met)
|
|
173
|
+
count_rates, spin_edges, counts, duration = get_energy_histogram(spin, energy)
|
|
174
|
+
quality_flags = np.full(
|
|
175
|
+
count_rates.shape, ImapRatesUltraFlags.NONE.value, dtype=np.uint16
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Zero counts/spin/energy level
|
|
179
|
+
quality_flags[counts == 0] |= ImapRatesUltraFlags.ZEROCOUNTS.value
|
|
180
|
+
threshold = get_n_sigma(count_rates, duration, sigma=sigma)
|
|
181
|
+
|
|
182
|
+
bin_edges = np.array(UltraConstants.CULLING_ENERGY_BIN_EDGES)
|
|
183
|
+
energy_midpoints = np.sqrt(bin_edges[:-1] * bin_edges[1:])
|
|
184
|
+
spin = np.unique(spin)
|
|
185
|
+
|
|
186
|
+
# Indices where the counts exceed the threshold
|
|
187
|
+
indices_n_sigma = count_rates > threshold[:, np.newaxis]
|
|
188
|
+
quality_flags[indices_n_sigma] |= ImapRatesUltraFlags.HIGHRATES.value
|
|
189
|
+
|
|
190
|
+
return quality_flags, spin, energy_midpoints, threshold
|
|
@@ -10,6 +10,7 @@ import xarray
|
|
|
10
10
|
from numpy import ndarray
|
|
11
11
|
from numpy.typing import NDArray
|
|
12
12
|
|
|
13
|
+
from imap_processing.spice.geometry import cartesian_to_spherical
|
|
13
14
|
from imap_processing.ultra.constants import UltraConstants
|
|
14
15
|
from imap_processing.ultra.l1b.lookup_utils import (
|
|
15
16
|
get_back_position,
|
|
@@ -437,20 +438,14 @@ def get_coincidence_positions(
|
|
|
437
438
|
return etof, xc_array * 100
|
|
438
439
|
|
|
439
440
|
|
|
440
|
-
def
|
|
441
|
+
def get_de_velocity(
|
|
441
442
|
front_position: tuple[NDArray, NDArray],
|
|
442
443
|
back_position: tuple[NDArray, NDArray],
|
|
443
444
|
d: np.ndarray,
|
|
444
445
|
tof: np.ndarray,
|
|
445
|
-
) ->
|
|
446
|
+
) -> NDArray:
|
|
446
447
|
"""
|
|
447
|
-
Determine the
|
|
448
|
-
|
|
449
|
-
The equation is: velocity = ((xf - xb), (yf - yb), d).
|
|
450
|
-
|
|
451
|
-
Further description is available on pages 39 of
|
|
452
|
-
IMAP-Ultra Flight Software Specification document
|
|
453
|
-
(7523-9009_Rev_-.pdf).
|
|
448
|
+
Determine the direct event velocity.
|
|
454
449
|
|
|
455
450
|
Parameters
|
|
456
451
|
----------
|
|
@@ -465,35 +460,30 @@ def get_unit_vector(
|
|
|
465
460
|
|
|
466
461
|
Returns
|
|
467
462
|
-------
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
vhat_y : np.array
|
|
471
|
-
Normalized component of the velocity vector in y direction.
|
|
472
|
-
vhat_z : np.array
|
|
473
|
-
Normalized component of the velocity vector in z direction.
|
|
463
|
+
velocities : np.ndarray
|
|
464
|
+
N x 3 array of velocity components (vx, vy, vz) in km/s.
|
|
474
465
|
"""
|
|
475
466
|
if tof[tof < 0].any():
|
|
476
467
|
logger.info("Negative tof values found.")
|
|
477
468
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
v_z = d / tof
|
|
469
|
+
# distances in .1 mm
|
|
470
|
+
delta_v = np.empty((len(d), 3), dtype=np.float32)
|
|
471
|
+
delta_v[:, 0] = (front_position[0] - back_position[0]) * 0.1
|
|
472
|
+
delta_v[:, 1] = (front_position[1] - back_position[1]) * 0.1
|
|
473
|
+
delta_v[:, 2] = d * 0.1
|
|
484
474
|
|
|
485
|
-
#
|
|
486
|
-
|
|
475
|
+
# Convert from 0.1mm/0.1ns to km/s.
|
|
476
|
+
v_x = delta_v[:, 0] / tof * 1e3
|
|
477
|
+
v_y = delta_v[:, 1] / tof * 1e3
|
|
478
|
+
v_z = delta_v[:, 2] / tof * 1e3
|
|
487
479
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
480
|
+
v_x[tof < 0] = np.nan # used as fillvals
|
|
481
|
+
v_y[tof < 0] = np.nan
|
|
482
|
+
v_z[tof < 0] = np.nan
|
|
491
483
|
|
|
492
|
-
|
|
493
|
-
vhat_y[tof < 0] = np.nan
|
|
494
|
-
vhat_z[tof < 0] = np.nan
|
|
484
|
+
velocities = np.vstack((v_x, v_y, v_z)).T
|
|
495
485
|
|
|
496
|
-
return
|
|
486
|
+
return velocities
|
|
497
487
|
|
|
498
488
|
|
|
499
489
|
def get_ssd_tof(de_dataset: xarray.Dataset, xf: np.ndarray) -> NDArray[np.float64]:
|
|
@@ -545,6 +535,37 @@ def get_ssd_tof(de_dataset: xarray.Dataset, xf: np.ndarray) -> NDArray[np.float6
|
|
|
545
535
|
return np.asarray(tof, dtype=np.float64)
|
|
546
536
|
|
|
547
537
|
|
|
538
|
+
def get_de_energy_kev(v: np.ndarray, species: np.ndarray) -> NDArray:
|
|
539
|
+
"""
|
|
540
|
+
Calculate the direct event energy.
|
|
541
|
+
|
|
542
|
+
Parameters
|
|
543
|
+
----------
|
|
544
|
+
v : np.ndarray
|
|
545
|
+
N x 3 array of velocity components (vx, vy, vz) in km/s.
|
|
546
|
+
species : np.ndarray
|
|
547
|
+
Species of the particle.
|
|
548
|
+
|
|
549
|
+
Returns
|
|
550
|
+
-------
|
|
551
|
+
energy : np.ndarray
|
|
552
|
+
Energy of the direct event in keV.
|
|
553
|
+
"""
|
|
554
|
+
vv = v * 1e3 # convert km/s to m/s
|
|
555
|
+
# Compute the sum of squares.
|
|
556
|
+
v2 = np.sum(vv**2, axis=1)
|
|
557
|
+
|
|
558
|
+
index_hydrogen = np.where(species == "H")
|
|
559
|
+
energy = np.full_like(v2, np.nan)
|
|
560
|
+
|
|
561
|
+
# 1/2 mv^2 in Joules, convert to keV
|
|
562
|
+
energy[index_hydrogen] = (
|
|
563
|
+
0.5 * UltraConstants.MASS_H * v2[index_hydrogen] * UltraConstants.J_KEV
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
return energy
|
|
567
|
+
|
|
568
|
+
|
|
548
569
|
def get_energy_pulse_height(
|
|
549
570
|
stop_type: np.ndarray, energy: np.ndarray, xb: np.ndarray, yb: np.ndarray
|
|
550
571
|
) -> NDArray[np.float64]:
|
|
@@ -728,3 +749,33 @@ def determine_species(tof: np.ndarray, path_length: np.ndarray, type: str) -> ND
|
|
|
728
749
|
] = "H"
|
|
729
750
|
|
|
730
751
|
return species_bin
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def get_de_az_el(v: NDArray) -> tuple[NDArray, NDArray]:
|
|
755
|
+
"""
|
|
756
|
+
Compute azimuth (phi) angles and elevation (theta).
|
|
757
|
+
|
|
758
|
+
Parameters
|
|
759
|
+
----------
|
|
760
|
+
v : np.ndarray
|
|
761
|
+
A NumPy array with shape (n, 3) where each
|
|
762
|
+
row represents a vector
|
|
763
|
+
with x, y, z-components.
|
|
764
|
+
|
|
765
|
+
Returns
|
|
766
|
+
-------
|
|
767
|
+
spherical_coords : np.ndarray
|
|
768
|
+
A NumPy array with shape (n, 3), where each row contains
|
|
769
|
+
the spherical coordinates (r, azimuth, elevation):
|
|
770
|
+
|
|
771
|
+
- azimuth : angle in the xy-plane
|
|
772
|
+
In radians:
|
|
773
|
+
output range=[0, 2*pi].
|
|
774
|
+
- elevation : angle from the xy-plane
|
|
775
|
+
In radians:
|
|
776
|
+
output range=[-pi/2, pi/2].
|
|
777
|
+
"""
|
|
778
|
+
# Compute azimuth (phi) angles and elevation (theta)
|
|
779
|
+
spherical_coords = cartesian_to_spherical(v, degrees=False)
|
|
780
|
+
|
|
781
|
+
return spherical_coords[:, 1], spherical_coords[:, 2]
|
|
@@ -6,7 +6,9 @@ import xarray as xr
|
|
|
6
6
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def calculate_histogram(
|
|
9
|
+
def calculate_histogram(
|
|
10
|
+
histogram_dataset: xr.Dataset, name: str, data_version: str
|
|
11
|
+
) -> xr.Dataset:
|
|
10
12
|
"""
|
|
11
13
|
Create dictionary with defined datatype for Histogram Data.
|
|
12
14
|
|
|
@@ -16,6 +18,8 @@ def calculate_histogram(histogram_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
16
18
|
Dataset containing histogram data.
|
|
17
19
|
name : str
|
|
18
20
|
Name of dataset.
|
|
21
|
+
data_version : str
|
|
22
|
+
Version of the data.
|
|
19
23
|
|
|
20
24
|
Returns
|
|
21
25
|
-------
|
|
@@ -31,6 +35,6 @@ def calculate_histogram(histogram_dataset: xr.Dataset, name: str) -> xr.Dataset:
|
|
|
31
35
|
histogram_dict["epoch"] = epoch
|
|
32
36
|
histogram_dict["sid"] = np.zeros(len(epoch), dtype=np.uint8)
|
|
33
37
|
|
|
34
|
-
dataset = create_dataset(histogram_dict, name, "l1c")
|
|
38
|
+
dataset = create_dataset(histogram_dict, name, "l1c", data_version)
|
|
35
39
|
|
|
36
40
|
return dataset
|