imap-processing 0.7.0__py3-none-any.whl → 0.8.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 +34 -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 +36 -8
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +9 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +7 -7
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +32 -33
- 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 +133 -78
- imap_processing/cdf/config/imap_variable_schema.yaml +13 -0
- imap_processing/cdf/imap_cdf_manager.py +31 -27
- imap_processing/cli.py +12 -10
- imap_processing/codice/codice_l1a.py +151 -61
- imap_processing/codice/constants.py +1 -1
- imap_processing/codice/decompress.py +4 -9
- imap_processing/codice/utils.py +1 -0
- 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/histogram.py +1 -1
- imap_processing/hi/l1a/science_direct_event.py +1 -1
- imap_processing/hi/l1b/hi_l1b.py +85 -11
- imap_processing/hi/l1c/hi_l1c.py +23 -1
- 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 +186 -153
- imap_processing/hit/l1a/hit_l1a.py +20 -175
- imap_processing/hit/l1b/hit_l1b.py +33 -153
- imap_processing/idex/idex_l1a.py +10 -9
- imap_processing/lo/l0/decompression_tables/decompression_tables.py +1 -1
- imap_processing/lo/l0/lo_science.py +1 -1
- imap_processing/lo/packet_definitions/lo_xtce.xml +1 -3296
- imap_processing/mag/l0/decom_mag.py +4 -3
- imap_processing/mag/l1a/mag_l1a.py +11 -11
- imap_processing/mag/l1b/mag_l1b.py +89 -7
- imap_processing/spice/geometry.py +126 -4
- imap_processing/swapi/l1/swapi_l1.py +1 -1
- imap_processing/swapi/l2/swapi_l2.py +1 -1
- imap_processing/swe/l1b/swe_l1b_science.py +8 -8
- imap_processing/tests/ccsds/test_data/expected_output.xml +1 -0
- 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 +54 -15
- 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/glows/test_glows_l2_data.py +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 +71 -1
- imap_processing/tests/hi/test_hi_l1c.py +10 -2
- imap_processing/tests/hi/test_utils.py +4 -3
- imap_processing/tests/hit/{test_hit_decom.py → test_decom_hit.py} +84 -35
- imap_processing/tests/hit/test_hit_l1a.py +2 -197
- imap_processing/tests/hit/test_hit_l1b.py +156 -25
- imap_processing/tests/hit/test_hit_utils.py +218 -0
- imap_processing/tests/idex/conftest.py +1 -1
- 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 +3 -3
- imap_processing/tests/idex/test_idex_l1a.py +1 -1
- imap_processing/tests/lo/test_lo_science.py +2 -2
- imap_processing/tests/mag/imap_mag_l1a_norm-magi_20251017_v001.cdf +0 -0
- imap_processing/tests/mag/test_mag_l1b.py +59 -3
- imap_processing/tests/spice/test_data/imap_ena_sim_metakernel.template +3 -1
- imap_processing/tests/spice/test_geometry.py +84 -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/test_utils.py +1 -1
- 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 +108 -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 +21 -11
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +9 -44
- imap_processing/ultra/constants.py +8 -3
- imap_processing/ultra/l1b/de.py +174 -30
- imap_processing/ultra/l1b/ultra_l1b_annotated.py +24 -10
- imap_processing/ultra/l1b/ultra_l1b_extended.py +21 -14
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +70 -119
- {imap_processing-0.7.0.dist-info → imap_processing-0.8.0.dist-info}/METADATA +15 -14
- {imap_processing-0.7.0.dist-info → imap_processing-0.8.0.dist-info}/RECORD +98 -113
- 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/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/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/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.8.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.8.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.7.0.dist-info → imap_processing-0.8.0.dist-info}/entry_points.txt +0 -0
|
@@ -6,6 +6,10 @@ from imap_processing.cdf.utils import load_cdf, write_cdf
|
|
|
6
6
|
from imap_processing.swe.l1a.swe_l1a import swe_l1a
|
|
7
7
|
from imap_processing.swe.l1a.swe_science import swe_science
|
|
8
8
|
from imap_processing.swe.l1b.swe_l1b import swe_l1b
|
|
9
|
+
from imap_processing.swe.l1b.swe_l1b_science import (
|
|
10
|
+
convert_counts_to_rate,
|
|
11
|
+
deadtime_correction,
|
|
12
|
+
)
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
def test_swe_l1b(decom_test_data_derived):
|
|
@@ -41,19 +45,36 @@ def test_swe_l1b(decom_test_data_derived):
|
|
|
41
45
|
)
|
|
42
46
|
|
|
43
47
|
|
|
44
|
-
def test_cdf_creation():
|
|
48
|
+
def test_cdf_creation(l1b_validation_df):
|
|
45
49
|
"""Test that CDF file is created and has the correct name."""
|
|
46
50
|
test_data_path = "tests/swe/l0_data/2024051010_SWE_SCIENCE_packet.bin"
|
|
47
51
|
l1a_datasets = swe_l1a(imap_module_directory / test_data_path, "002")
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
assert sci_l1a_filepath.name == "imap_swe_l1a_sci_20240510_v002.cdf"
|
|
52
|
-
|
|
53
|
-
# reads data from CDF file and passes to l1b
|
|
54
|
-
l1a_cdf_dataset = load_cdf(sci_l1a_filepath)
|
|
55
|
-
l1b_dataset = swe_l1b(l1a_cdf_dataset, "002")
|
|
53
|
+
l1b_dataset = swe_l1b(l1a_datasets, "002")
|
|
56
54
|
|
|
57
55
|
sci_l1b_filepath = write_cdf(l1b_dataset)
|
|
58
56
|
|
|
59
57
|
assert sci_l1b_filepath.name == "imap_swe_l1b_sci_20240510_v002.cdf"
|
|
58
|
+
# load the CDF file and compare the values
|
|
59
|
+
l1b_cdf_dataset = load_cdf(sci_l1b_filepath)
|
|
60
|
+
processed_science = l1b_cdf_dataset["science_data"].data
|
|
61
|
+
validation_science = l1b_validation_df.values[:, 1:].reshape(6, 24, 30, 7)
|
|
62
|
+
np.testing.assert_allclose(processed_science, validation_science, rtol=1e-7)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_count_rate():
|
|
66
|
+
x = np.array([1, 10, 100, 1000, 10000, 38911, 65535])
|
|
67
|
+
acq_duration = 80000
|
|
68
|
+
deatime_corrected = deadtime_correction(x, acq_duration)
|
|
69
|
+
count_rate = convert_counts_to_rate(deatime_corrected, acq_duration)
|
|
70
|
+
# Ruth provided the expected output for this test
|
|
71
|
+
expected_output = [
|
|
72
|
+
12.50005653,
|
|
73
|
+
125.00562805,
|
|
74
|
+
1250.56278121,
|
|
75
|
+
12556.50455087,
|
|
76
|
+
130890.05519127,
|
|
77
|
+
589631.73670132,
|
|
78
|
+
1161815.68783304,
|
|
79
|
+
]
|
|
80
|
+
np.testing.assert_allclose(count_rate, expected_output, rtol=1e-7)
|
|
@@ -99,7 +99,7 @@ def test_packet_file_to_datasets(use_derived_value, expected_mode):
|
|
|
99
99
|
|
|
100
100
|
|
|
101
101
|
def test_packet_file_to_datasets_flat_definition():
|
|
102
|
-
test_file = "tests/idex/
|
|
102
|
+
test_file = "tests/idex/imap_idex_l0_raw_20231214_v001.pkts"
|
|
103
103
|
packet_files = imap_module_directory / test_file
|
|
104
104
|
packet_definition = (
|
|
105
105
|
imap_module_directory / "idex/packet_definitions/idex_packet_definition.xml"
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,108 @@
|
|
|
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.l1b.de import calculate_de
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture()
|
|
13
|
+
def df_filt(de_dataset, events_fsw_comparison_theta_0):
|
|
14
|
+
"""Fixture to import test dataset."""
|
|
15
|
+
df = pd.read_csv(events_fsw_comparison_theta_0)
|
|
16
|
+
df_filt = df[df["StartType"] != -1]
|
|
17
|
+
df_filt = df_filt.replace("FILL", 0)
|
|
18
|
+
|
|
19
|
+
return df_filt
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@mock.patch("imap_processing.ultra.l1b.de.get_annotated_particle_velocity")
|
|
23
|
+
def test_calculate_de(mock_get_annotated_particle_velocity, de_dataset, df_filt):
|
|
24
|
+
"""Tests calculate_de function."""
|
|
25
|
+
|
|
26
|
+
# Mock get_annotated_particle_velocity to avoid needing kernels
|
|
27
|
+
def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
|
|
28
|
+
"""
|
|
29
|
+
Mock behavior of get_annotated_particle_velocity.
|
|
30
|
+
|
|
31
|
+
Returns NaN-filled arrays matching the expected output shape.
|
|
32
|
+
"""
|
|
33
|
+
num_events = event_times.size
|
|
34
|
+
return (
|
|
35
|
+
np.full((num_events, 3), np.nan), # sc_velocity
|
|
36
|
+
np.full((num_events, 3), np.nan), # sc_dps_velocity
|
|
37
|
+
np.full((num_events, 3), np.nan), # helio_velocity
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
mock_get_annotated_particle_velocity.side_effect = side_effect_func
|
|
41
|
+
|
|
42
|
+
dataset = calculate_de(de_dataset, "imap_ultra_l1b_45sensor-de")
|
|
43
|
+
|
|
44
|
+
# Front and back positions
|
|
45
|
+
assert np.allclose(dataset["x_front"].data, df_filt["Xf"].astype("float"))
|
|
46
|
+
assert np.allclose(dataset["y_front"], df_filt["Yf"].astype("float"))
|
|
47
|
+
assert np.allclose(dataset["x_back"], df_filt["Xb"].astype("float"))
|
|
48
|
+
assert np.allclose(dataset["y_back"], df_filt["Yb"].astype("float"))
|
|
49
|
+
|
|
50
|
+
# Coincidence positions
|
|
51
|
+
assert np.allclose(dataset["x_coin"], df_filt["Xc"].astype("float"))
|
|
52
|
+
|
|
53
|
+
# Time of flight
|
|
54
|
+
assert np.allclose(dataset["tof_start_stop"], df_filt["TOF"].astype("float"))
|
|
55
|
+
assert np.allclose(dataset["tof_stop_coin"], df_filt["eTOF"].astype("float"))
|
|
56
|
+
assert np.allclose(dataset["tof_corrected"], df_filt["cTOF"].astype("float"))
|
|
57
|
+
|
|
58
|
+
# Distances and path lengths
|
|
59
|
+
assert np.allclose(dataset["front_back_distance"], df_filt["d"].astype("float"))
|
|
60
|
+
assert np.allclose(dataset["path_length"], df_filt["r"].astype("float"))
|
|
61
|
+
|
|
62
|
+
# Coincidence, start, and event types
|
|
63
|
+
assert np.allclose(dataset["coincidence_type"], df_filt["CoinType"].astype("float"))
|
|
64
|
+
assert np.allclose(dataset["start_type"], df_filt["StartType"].astype("float"))
|
|
65
|
+
assert np.allclose(dataset["event_type"], df_filt["StopType"].astype("float"))
|
|
66
|
+
|
|
67
|
+
# Energies and species
|
|
68
|
+
assert np.allclose(dataset["energy"], df_filt["Energy"].astype("float"))
|
|
69
|
+
assert np.allclose(
|
|
70
|
+
dataset["species"], np.full(len(de_dataset["epoch"]), np.nan, dtype=np.uint8)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Velocities in various frames
|
|
74
|
+
test_tof = dataset["tof_start_stop"]
|
|
75
|
+
assert np.allclose(
|
|
76
|
+
dataset["vx_ultra"][test_tof > 0],
|
|
77
|
+
-df_filt["vhatX"].astype("float").values[test_tof > 0],
|
|
78
|
+
rtol=1e-2,
|
|
79
|
+
)
|
|
80
|
+
assert np.allclose(
|
|
81
|
+
dataset["vy_ultra"][test_tof > 0],
|
|
82
|
+
-df_filt["vhatY"].astype("float").values[test_tof > 0],
|
|
83
|
+
rtol=1e-2,
|
|
84
|
+
)
|
|
85
|
+
assert np.allclose(
|
|
86
|
+
dataset["vz_ultra"][test_tof > 0],
|
|
87
|
+
-df_filt["vhatZ"].astype("float").values[test_tof > 0],
|
|
88
|
+
rtol=1e-2,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
assert dataset["vx_sc"].shape == (len(de_dataset["epoch"]),)
|
|
92
|
+
assert dataset["vy_sc"].shape == (len(de_dataset["epoch"]),)
|
|
93
|
+
assert dataset["vz_sc"].shape == (len(de_dataset["epoch"]),)
|
|
94
|
+
|
|
95
|
+
assert dataset["vx_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
96
|
+
assert dataset["vy_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
97
|
+
assert dataset["vz_dps_sc"].shape == (len(de_dataset["epoch"]),)
|
|
98
|
+
|
|
99
|
+
assert dataset["vx_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
100
|
+
assert dataset["vy_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
101
|
+
assert dataset["vz_dps_helio"].shape == (len(de_dataset["epoch"]),)
|
|
102
|
+
|
|
103
|
+
# Event efficiency
|
|
104
|
+
assert np.allclose(
|
|
105
|
+
dataset["event_efficiency"],
|
|
106
|
+
np.full(len(de_dataset["epoch"]), np.nan),
|
|
107
|
+
equal_nan=True,
|
|
108
|
+
)
|
|
@@ -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
|
+
)
|
|
@@ -17,11 +17,11 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
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,
|
|
@@ -298,17 +298,27 @@ def test_get_ctof(yf_fixture):
|
|
|
298
298
|
"""Tests get_ctof function."""
|
|
299
299
|
df_filt, _, _ = yf_fixture
|
|
300
300
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
]
|
|
301
|
+
df_ph = df_filt[df_filt["StopType"].isin([StopType.PH.value])]
|
|
302
|
+
|
|
303
|
+
df_ssd = df_filt[df_filt["StopType"].isin([StopType.SSD.value])]
|
|
304
|
+
|
|
305
|
+
ph_ctof = get_ctof(
|
|
306
|
+
df_ph["TOF"].astype("float").to_numpy(),
|
|
307
|
+
df_ph["r"].astype("float").to_numpy(),
|
|
308
|
+
"PH",
|
|
309
|
+
)
|
|
304
310
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
311
|
+
ssd_ctof = get_ctof(
|
|
312
|
+
df_ssd["TOF"].astype("float").to_numpy(),
|
|
313
|
+
df_ssd["r"].astype("float").to_numpy(),
|
|
314
|
+
"SSD",
|
|
308
315
|
)
|
|
309
316
|
|
|
310
317
|
np.testing.assert_allclose(
|
|
311
|
-
|
|
318
|
+
ph_ctof, df_ph["cTOF"].astype("float"), atol=1e-05, rtol=0
|
|
319
|
+
)
|
|
320
|
+
np.testing.assert_allclose(
|
|
321
|
+
ssd_ctof, df_ssd["cTOF"].astype("float"), atol=1e-05, rtol=0
|
|
312
322
|
)
|
|
313
323
|
|
|
314
324
|
|
|
@@ -3,14 +3,12 @@
|
|
|
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
11
|
build_spatial_bins,
|
|
13
|
-
cartesian_to_spherical,
|
|
14
12
|
get_helio_exposure_times,
|
|
15
13
|
get_histogram,
|
|
16
14
|
get_pointing_frame_exposure_times,
|
|
@@ -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.
|
|
@@ -90,21 +70,6 @@ def test_build_spatial_bins():
|
|
|
90
70
|
np.testing.assert_allclose(el_bin_midpoints[-1], 89.75, atol=1e-4)
|
|
91
71
|
|
|
92
72
|
|
|
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
73
|
def test_get_histogram(test_data):
|
|
109
74
|
"""Tests get_histogram function."""
|
|
110
75
|
v, energy = test_data
|
|
@@ -119,7 +84,7 @@ def test_get_histogram(test_data):
|
|
|
119
84
|
assert hist.shape == (
|
|
120
85
|
len(az_bin_edges) - 1,
|
|
121
86
|
len(el_bin_edges) - 1,
|
|
122
|
-
len(energy_bin_edges)
|
|
87
|
+
len(energy_bin_edges),
|
|
123
88
|
)
|
|
124
89
|
|
|
125
90
|
|
|
@@ -143,10 +108,10 @@ def test_get_pointing_frame_exposure_times():
|
|
|
143
108
|
|
|
144
109
|
|
|
145
110
|
@pytest.mark.external_kernel()
|
|
146
|
-
|
|
111
|
+
@pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
|
|
112
|
+
def test_et_helio_exposure_times():
|
|
147
113
|
"""Tests get_helio_exposure_times function."""
|
|
148
114
|
|
|
149
|
-
spice.furnsh(kernels)
|
|
150
115
|
constant_exposure = BASE_PATH / "dps_grid45_compressed.cdf"
|
|
151
116
|
start_time = 829485054.185627
|
|
152
117
|
end_time = 829567884.185627
|
|
@@ -185,9 +150,9 @@ def test_et_helio_exposure_times(kernels):
|
|
|
185
150
|
transposed_exposure = np.transpose(exposure_data, (2, 1, 0))
|
|
186
151
|
exposures.append(transposed_exposure)
|
|
187
152
|
|
|
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[:, :,
|
|
153
|
+
assert np.array_equal(np.squeeze(exposures[0]), exposure_3d[:, :, 0])
|
|
154
|
+
assert np.array_equal(np.squeeze(exposures[1]), exposure_3d[:, :, 11])
|
|
155
|
+
assert np.array_equal(np.squeeze(exposures[2]), exposure_3d[:, :, 23])
|
|
191
156
|
|
|
192
157
|
|
|
193
158
|
def test_get_pointing_frame_sensitivity():
|
|
@@ -52,13 +52,18 @@ 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
|