imap-processing 0.7.0__py3-none-any.whl → 0.9.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 -1
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/excel_to_xtce.py +36 -2
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +145 -30
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +36 -36
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +136 -9
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +14 -0
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +63 -1
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +9 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +14 -7
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +577 -235
- imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +326 -0
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +33 -23
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +24 -28
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +1 -0
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +137 -79
- imap_processing/cdf/config/imap_variable_schema.yaml +13 -0
- imap_processing/cdf/imap_cdf_manager.py +31 -27
- imap_processing/cdf/utils.py +3 -5
- imap_processing/cli.py +25 -14
- imap_processing/codice/codice_l1a.py +153 -63
- imap_processing/codice/constants.py +10 -10
- imap_processing/codice/decompress.py +10 -11
- imap_processing/codice/utils.py +1 -0
- imap_processing/glows/l1a/glows_l1a.py +1 -2
- imap_processing/glows/l1b/glows_l1b.py +3 -3
- imap_processing/glows/l1b/glows_l1b_data.py +59 -37
- imap_processing/glows/l2/glows_l2_data.py +123 -0
- imap_processing/hi/l1a/hi_l1a.py +4 -4
- imap_processing/hi/l1a/histogram.py +107 -109
- imap_processing/hi/l1a/science_direct_event.py +92 -225
- imap_processing/hi/l1b/hi_l1b.py +85 -11
- imap_processing/hi/l1c/hi_l1c.py +23 -1
- imap_processing/hi/packet_definitions/TLM_HI_COMBINED_SCI.xml +3994 -0
- imap_processing/hi/utils.py +1 -1
- imap_processing/hit/hit_utils.py +221 -0
- imap_processing/hit/l0/constants.py +118 -0
- imap_processing/hit/l0/decom_hit.py +100 -156
- imap_processing/hit/l1a/hit_l1a.py +170 -184
- imap_processing/hit/l1b/hit_l1b.py +33 -153
- imap_processing/ialirt/l0/process_codicelo.py +153 -0
- imap_processing/ialirt/l0/process_hit.py +5 -5
- imap_processing/ialirt/packet_definitions/ialirt_codicelo.xml +281 -0
- imap_processing/ialirt/process_ephemeris.py +212 -0
- imap_processing/idex/idex_l1a.py +65 -84
- imap_processing/idex/idex_l1b.py +192 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +33 -0
- imap_processing/idex/packet_definitions/idex_packet_definition.xml +97 -595
- imap_processing/lo/l0/decompression_tables/decompression_tables.py +17 -1
- imap_processing/lo/l0/lo_science.py +45 -13
- imap_processing/lo/l1a/lo_l1a.py +76 -8
- imap_processing/lo/packet_definitions/lo_xtce.xml +8344 -1849
- imap_processing/mag/l0/decom_mag.py +4 -3
- imap_processing/mag/l1a/mag_l1a.py +12 -13
- imap_processing/mag/l1a/mag_l1a_data.py +1 -2
- imap_processing/mag/l1b/mag_l1b.py +90 -7
- imap_processing/spice/geometry.py +156 -16
- imap_processing/spice/time.py +144 -2
- imap_processing/swapi/l1/swapi_l1.py +4 -4
- imap_processing/swapi/l2/swapi_l2.py +1 -1
- imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +1535 -446
- imap_processing/swe/l1b/swe_l1b_science.py +8 -8
- imap_processing/swe/l2/swe_l2.py +134 -17
- imap_processing/tests/ccsds/test_data/expected_output.xml +2 -1
- imap_processing/tests/ccsds/test_excel_to_xtce.py +4 -4
- imap_processing/tests/cdf/test_imap_cdf_manager.py +0 -10
- imap_processing/tests/codice/conftest.py +1 -17
- imap_processing/tests/codice/data/imap_codice_l0_raw_20241110_v001.pkts +0 -0
- imap_processing/tests/codice/test_codice_l0.py +8 -2
- imap_processing/tests/codice/test_codice_l1a.py +127 -107
- imap_processing/tests/codice/test_codice_l1b.py +1 -0
- imap_processing/tests/codice/test_decompress.py +7 -7
- imap_processing/tests/conftest.py +100 -58
- imap_processing/tests/glows/conftest.py +6 -0
- imap_processing/tests/glows/test_glows_l1b.py +9 -9
- imap_processing/tests/glows/test_glows_l1b_data.py +9 -9
- imap_processing/tests/hi/test_data/l0/H90_NHK_20241104.bin +0 -0
- imap_processing/tests/hi/test_data/l0/H90_sci_cnt_20241104.bin +0 -0
- imap_processing/tests/hi/test_data/l0/H90_sci_de_20241104.bin +0 -0
- imap_processing/tests/hi/test_data/l1a/imap_hi_l1a_45sensor-de_20250415_v000.cdf +0 -0
- imap_processing/tests/hi/test_hi_l1b.py +73 -3
- imap_processing/tests/hi/test_hi_l1c.py +10 -2
- imap_processing/tests/hi/test_l1a.py +31 -58
- imap_processing/tests/hi/test_science_direct_event.py +58 -0
- imap_processing/tests/hi/test_utils.py +4 -3
- imap_processing/tests/hit/test_data/sci_sample1.ccsds +0 -0
- imap_processing/tests/hit/{test_hit_decom.py → test_decom_hit.py} +95 -36
- imap_processing/tests/hit/test_hit_l1a.py +299 -179
- imap_processing/tests/hit/test_hit_l1b.py +231 -24
- imap_processing/tests/hit/test_hit_utils.py +218 -0
- imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +89 -0
- imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +29 -0
- imap_processing/tests/ialirt/test_data/l0/apid01152.tlm +0 -0
- imap_processing/tests/ialirt/test_data/l0/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/ialirt/unit/test_process_codicelo.py +106 -0
- imap_processing/tests/ialirt/unit/test_process_ephemeris.py +109 -0
- imap_processing/tests/ialirt/unit/test_process_hit.py +9 -6
- imap_processing/tests/idex/conftest.py +2 -2
- imap_processing/tests/idex/imap_idex_l0_raw_20231214_v001.pkts +0 -0
- imap_processing/tests/idex/impact_14_tof_high_data.txt +4444 -4444
- imap_processing/tests/idex/test_idex_l0.py +4 -4
- imap_processing/tests/idex/test_idex_l1a.py +8 -2
- imap_processing/tests/idex/test_idex_l1b.py +126 -0
- imap_processing/tests/lo/test_lo_l1a.py +7 -16
- imap_processing/tests/lo/test_lo_science.py +69 -5
- imap_processing/tests/lo/test_pkts/imap_lo_l0_raw_20240803_v002.pkts +0 -0
- imap_processing/tests/lo/validation_data/Instrument_FM1_T104_R129_20240803_ILO_SCI_DE_dec_DN_with_fills.csv +1999 -0
- imap_processing/tests/mag/imap_mag_l1a_norm-magi_20251017_v001.cdf +0 -0
- imap_processing/tests/mag/test_mag_l1b.py +97 -7
- imap_processing/tests/spice/test_data/imap_ena_sim_metakernel.template +3 -1
- imap_processing/tests/spice/test_geometry.py +115 -9
- imap_processing/tests/spice/test_time.py +135 -6
- imap_processing/tests/swapi/test_swapi_decom.py +75 -69
- imap_processing/tests/swapi/test_swapi_l1.py +4 -4
- imap_processing/tests/swe/conftest.py +33 -0
- imap_processing/tests/swe/l1_validation/swe_l0_unpacked-data_20240510_v001_VALIDATION_L1B_v3.dat +4332 -0
- imap_processing/tests/swe/test_swe_l1b.py +29 -8
- imap_processing/tests/swe/test_swe_l2.py +64 -8
- imap_processing/tests/test_utils.py +2 -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/l1/dps_exposure_helio_45_E12.cdf +0 -0
- imap_processing/tests/ultra/test_data/l1/dps_exposure_helio_45_E24.cdf +0 -0
- imap_processing/tests/ultra/unit/test_de.py +113 -0
- imap_processing/tests/ultra/unit/test_spatial_utils.py +125 -0
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +27 -3
- imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +31 -10
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +55 -35
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +10 -68
- imap_processing/ultra/constants.py +12 -3
- imap_processing/ultra/l1b/de.py +168 -30
- imap_processing/ultra/l1b/ultra_l1b_annotated.py +24 -10
- imap_processing/ultra/l1b/ultra_l1b_extended.py +46 -80
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +60 -144
- imap_processing/ultra/utils/spatial_utils.py +221 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.9.0.dist-info}/METADATA +15 -14
- {imap_processing-0.7.0.dist-info → imap_processing-0.9.0.dist-info}/RECORD +142 -139
- imap_processing/cdf/cdf_attribute_manager.py +0 -322
- imap_processing/cdf/config/shared/default_global_cdf_attrs_schema.yaml +0 -246
- imap_processing/cdf/config/shared/default_variable_cdf_attrs_schema.yaml +0 -466
- imap_processing/hi/l0/decom_hi.py +0 -24
- imap_processing/hi/packet_definitions/hi_packet_definition.xml +0 -482
- imap_processing/hit/l0/data_classes/housekeeping.py +0 -240
- imap_processing/hit/l0/data_classes/science_packet.py +0 -259
- imap_processing/hit/l0/utils/hit_base.py +0 -57
- imap_processing/tests/cdf/shared/default_global_cdf_attrs_schema.yaml +0 -246
- imap_processing/tests/cdf/shared/default_variable_cdf_attrs_schema.yaml +0 -466
- imap_processing/tests/cdf/test_cdf_attribute_manager.py +0 -353
- imap_processing/tests/codice/data/imap_codice_l0_hi-counters-aggregated_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-counters-singles_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-omni_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-pha_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hi-sectored_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_hskp_20100101_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-counters-aggregated_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-counters-singles_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-angular_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-priority_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-species_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-pha_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-angular_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-priority_20240429_v001.pkts +0 -0
- imap_processing/tests/codice/data/imap_codice_l0_lo-sw-species_20240429_v001.pkts +0 -0
- imap_processing/tests/hi/test_decom.py +0 -55
- imap_processing/tests/hi/test_l1a_sci_de.py +0 -72
- imap_processing/tests/idex/imap_idex_l0_raw_20230725_v001.pkts +0 -0
- imap_processing/tests/mag/imap_mag_l1a_burst-magi_20231025_v001.cdf +0 -0
- /imap_processing/{hi/l0/__init__.py → tests/glows/test_glows_l2_data.py} +0 -0
- /imap_processing/tests/hit/test_data/{imap_hit_l0_hk_20100105_v001.pkts → imap_hit_l0_raw_20100105_v001.pkts} +0 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.9.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.9.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.9.0.dist-info}/entry_points.txt +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Tests Extended Raw Events for ULTRA L1b."""
|
|
2
|
+
|
|
3
|
+
from unittest import mock
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from imap_processing.ultra.constants import UltraConstants
|
|
10
|
+
from imap_processing.ultra.l1b.de import calculate_de
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture()
|
|
14
|
+
def df_filt(de_dataset, events_fsw_comparison_theta_0):
|
|
15
|
+
"""Fixture to import test dataset."""
|
|
16
|
+
df = pd.read_csv(events_fsw_comparison_theta_0)
|
|
17
|
+
df_filt = df[df["StartType"] != -1]
|
|
18
|
+
df_filt = df_filt.replace("FILL", 0)
|
|
19
|
+
|
|
20
|
+
return df_filt
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@mock.patch("imap_processing.ultra.l1b.de.get_annotated_particle_velocity")
|
|
24
|
+
def test_calculate_de(mock_get_annotated_particle_velocity, de_dataset, df_filt):
|
|
25
|
+
"""Tests calculate_de function."""
|
|
26
|
+
|
|
27
|
+
# Mock get_annotated_particle_velocity to avoid needing kernels
|
|
28
|
+
def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
|
|
29
|
+
"""
|
|
30
|
+
Mock behavior of get_annotated_particle_velocity.
|
|
31
|
+
|
|
32
|
+
Returns NaN-filled arrays matching the expected output shape.
|
|
33
|
+
"""
|
|
34
|
+
num_events = event_times.size
|
|
35
|
+
return (
|
|
36
|
+
np.full((num_events, 3), np.nan), # sc_velocity
|
|
37
|
+
np.full((num_events, 3), np.nan), # sc_dps_velocity
|
|
38
|
+
np.full((num_events, 3), np.nan), # helio_velocity
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
mock_get_annotated_particle_velocity.side_effect = side_effect_func
|
|
42
|
+
|
|
43
|
+
dataset = calculate_de(de_dataset, "imap_ultra_l1b_45sensor-de")
|
|
44
|
+
|
|
45
|
+
# Front and back positions
|
|
46
|
+
assert np.allclose(dataset["x_front"].data, df_filt["Xf"].astype("float"))
|
|
47
|
+
assert np.allclose(dataset["y_front"], df_filt["Yf"].astype("float"))
|
|
48
|
+
assert np.allclose(dataset["x_back"], df_filt["Xb"].astype("float"))
|
|
49
|
+
assert np.allclose(dataset["y_back"], df_filt["Yb"].astype("float"))
|
|
50
|
+
|
|
51
|
+
# Coincidence positions
|
|
52
|
+
assert np.allclose(dataset["x_coin"], df_filt["Xc"].astype("float"))
|
|
53
|
+
|
|
54
|
+
# Time of flight
|
|
55
|
+
assert np.allclose(dataset["tof_start_stop"], df_filt["TOF"].astype("float"))
|
|
56
|
+
assert np.allclose(dataset["tof_stop_coin"], df_filt["eTOF"].astype("float"))
|
|
57
|
+
assert np.allclose(dataset["tof_corrected"], df_filt["cTOF"].astype("float"))
|
|
58
|
+
|
|
59
|
+
# Distances and path lengths
|
|
60
|
+
assert np.allclose(dataset["front_back_distance"], df_filt["d"].astype("float"))
|
|
61
|
+
assert np.allclose(dataset["path_length"], df_filt["r"].astype("float"))
|
|
62
|
+
|
|
63
|
+
# Coincidence, start, and event types
|
|
64
|
+
assert np.allclose(dataset["coincidence_type"], df_filt["CoinType"].astype("float"))
|
|
65
|
+
assert np.allclose(dataset["start_type"], df_filt["StartType"].astype("float"))
|
|
66
|
+
assert np.allclose(dataset["event_type"], df_filt["StopType"].astype("float"))
|
|
67
|
+
|
|
68
|
+
# Energies and species
|
|
69
|
+
assert np.allclose(dataset["energy"], df_filt["Energy"].astype("float"))
|
|
70
|
+
species_array = dataset["species"][
|
|
71
|
+
np.where(
|
|
72
|
+
(dataset["tof_corrected"] > UltraConstants.CTOF_SPECIES_MIN)
|
|
73
|
+
& (dataset["tof_corrected"] < UltraConstants.CTOF_SPECIES_MAX)
|
|
74
|
+
)[0]
|
|
75
|
+
]
|
|
76
|
+
assert np.all(species_array == "H")
|
|
77
|
+
|
|
78
|
+
# Velocities in various frames
|
|
79
|
+
test_tof = dataset["tof_start_stop"]
|
|
80
|
+
assert np.allclose(
|
|
81
|
+
dataset["vx_ultra"][test_tof > 0],
|
|
82
|
+
-df_filt["vhatX"].astype("float").values[test_tof > 0],
|
|
83
|
+
rtol=1e-2,
|
|
84
|
+
)
|
|
85
|
+
assert np.allclose(
|
|
86
|
+
dataset["vy_ultra"][test_tof > 0],
|
|
87
|
+
-df_filt["vhatY"].astype("float").values[test_tof > 0],
|
|
88
|
+
rtol=1e-2,
|
|
89
|
+
)
|
|
90
|
+
assert np.allclose(
|
|
91
|
+
dataset["vz_ultra"][test_tof > 0],
|
|
92
|
+
-df_filt["vhatZ"].astype("float").values[test_tof > 0],
|
|
93
|
+
rtol=1e-2,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
assert dataset["vx_sc"].shape == (len(de_dataset["epoch"]),)
|
|
97
|
+
assert dataset["vy_sc"].shape == (len(de_dataset["epoch"]),)
|
|
98
|
+
assert dataset["vz_sc"].shape == (len(de_dataset["epoch"]),)
|
|
99
|
+
|
|
100
|
+
assert dataset["vx_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
101
|
+
assert dataset["vy_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
102
|
+
assert dataset["vz_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
103
|
+
|
|
104
|
+
assert dataset["vx_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
105
|
+
assert dataset["vy_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
106
|
+
assert dataset["vz_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
107
|
+
|
|
108
|
+
# Event efficiency
|
|
109
|
+
assert np.allclose(
|
|
110
|
+
dataset["event_efficiency"],
|
|
111
|
+
np.full(len(de_dataset["epoch"]), np.nan),
|
|
112
|
+
equal_nan=True,
|
|
113
|
+
)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Test creation of solid angle map."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import numpy.testing as npt
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from imap_processing.ultra.utils import spatial_utils
|
|
8
|
+
|
|
9
|
+
# Parameterize with spacings (degrees here):
|
|
10
|
+
valid_spacings = [0.1, 0.25, 0.5, 1, 5, 10, 20]
|
|
11
|
+
invalid_spacings = [0, -1, 11]
|
|
12
|
+
invalid_spacings_match_str = [
|
|
13
|
+
"Spacing must be positive valued, non-zero.",
|
|
14
|
+
"Spacing must be positive valued, non-zero.",
|
|
15
|
+
"Spacing must divide evenly into pi radians.",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_build_spatial_bins():
|
|
20
|
+
"""Tests build_spatial_bins function."""
|
|
21
|
+
az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
|
|
22
|
+
spatial_utils.build_spatial_bins()
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
assert az_bin_edges[0] == 0
|
|
26
|
+
assert az_bin_edges[-1] == 360
|
|
27
|
+
assert len(az_bin_edges) == 721
|
|
28
|
+
|
|
29
|
+
assert el_bin_edges[0] == -90
|
|
30
|
+
assert el_bin_edges[-1] == 90
|
|
31
|
+
assert len(el_bin_edges) == 361
|
|
32
|
+
|
|
33
|
+
assert len(az_bin_midpoints) == 720
|
|
34
|
+
np.testing.assert_allclose(az_bin_midpoints[0], 0.25, atol=1e-4)
|
|
35
|
+
np.testing.assert_allclose(az_bin_midpoints[-1], 359.75, atol=1e-4)
|
|
36
|
+
|
|
37
|
+
assert len(el_bin_midpoints) == 360
|
|
38
|
+
np.testing.assert_allclose(el_bin_midpoints[0], -89.75, atol=1e-4)
|
|
39
|
+
np.testing.assert_allclose(el_bin_midpoints[-1], 89.75, atol=1e-4)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.mark.parametrize("spacing", valid_spacings)
|
|
43
|
+
def test_build_solid_angle_map(spacing):
|
|
44
|
+
"""Test build_solid_angle_map function."""
|
|
45
|
+
solid_angle_map_steradians = spatial_utils.build_solid_angle_map(
|
|
46
|
+
spacing, input_degrees=True, output_degrees=False
|
|
47
|
+
)
|
|
48
|
+
assert np.isclose(np.sum(solid_angle_map_steradians), 4 * np.pi, atol=0, rtol=1e-9)
|
|
49
|
+
|
|
50
|
+
solid_angle_map_sqdeg = spatial_utils.build_solid_angle_map(
|
|
51
|
+
np.deg2rad(spacing), input_degrees=False, output_degrees=True
|
|
52
|
+
)
|
|
53
|
+
assert np.isclose(
|
|
54
|
+
np.sum(solid_angle_map_sqdeg), 4 * np.pi * (180 / np.pi) ** 2, atol=0, rtol=1e-9
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.mark.parametrize(
|
|
59
|
+
"spacing, match_str", zip(invalid_spacings, invalid_spacings_match_str)
|
|
60
|
+
)
|
|
61
|
+
def test_build_solid_angle_map_invalid_spacing(spacing, match_str):
|
|
62
|
+
"""Test build_solid_angle_map function raises error for invalid spacing."""
|
|
63
|
+
with pytest.raises(ValueError, match=match_str):
|
|
64
|
+
_ = spatial_utils.build_solid_angle_map(
|
|
65
|
+
spacing, input_degrees=True, output_degrees=False
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.mark.parametrize("spacing", valid_spacings)
|
|
70
|
+
def test_build_az_el_grid(spacing):
|
|
71
|
+
"""Test build_az_el_grid function."""
|
|
72
|
+
az_range, el_range, az_grid, el_grid = spatial_utils.build_az_el_grid(
|
|
73
|
+
spacing=spacing,
|
|
74
|
+
input_degrees=True,
|
|
75
|
+
output_degrees=True,
|
|
76
|
+
centered_azimuth=False,
|
|
77
|
+
centered_elevation=True,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Size checks
|
|
81
|
+
assert az_range.size == int(360 / spacing)
|
|
82
|
+
assert el_range.size == int(180 / spacing)
|
|
83
|
+
assert az_range.size == az_grid.shape[1]
|
|
84
|
+
assert el_range.size == el_grid.shape[0]
|
|
85
|
+
|
|
86
|
+
# Check grid values
|
|
87
|
+
expected_az_range = np.arange((spacing / 2), 360 + (spacing / 2), spacing)
|
|
88
|
+
expected_el_range = np.arange(-90 + (spacing / 2), 90 + (spacing / 2), spacing)[
|
|
89
|
+
::-1
|
|
90
|
+
] # Note el order is reversed
|
|
91
|
+
|
|
92
|
+
npt.assert_allclose(az_range, expected_az_range, atol=1e-12)
|
|
93
|
+
npt.assert_allclose(el_range, expected_el_range, atol=1e-12)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_rewrap_even_spaced_el_az_grid_1d():
|
|
97
|
+
"""Test rewrap_even_spaced_el_az_grid function, without extra axis."""
|
|
98
|
+
orig_shape = (180 * 12, 360 * 12)
|
|
99
|
+
orig_grid = np.fromfunction(lambda i, j: i**2 + j, orig_shape, dtype=int)
|
|
100
|
+
raveled_values = orig_grid.ravel(order="F")
|
|
101
|
+
rewrapped_grid_infer_shape = spatial_utils.rewrap_even_spaced_el_az_grid(
|
|
102
|
+
raveled_values
|
|
103
|
+
)
|
|
104
|
+
rewrapped_grid_known_shape = spatial_utils.rewrap_even_spaced_el_az_grid(
|
|
105
|
+
raveled_values, shape=orig_shape
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
assert np.array_equal(rewrapped_grid_infer_shape, orig_grid)
|
|
109
|
+
assert np.array_equal(rewrapped_grid_known_shape, orig_grid)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_rewrap_even_spaced_el_az_grid_2d():
|
|
113
|
+
"""Test rewrap_even_spaced_el_az_grid function, with extra axis."""
|
|
114
|
+
orig_shape = (180 * 12, 360 * 12, 5)
|
|
115
|
+
orig_grid = np.fromfunction(lambda i, j, k: i**2 + j + k, orig_shape, dtype=int)
|
|
116
|
+
raveled_values = orig_grid.reshape(-1, 5, order="F")
|
|
117
|
+
rewrapped_grid_infer_shape = spatial_utils.rewrap_even_spaced_el_az_grid(
|
|
118
|
+
raveled_values, extra_axis=True
|
|
119
|
+
)
|
|
120
|
+
rewrapped_grid_known_shape = spatial_utils.rewrap_even_spaced_el_az_grid(
|
|
121
|
+
raveled_values, shape=orig_shape, extra_axis=True
|
|
122
|
+
)
|
|
123
|
+
assert raveled_values.shape == (180 * 12 * 360 * 12, 5)
|
|
124
|
+
assert np.array_equal(rewrapped_grid_infer_shape, orig_grid)
|
|
125
|
+
assert np.array_equal(rewrapped_grid_known_shape, orig_grid)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
import pytest
|
|
3
5
|
import xarray as xr
|
|
@@ -73,7 +75,7 @@ def test_create_dataset(mock_data_l1b_dict):
|
|
|
73
75
|
assert "epoch" in dataset.coords
|
|
74
76
|
assert dataset.coords["epoch"].dtype == "datetime64[ns]"
|
|
75
77
|
assert dataset.attrs["Logical_source"] == "imap_ultra_l1b_45sensor-de"
|
|
76
|
-
assert dataset["x_front"].attrs["UNITS"] == "mm"
|
|
78
|
+
assert dataset["x_front"].attrs["UNITS"] == "mm / 100"
|
|
77
79
|
np.testing.assert_array_equal(dataset["x_front"], np.zeros(3))
|
|
78
80
|
|
|
79
81
|
|
|
@@ -99,9 +101,31 @@ def test_ultra_l1b_rates(mock_data_l1a_rates_dict):
|
|
|
99
101
|
)
|
|
100
102
|
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
@pytest.mark.external_kernel()
|
|
105
|
+
@pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
|
|
106
|
+
@mock.patch("imap_processing.ultra.l1b.de.get_annotated_particle_velocity")
|
|
107
|
+
def test_ultra_l1b_de(mock_get_annotated_particle_velocity, de_dataset):
|
|
103
108
|
"""Tests that L1b data is created."""
|
|
104
|
-
|
|
109
|
+
data_dict = {}
|
|
110
|
+
data_dict[de_dataset.attrs["Logical_source"]] = de_dataset
|
|
111
|
+
data_dict["imap_ultra_l1a_45sensor-aux"] = de_dataset
|
|
112
|
+
|
|
113
|
+
# Mock get_annotated_particle_velocity to avoid needing kernels
|
|
114
|
+
def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
|
|
115
|
+
"""
|
|
116
|
+
Mock behavior of get_annotated_particle_velocity.
|
|
117
|
+
|
|
118
|
+
Returns NaN-filled arrays matching the expected output shape.
|
|
119
|
+
"""
|
|
120
|
+
num_events = event_times.size
|
|
121
|
+
return (
|
|
122
|
+
np.full((num_events, 3), np.nan), # sc_velocity
|
|
123
|
+
np.full((num_events, 3), np.nan), # sc_dps_velocity
|
|
124
|
+
np.full((num_events, 3), np.nan), # helio_velocity
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
mock_get_annotated_particle_velocity.side_effect = side_effect_func
|
|
128
|
+
output_datasets = ultra_l1b(data_dict, data_version="001")
|
|
105
129
|
|
|
106
130
|
assert len(output_datasets) == 1
|
|
107
131
|
assert output_datasets[0].attrs["Logical_source"] == "imap_ultra_l1b_45sensor-de"
|
|
@@ -5,7 +5,9 @@ import pytest
|
|
|
5
5
|
import spiceypy as spice
|
|
6
6
|
|
|
7
7
|
from imap_processing.spice.geometry import SpiceFrame
|
|
8
|
-
from imap_processing.ultra.l1b.ultra_l1b_annotated import
|
|
8
|
+
from imap_processing.ultra.l1b.ultra_l1b_annotated import (
|
|
9
|
+
get_annotated_particle_velocity,
|
|
10
|
+
)
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
@pytest.fixture()
|
|
@@ -45,18 +47,37 @@ def test_get_particle_velocity(spice_test_data_path, kernels):
|
|
|
45
47
|
times = np.array([start])
|
|
46
48
|
instrument_velocity = np.array([[41.18609, -471.24467, -832.8784]])
|
|
47
49
|
|
|
48
|
-
sc_velocity_45, helio_velocity_45 =
|
|
49
|
-
|
|
50
|
+
sc_velocity_45, sc_dps_velocity_45, helio_velocity_45 = (
|
|
51
|
+
get_annotated_particle_velocity(
|
|
52
|
+
times,
|
|
53
|
+
instrument_velocity,
|
|
54
|
+
SpiceFrame.IMAP_ULTRA_45,
|
|
55
|
+
SpiceFrame.IMAP_DPS,
|
|
56
|
+
SpiceFrame.IMAP_SPACECRAFT,
|
|
57
|
+
)
|
|
50
58
|
)
|
|
51
|
-
sc_velocity_90, helio_velocity_90 =
|
|
52
|
-
|
|
59
|
+
sc_velocity_90, sc_dps_velocity_90, helio_velocity_90 = (
|
|
60
|
+
get_annotated_particle_velocity(
|
|
61
|
+
times,
|
|
62
|
+
instrument_velocity,
|
|
63
|
+
SpiceFrame.IMAP_ULTRA_90,
|
|
64
|
+
SpiceFrame.IMAP_DPS,
|
|
65
|
+
SpiceFrame.IMAP_SPACECRAFT,
|
|
66
|
+
)
|
|
53
67
|
)
|
|
54
68
|
|
|
55
69
|
# Compute the magnitude of the velocity vectors in both frames
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
magnitude_sc_45 = np.linalg.norm(sc_velocity_45)
|
|
71
|
+
magnitude_sc_90 = np.linalg.norm(sc_velocity_90)
|
|
72
|
+
magnitude_dps_45 = np.linalg.norm(sc_dps_velocity_45)
|
|
73
|
+
magnitude_dps_90 = np.linalg.norm(sc_dps_velocity_90)
|
|
58
74
|
state, lt = spice.spkezr("IMAP", times, "IMAP_DPS", "NONE", "SUN")
|
|
59
75
|
|
|
60
|
-
assert np.allclose(
|
|
61
|
-
assert np.
|
|
62
|
-
assert np.array_equal(
|
|
76
|
+
assert np.allclose(magnitude_sc_45, magnitude_sc_90, atol=1e-6)
|
|
77
|
+
assert np.allclose(magnitude_dps_45, magnitude_dps_90, atol=1e-6)
|
|
78
|
+
assert np.array_equal(
|
|
79
|
+
(helio_velocity_45 - state[0][3:6]).flatten(), sc_dps_velocity_45
|
|
80
|
+
)
|
|
81
|
+
assert np.array_equal(
|
|
82
|
+
(helio_velocity_90 - state[0][3:6]).flatten(), sc_dps_velocity_90
|
|
83
|
+
)
|
|
@@ -4,24 +4,24 @@ import numpy as np
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
+
from imap_processing.ultra.constants import UltraConstants
|
|
7
8
|
from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
8
9
|
CoinType,
|
|
9
10
|
StartType,
|
|
10
11
|
StopType,
|
|
11
12
|
calculate_etof_xc,
|
|
12
|
-
|
|
13
|
-
determine_species_ssd,
|
|
13
|
+
determine_species,
|
|
14
14
|
get_coincidence_positions,
|
|
15
15
|
get_ctof,
|
|
16
16
|
get_energy_pulse_height,
|
|
17
17
|
get_energy_ssd,
|
|
18
18
|
get_front_x_position,
|
|
19
19
|
get_front_y_position,
|
|
20
|
-
get_particle_velocity,
|
|
21
20
|
get_path_length,
|
|
22
21
|
get_ph_tof_and_back_positions,
|
|
23
22
|
get_ssd_back_position_and_tof_offset,
|
|
24
23
|
get_ssd_tof,
|
|
24
|
+
get_unit_vector,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
@@ -213,8 +213,8 @@ def test_calculate_etof_xc(de_dataset, yf_fixture):
|
|
|
213
213
|
)
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
def
|
|
217
|
-
"""Tests
|
|
216
|
+
def test_get_unit_vector(de_dataset, yf_fixture):
|
|
217
|
+
"""Tests get_unit_vector function."""
|
|
218
218
|
df_filt, _, _ = yf_fixture
|
|
219
219
|
|
|
220
220
|
ph_indices = np.nonzero(
|
|
@@ -229,7 +229,7 @@ def test_get_particle_velocity(de_dataset, yf_fixture):
|
|
|
229
229
|
test_d = ph_rows["d"].astype("float").values
|
|
230
230
|
test_tof = ph_rows["TOF"].astype("float").values
|
|
231
231
|
|
|
232
|
-
vhat_x, vhat_y, vhat_z =
|
|
232
|
+
vhat_x, vhat_y, vhat_z = get_unit_vector(
|
|
233
233
|
(test_xf, test_yf),
|
|
234
234
|
(test_xb, test_yb),
|
|
235
235
|
test_d,
|
|
@@ -254,7 +254,7 @@ def test_get_particle_velocity(de_dataset, yf_fixture):
|
|
|
254
254
|
def test_get_ssd_tof(de_dataset, yf_fixture):
|
|
255
255
|
"""Tests get_ssd_tof function."""
|
|
256
256
|
df_filt, _, _ = yf_fixture
|
|
257
|
-
df_ssd = df_filt[df_filt["StopType"]
|
|
257
|
+
df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
|
|
258
258
|
test_xf = df_filt["Xf"].astype("float").values
|
|
259
259
|
|
|
260
260
|
ssd_tof = get_ssd_tof(de_dataset, test_xf)
|
|
@@ -267,7 +267,7 @@ def test_get_ssd_tof(de_dataset, yf_fixture):
|
|
|
267
267
|
def test_get_energy_ssd(de_dataset, yf_fixture):
|
|
268
268
|
"""Tests get_energy_ssd function."""
|
|
269
269
|
df_filt, _, _ = yf_fixture
|
|
270
|
-
df_ssd = df_filt[df_filt["StopType"]
|
|
270
|
+
df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
|
|
271
271
|
_, _, ssd_number = get_ssd_back_position_and_tof_offset(de_dataset)
|
|
272
272
|
energy = get_energy_ssd(de_dataset, ssd_number)
|
|
273
273
|
test_energy = df_ssd["Energy"].astype("float")
|
|
@@ -278,7 +278,7 @@ def test_get_energy_ssd(de_dataset, yf_fixture):
|
|
|
278
278
|
def test_get_energy_pulse_height(de_dataset, yf_fixture):
|
|
279
279
|
"""Tests get_energy_ssd function."""
|
|
280
280
|
df_filt, _, _ = yf_fixture
|
|
281
|
-
df_ph = df_filt[df_filt["StopType"]
|
|
281
|
+
df_ph = df_filt[np.isin(df_filt["StopType"], [StopType.PH.value])]
|
|
282
282
|
ph_indices = np.nonzero(
|
|
283
283
|
np.isin(de_dataset["STOP_TYPE"], [StopType.Top.value, StopType.Bottom.value])
|
|
284
284
|
)[0]
|
|
@@ -297,46 +297,66 @@ def test_get_energy_pulse_height(de_dataset, yf_fixture):
|
|
|
297
297
|
def test_get_ctof(yf_fixture):
|
|
298
298
|
"""Tests get_ctof function."""
|
|
299
299
|
df_filt, _, _ = yf_fixture
|
|
300
|
+
df_filt = df_filt[df_filt["eTOF"].astype("str") != "FILL"]
|
|
301
|
+
df_filt = df_filt[df_filt["cTOF"].astype("float") > 0]
|
|
300
302
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
]
|
|
303
|
+
df_ph = df_filt[np.isin(df_filt["StopType"], [StopType.PH.value])]
|
|
304
|
+
df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
|
|
304
305
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
ph_ctof, ph_magnitude_v = get_ctof(
|
|
307
|
+
df_ph["TOF"].astype("float").to_numpy(),
|
|
308
|
+
df_ph["r"].astype("float").to_numpy(),
|
|
309
|
+
"PH",
|
|
308
310
|
)
|
|
309
311
|
|
|
312
|
+
ssd_ctof, ssd_magnitude_v = get_ctof(
|
|
313
|
+
df_ssd["TOF"].astype("float").to_numpy(),
|
|
314
|
+
df_ssd["r"].astype("float").to_numpy(),
|
|
315
|
+
"SSD",
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
np.testing.assert_allclose(
|
|
319
|
+
ph_ctof, df_ph["cTOF"].astype("float"), atol=1e-05, rtol=0
|
|
320
|
+
)
|
|
321
|
+
np.testing.assert_allclose(
|
|
322
|
+
ssd_ctof, df_ssd["cTOF"].astype("float"), atol=1e-05, rtol=0
|
|
323
|
+
)
|
|
310
324
|
np.testing.assert_allclose(
|
|
311
|
-
|
|
325
|
+
ph_magnitude_v, df_ph["vmag"].astype("float"), atol=1e-01, rtol=0
|
|
326
|
+
)
|
|
327
|
+
np.testing.assert_allclose(
|
|
328
|
+
ssd_magnitude_v, df_ssd["vmag"].astype("float"), atol=1e-01, rtol=0
|
|
312
329
|
)
|
|
313
330
|
|
|
314
331
|
|
|
315
|
-
def
|
|
316
|
-
"""Tests
|
|
332
|
+
def test_determine_species(yf_fixture):
|
|
333
|
+
"""Tests determine_species function."""
|
|
317
334
|
df_filt, _, _ = yf_fixture
|
|
318
|
-
df_ph = df_filt[df_filt["StopType"]
|
|
335
|
+
df_ph = df_filt[np.isin(df_filt["StopType"], [StopType.PH.value])]
|
|
336
|
+
df_ssd = df_filt[np.isin(df_filt["StopType"], [StopType.SSD.value])]
|
|
319
337
|
|
|
320
|
-
|
|
321
|
-
df_ph["Energy"].astype("float").to_numpy(),
|
|
338
|
+
species_bin_ph = determine_species(
|
|
322
339
|
df_ph["TOF"].astype("float").to_numpy(),
|
|
323
340
|
df_ph["r"].astype("float").to_numpy(),
|
|
341
|
+
"PH",
|
|
324
342
|
)
|
|
325
|
-
|
|
326
|
-
# TODO: add in bin values.
|
|
327
|
-
np.testing.assert_allclose(bin, np.zeros(len(bin)), atol=1e-05, rtol=0)
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
def test_determine_species_ssd(yf_fixture):
|
|
331
|
-
"""Tests determine_species_ssd function."""
|
|
332
|
-
df_filt, _, _ = yf_fixture
|
|
333
|
-
df_ssd = df_filt[df_filt["StopType"].isin(StopType.SSD.value)]
|
|
334
|
-
|
|
335
|
-
bin = determine_species_ssd(
|
|
336
|
-
df_ssd["Energy"].astype("float").to_numpy(),
|
|
343
|
+
species_bin_ssd = determine_species(
|
|
337
344
|
df_ssd["TOF"].astype("float").to_numpy(),
|
|
338
345
|
df_ssd["r"].astype("float").to_numpy(),
|
|
346
|
+
"SSD",
|
|
339
347
|
)
|
|
340
348
|
|
|
341
|
-
|
|
342
|
-
|
|
349
|
+
h_indices_ph = np.where(species_bin_ph == "H")[0]
|
|
350
|
+
ctof_indices_ph = np.where(
|
|
351
|
+
(df_ph["cTOF"].astype("float") > UltraConstants.CTOF_SPECIES_MIN)
|
|
352
|
+
& (df_ph["cTOF"].astype("float") < UltraConstants.CTOF_SPECIES_MAX)
|
|
353
|
+
)[0]
|
|
354
|
+
|
|
355
|
+
h_indices_ssd = np.where(species_bin_ssd == "H")[0]
|
|
356
|
+
ctof_indices_ssd = np.where(
|
|
357
|
+
(df_ssd["cTOF"].astype("float") > UltraConstants.CTOF_SPECIES_MIN)
|
|
358
|
+
& (df_ssd["cTOF"].astype("float") < UltraConstants.CTOF_SPECIES_MAX)
|
|
359
|
+
)[0]
|
|
360
|
+
|
|
361
|
+
np.testing.assert_array_equal(h_indices_ph, ctof_indices_ph)
|
|
362
|
+
np.testing.assert_array_equal(h_indices_ssd, ctof_indices_ssd)
|
|
@@ -3,19 +3,17 @@
|
|
|
3
3
|
import cdflib
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pytest
|
|
6
|
-
import spiceypy as spice
|
|
7
6
|
from cdflib import CDF
|
|
8
7
|
|
|
9
8
|
from imap_processing import imap_module_directory
|
|
10
9
|
from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
|
|
11
10
|
build_energy_bins,
|
|
12
|
-
build_spatial_bins,
|
|
13
|
-
cartesian_to_spherical,
|
|
14
11
|
get_helio_exposure_times,
|
|
15
12
|
get_histogram,
|
|
16
13
|
get_pointing_frame_exposure_times,
|
|
17
14
|
get_pointing_frame_sensitivity,
|
|
18
15
|
)
|
|
16
|
+
from imap_processing.ultra.utils.spatial_utils import build_spatial_bins
|
|
19
17
|
|
|
20
18
|
BASE_PATH = imap_module_directory / "ultra" / "lookup_tables"
|
|
21
19
|
|
|
@@ -32,33 +30,15 @@ def test_data():
|
|
|
32
30
|
return v, energy
|
|
33
31
|
|
|
34
32
|
|
|
35
|
-
@pytest.fixture()
|
|
36
|
-
def kernels(spice_test_data_path):
|
|
37
|
-
"""List SPICE kernels."""
|
|
38
|
-
required_kernels = [
|
|
39
|
-
"imap_science_0001.tf",
|
|
40
|
-
"imap_sclk_0000.tsc",
|
|
41
|
-
"sim_1yr_imap_attitude.bc",
|
|
42
|
-
"imap_wkcp.tf",
|
|
43
|
-
"naif0012.tls",
|
|
44
|
-
"sim_1yr_imap_pointing_frame.bc",
|
|
45
|
-
"de440s.bsp",
|
|
46
|
-
"imap_spk_demo.bsp",
|
|
47
|
-
]
|
|
48
|
-
kernels = [str(spice_test_data_path / kernel) for kernel in required_kernels]
|
|
49
|
-
|
|
50
|
-
return kernels
|
|
51
|
-
|
|
52
|
-
|
|
53
33
|
def test_build_energy_bins():
|
|
54
34
|
"""Tests build_energy_bins function."""
|
|
55
35
|
energy_bin_edges, energy_midpoints = build_energy_bins()
|
|
56
|
-
energy_bin_start =
|
|
57
|
-
energy_bin_end =
|
|
36
|
+
energy_bin_start = [interval[0] for interval in energy_bin_edges]
|
|
37
|
+
energy_bin_end = [interval[1] for interval in energy_bin_edges]
|
|
58
38
|
|
|
59
39
|
assert energy_bin_start[0] == 0
|
|
60
40
|
assert energy_bin_start[1] == 3.385
|
|
61
|
-
assert len(energy_bin_edges) ==
|
|
41
|
+
assert len(energy_bin_edges) == 24
|
|
62
42
|
assert energy_midpoints[0] == (energy_bin_start[0] + energy_bin_end[0]) / 2
|
|
63
43
|
|
|
64
44
|
# Comparison to expected values.
|
|
@@ -67,44 +47,6 @@ def test_build_energy_bins():
|
|
|
67
47
|
np.testing.assert_allclose(energy_bin_end[-1], 341.989, atol=1e-4)
|
|
68
48
|
|
|
69
49
|
|
|
70
|
-
def test_build_spatial_bins():
|
|
71
|
-
"""Tests build_spatial_bins function."""
|
|
72
|
-
az_bin_edges, el_bin_edges, az_bin_midpoints, el_bin_midpoints = (
|
|
73
|
-
build_spatial_bins()
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
assert az_bin_edges[0] == 0
|
|
77
|
-
assert az_bin_edges[-1] == 360
|
|
78
|
-
assert len(az_bin_edges) == 721
|
|
79
|
-
|
|
80
|
-
assert el_bin_edges[0] == -90
|
|
81
|
-
assert el_bin_edges[-1] == 90
|
|
82
|
-
assert len(el_bin_edges) == 361
|
|
83
|
-
|
|
84
|
-
assert len(az_bin_midpoints) == 720
|
|
85
|
-
np.testing.assert_allclose(az_bin_midpoints[0], 0.25, atol=1e-4)
|
|
86
|
-
np.testing.assert_allclose(az_bin_midpoints[-1], 359.75, atol=1e-4)
|
|
87
|
-
|
|
88
|
-
assert len(el_bin_midpoints) == 360
|
|
89
|
-
np.testing.assert_allclose(el_bin_midpoints[0], -89.75, atol=1e-4)
|
|
90
|
-
np.testing.assert_allclose(el_bin_midpoints[-1], 89.75, atol=1e-4)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def test_cartesian_to_spherical(test_data):
|
|
94
|
-
"""Tests cartesian_to_spherical function."""
|
|
95
|
-
v, _ = test_data
|
|
96
|
-
|
|
97
|
-
az_sc, el_sc, r = cartesian_to_spherical(v)
|
|
98
|
-
|
|
99
|
-
# MATLAB code outputs:
|
|
100
|
-
np.testing.assert_allclose(
|
|
101
|
-
np.unique(np.radians(az_sc)), np.array([1.31300, 2.34891]), atol=1e-05, rtol=0
|
|
102
|
-
)
|
|
103
|
-
np.testing.assert_allclose(
|
|
104
|
-
np.unique(np.radians(el_sc)), np.array([-0.88901, -0.70136]), atol=1e-05, rtol=0
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
50
|
def test_get_histogram(test_data):
|
|
109
51
|
"""Tests get_histogram function."""
|
|
110
52
|
v, energy = test_data
|
|
@@ -119,7 +61,7 @@ def test_get_histogram(test_data):
|
|
|
119
61
|
assert hist.shape == (
|
|
120
62
|
len(az_bin_edges) - 1,
|
|
121
63
|
len(el_bin_edges) - 1,
|
|
122
|
-
len(energy_bin_edges)
|
|
64
|
+
len(energy_bin_edges),
|
|
123
65
|
)
|
|
124
66
|
|
|
125
67
|
|
|
@@ -143,10 +85,10 @@ def test_get_pointing_frame_exposure_times():
|
|
|
143
85
|
|
|
144
86
|
|
|
145
87
|
@pytest.mark.external_kernel()
|
|
146
|
-
|
|
88
|
+
@pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
|
|
89
|
+
def test_get_helio_exposure_times():
|
|
147
90
|
"""Tests get_helio_exposure_times function."""
|
|
148
91
|
|
|
149
|
-
spice.furnsh(kernels)
|
|
150
92
|
constant_exposure = BASE_PATH / "dps_grid45_compressed.cdf"
|
|
151
93
|
start_time = 829485054.185627
|
|
152
94
|
end_time = 829567884.185627
|
|
@@ -185,9 +127,9 @@ def test_et_helio_exposure_times(kernels):
|
|
|
185
127
|
transposed_exposure = np.transpose(exposure_data, (2, 1, 0))
|
|
186
128
|
exposures.append(transposed_exposure)
|
|
187
129
|
|
|
188
|
-
np.array_equal(exposures[0], exposure_3d[:, :, 0])
|
|
189
|
-
np.array_equal(exposures[1], exposure_3d[:, :,
|
|
190
|
-
np.array_equal(exposures[2], exposure_3d[:, :,
|
|
130
|
+
assert np.array_equal(np.squeeze(exposures[0]), exposure_3d[:, :, 0])
|
|
131
|
+
assert np.array_equal(np.squeeze(exposures[1]), exposure_3d[:, :, 11])
|
|
132
|
+
assert np.array_equal(np.squeeze(exposures[2]), exposure_3d[:, :, 23])
|
|
191
133
|
|
|
192
134
|
|
|
193
135
|
def test_get_pointing_frame_sensitivity():
|
|
@@ -52,13 +52,22 @@ class UltraConstants:
|
|
|
52
52
|
DF: float = 3.39 # Distance from slit to foil [mm]
|
|
53
53
|
|
|
54
54
|
# Derived constants
|
|
55
|
-
|
|
55
|
+
DMIN_PH_CTOF: float = (
|
|
56
56
|
Z_DS - (2**0.5) * DF
|
|
57
57
|
) # Minimum distance between front and back detectors [mm]
|
|
58
|
-
DMIN_SSD_CTOF: float = (
|
|
59
|
-
|
|
58
|
+
DMIN_SSD_CTOF: float = (DMIN_PH_CTOF**2) / (
|
|
59
|
+
DMIN_PH_CTOF - Z_DSTOP
|
|
60
60
|
) # SSD-specific correction to DMIN [mm]
|
|
61
61
|
|
|
62
62
|
# Conversion factors
|
|
63
63
|
KEV_J = 1.602180000000000e-16 # 1.6021766339999e-16 # keV to joules
|
|
64
64
|
MASS_H = 1.6735575e-27 # Mass of a hydrogen atom in kilograms.
|
|
65
|
+
|
|
66
|
+
# Energy bin constants
|
|
67
|
+
ALPHA = 0.2 # deltaE/E
|
|
68
|
+
ENERGY_START = 3.385 # energy start for the Ultra grids
|
|
69
|
+
N_BINS = 23 # number of energy bins
|
|
70
|
+
|
|
71
|
+
# Constants for species determination based on ctof range.
|
|
72
|
+
CTOF_SPECIES_MIN = 50
|
|
73
|
+
CTOF_SPECIES_MAX = 200
|