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
|
@@ -7,7 +7,7 @@ from imap_processing import imap_module_directory
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def test_idex_decom_length(decom_test_data: xr.Dataset):
|
|
10
|
-
"""Verify that
|
|
10
|
+
"""Verify that the output data has the expected number of data variables.
|
|
11
11
|
|
|
12
12
|
Parameters
|
|
13
13
|
----------
|
|
@@ -18,7 +18,7 @@ def test_idex_decom_length(decom_test_data: xr.Dataset):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def test_idex_decom_event_num(decom_test_data: xr.Dataset):
|
|
21
|
-
"""Verify that
|
|
21
|
+
"""Verify that 14 impacts were gathered by the test data.
|
|
22
22
|
|
|
23
23
|
Parameters
|
|
24
24
|
----------
|
|
@@ -26,7 +26,7 @@ def test_idex_decom_event_num(decom_test_data: xr.Dataset):
|
|
|
26
26
|
The dataset to test with
|
|
27
27
|
"""
|
|
28
28
|
for var in decom_test_data:
|
|
29
|
-
assert len(decom_test_data[var]) ==
|
|
29
|
+
assert len(decom_test_data[var]) == 14
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def test_idex_tof_high_data(decom_test_data: xr.Dataset):
|
|
@@ -21,7 +21,7 @@ def test_idex_cdf_file(decom_test_data: xr.Dataset):
|
|
|
21
21
|
file_name = write_cdf(decom_test_data)
|
|
22
22
|
|
|
23
23
|
assert file_name.exists()
|
|
24
|
-
assert file_name.name == "
|
|
24
|
+
assert file_name.name == "imap_idex_l1a_sci_20231214_v001.cdf"
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def test_bad_cdf_attributes(decom_test_data: xr.Dataset):
|
|
@@ -195,9 +195,9 @@ def test_combine_segmented_packets(segmented_pkts_fake_data):
|
|
|
195
195
|
dataset["events"].values,
|
|
196
196
|
np.array(
|
|
197
197
|
[
|
|
198
|
-
"
|
|
198
|
+
"0000000001000000001000000001000000001000",
|
|
199
199
|
"0000010000",
|
|
200
|
-
"
|
|
200
|
+
"01000000001000000000",
|
|
201
201
|
]
|
|
202
202
|
),
|
|
203
203
|
)
|
|
Binary file
|
|
@@ -12,18 +12,38 @@ from imap_processing.mag.l1b.mag_l1b import mag_l1b, mag_l1b_processing
|
|
|
12
12
|
def mag_l1a_dataset():
|
|
13
13
|
epoch = xr.DataArray(np.arange(20), name="epoch", dims=["epoch"])
|
|
14
14
|
direction = xr.DataArray(np.arange(4), name="direction", dims=["direction"])
|
|
15
|
+
compression = xr.DataArray(np.arange(2), name="compression", dims=["compression"])
|
|
16
|
+
|
|
17
|
+
direction_label = xr.DataArray(
|
|
18
|
+
direction.values.astype(str),
|
|
19
|
+
name="direction_label",
|
|
20
|
+
dims=["direction_label"],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
compression_label = xr.DataArray(
|
|
24
|
+
compression.values.astype(str),
|
|
25
|
+
name="compression_label",
|
|
26
|
+
dims=["compression_label"],
|
|
27
|
+
)
|
|
28
|
+
|
|
15
29
|
vectors = xr.DataArray(
|
|
16
30
|
np.zeros((20, 4)),
|
|
17
31
|
dims=["epoch", "direction"],
|
|
18
32
|
coords={"epoch": epoch, "direction": direction},
|
|
19
33
|
)
|
|
34
|
+
compression_flags = xr.DataArray(
|
|
35
|
+
np.zeros((20, 2), dtype=np.int8), dims=["epoch", "compression"]
|
|
36
|
+
)
|
|
20
37
|
|
|
21
38
|
vectors[0, :] = np.array([1, 1, 1, 0])
|
|
22
39
|
|
|
23
40
|
output_dataset = xr.Dataset(
|
|
24
|
-
coords={"epoch": epoch, "direction": direction},
|
|
41
|
+
coords={"epoch": epoch, "direction": direction, "compression": compression},
|
|
25
42
|
)
|
|
26
43
|
output_dataset["vectors"] = vectors
|
|
44
|
+
output_dataset["compression_flags"] = compression_flags
|
|
45
|
+
output_dataset["direction_label"] = direction_label
|
|
46
|
+
output_dataset["compression_label"] = compression_label
|
|
27
47
|
|
|
28
48
|
return output_dataset
|
|
29
49
|
|
|
@@ -66,13 +86,49 @@ def test_mag_attributes(mag_l1a_dataset):
|
|
|
66
86
|
assert output.attrs["Data_level"] == "L1B"
|
|
67
87
|
|
|
68
88
|
|
|
69
|
-
@pytest.mark.skip(reason="Epoch variable data need to be monotonically increasing")
|
|
70
89
|
def test_cdf_output():
|
|
71
90
|
l1a_cdf = load_cdf(
|
|
72
|
-
Path(__file__).parent / "
|
|
91
|
+
Path(__file__).parent / "imap_mag_l1a_norm-magi_20251017_v001.cdf"
|
|
73
92
|
)
|
|
74
93
|
l1b_dataset = mag_l1b(l1a_cdf, "v001")
|
|
75
94
|
|
|
76
95
|
output_path = write_cdf(l1b_dataset)
|
|
77
96
|
|
|
78
97
|
assert Path.exists(output_path)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_mag_compression_scale(mag_l1a_dataset):
|
|
101
|
+
test_calibration = np.array(
|
|
102
|
+
[
|
|
103
|
+
[2.2972202, 0.0, 0.0],
|
|
104
|
+
[0.00348625, 2.23802879, 0.0],
|
|
105
|
+
[-0.00250788, -0.00888437, 2.24950008],
|
|
106
|
+
]
|
|
107
|
+
)
|
|
108
|
+
mag_l1a_dataset["vectors"][0, :] = np.array([1, 1, 1, 0])
|
|
109
|
+
mag_l1a_dataset["vectors"][1, :] = np.array([1, 1, 1, 0])
|
|
110
|
+
mag_l1a_dataset["vectors"][2, :] = np.array([1, 1, 1, 0])
|
|
111
|
+
mag_l1a_dataset["vectors"][3, :] = np.array([1, 1, 1, 0])
|
|
112
|
+
|
|
113
|
+
mag_l1a_dataset["compression_flags"][0, :] = np.array([1, 16], dtype=np.int8)
|
|
114
|
+
mag_l1a_dataset["compression_flags"][1, :] = np.array([0, 0], dtype=np.int8)
|
|
115
|
+
mag_l1a_dataset["compression_flags"][2, :] = np.array([1, 18], dtype=np.int8)
|
|
116
|
+
mag_l1a_dataset["compression_flags"][3, :] = np.array([1, 14], dtype=np.int8)
|
|
117
|
+
|
|
118
|
+
mag_l1a_dataset.attrs["Logical_source"] = ["imap_mag_l1a_norm-mago"]
|
|
119
|
+
output = mag_l1b(mag_l1a_dataset, "v001")
|
|
120
|
+
|
|
121
|
+
calibrated_vectors = np.matmul(np.array([1, 1, 1]), test_calibration)
|
|
122
|
+
# 16 bit width is the standard
|
|
123
|
+
assert np.allclose(output["vectors"].data[0][:3], calibrated_vectors)
|
|
124
|
+
# uncompressed data is uncorrected
|
|
125
|
+
assert np.allclose(output["vectors"].data[1][:3], calibrated_vectors)
|
|
126
|
+
|
|
127
|
+
# width of 18 should be multiplied by 1/4
|
|
128
|
+
scaled_vectors = calibrated_vectors * 1 / 4
|
|
129
|
+
# should be corrected
|
|
130
|
+
assert np.allclose(output["vectors"].data[2][:3], scaled_vectors)
|
|
131
|
+
|
|
132
|
+
# width of 14 should be multiplied by 4
|
|
133
|
+
scaled_vectors = calibrated_vectors * 4
|
|
134
|
+
assert np.allclose(output["vectors"].data[3][:3], scaled_vectors)
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
{SPICE_TEST_DATA_PATH}/imap_spk_demo.bsp
|
|
4
4
|
{SPICE_TEST_DATA_PATH}/sim_1yr_imap_attitude.bc
|
|
5
5
|
{SPICE_TEST_DATA_PATH}/imap_wkcp.tf
|
|
6
|
-
{SPICE_TEST_DATA_PATH}/de440s.bsp
|
|
6
|
+
{SPICE_TEST_DATA_PATH}/de440s.bsp
|
|
7
|
+
{SPICE_TEST_DATA_PATH}/imap_science_0001.tf
|
|
8
|
+
{SPICE_TEST_DATA_PATH}/sim_1yr_imap_pointing_frame.bc
|
|
@@ -8,6 +8,8 @@ import spiceypy as spice
|
|
|
8
8
|
from imap_processing.spice.geometry import (
|
|
9
9
|
SpiceBody,
|
|
10
10
|
SpiceFrame,
|
|
11
|
+
basis_vectors,
|
|
12
|
+
cartesian_to_spherical,
|
|
11
13
|
frame_transform,
|
|
12
14
|
get_instrument_spin_phase,
|
|
13
15
|
get_rotation_matrix,
|
|
@@ -16,7 +18,9 @@ from imap_processing.spice.geometry import (
|
|
|
16
18
|
get_spin_data,
|
|
17
19
|
imap_state,
|
|
18
20
|
instrument_pointing,
|
|
21
|
+
spherical_to_cartesian,
|
|
19
22
|
)
|
|
23
|
+
from imap_processing.spice.kernels import ensure_spice
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
@pytest.mark.parametrize(
|
|
@@ -99,10 +103,10 @@ def test_get_spacecraft_spin_phase_value_error(query_met_times, fake_spin_data):
|
|
|
99
103
|
_ = get_spacecraft_spin_phase(query_met_times)
|
|
100
104
|
|
|
101
105
|
|
|
102
|
-
@pytest.mark.usefixtures("
|
|
103
|
-
def test_get_spin_data():
|
|
106
|
+
@pytest.mark.usefixtures("use_fake_spin_data_for_time")
|
|
107
|
+
def test_get_spin_data(use_fake_spin_data_for_time):
|
|
104
108
|
"""Test get_spin_data() with generated spin data."""
|
|
105
|
-
|
|
109
|
+
use_fake_spin_data_for_time(453051323.0 - 56120)
|
|
106
110
|
spin_data = get_spin_data()
|
|
107
111
|
|
|
108
112
|
(
|
|
@@ -250,7 +254,7 @@ def test_frame_transform_exceptions():
|
|
|
250
254
|
match="Mismatch in number of position vectors and Ephemeris times provided.",
|
|
251
255
|
):
|
|
252
256
|
frame_transform(
|
|
253
|
-
|
|
257
|
+
1,
|
|
254
258
|
np.arange(9).reshape((3, 3)),
|
|
255
259
|
SpiceFrame.ECLIPJ2000,
|
|
256
260
|
SpiceFrame.IMAP_HIT,
|
|
@@ -306,3 +310,79 @@ def test_instrument_pointing(furnish_kernels):
|
|
|
306
310
|
et, SpiceFrame.IMAP_HI_90, SpiceFrame.ECLIPJ2000, cartesian=True
|
|
307
311
|
)
|
|
308
312
|
assert ins_pointing.shape == (3, 3)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@pytest.mark.external_kernel()
|
|
316
|
+
@pytest.mark.use_test_metakernel("imap_ena_sim_metakernel.template")
|
|
317
|
+
def test_basis_vectors():
|
|
318
|
+
"""Test coverage for basis_vectors()."""
|
|
319
|
+
# This call to SPICE needs to be wrapped with `ensure_spice` so that kernels
|
|
320
|
+
# get furnished automatically
|
|
321
|
+
et = ensure_spice(spice.utc2et)("2025-09-30T12:00:00.000")
|
|
322
|
+
# test input of float
|
|
323
|
+
sc_axes = basis_vectors(et, SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.IMAP_SPACECRAFT)
|
|
324
|
+
np.testing.assert_array_equal(sc_axes, np.eye(3))
|
|
325
|
+
# test array of et input
|
|
326
|
+
et_array = np.arange(10) + et
|
|
327
|
+
sc_axes = basis_vectors(et_array, SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.ECLIPJ2000)
|
|
328
|
+
assert sc_axes.shape == (10, 3, 3)
|
|
329
|
+
# Verify that for each time, the basis vectors are correct
|
|
330
|
+
for et, basis_matrix in zip(et_array, sc_axes):
|
|
331
|
+
np.testing.assert_array_equal(
|
|
332
|
+
basis_matrix,
|
|
333
|
+
frame_transform(
|
|
334
|
+
et * np.ones(3),
|
|
335
|
+
np.eye(3),
|
|
336
|
+
SpiceFrame.IMAP_SPACECRAFT,
|
|
337
|
+
SpiceFrame.ECLIPJ2000,
|
|
338
|
+
),
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def test_cartesian_to_spherical():
|
|
343
|
+
"""Tests cartesian_to_spherical function."""
|
|
344
|
+
|
|
345
|
+
step = 0.05
|
|
346
|
+
x = np.arange(-1, 1 + step, step)
|
|
347
|
+
y = np.arange(-1, 1 + step, step)
|
|
348
|
+
z = np.arange(-1, 1 + step, step)
|
|
349
|
+
x, y, z = np.meshgrid(x, y, z)
|
|
350
|
+
|
|
351
|
+
cartesian_points = np.stack((x.ravel(), y.ravel(), z.ravel()), axis=-1)
|
|
352
|
+
|
|
353
|
+
for point in cartesian_points:
|
|
354
|
+
r, az, el = cartesian_to_spherical(point)
|
|
355
|
+
r_spice, colat_spice, slong_spice = spice.recsph(point)
|
|
356
|
+
|
|
357
|
+
# Convert SPICE co-latitude to elevation
|
|
358
|
+
el_spice = 90 - np.degrees(colat_spice)
|
|
359
|
+
az_spice = np.degrees(slong_spice)
|
|
360
|
+
|
|
361
|
+
# Normalize azimuth to [0, 360]
|
|
362
|
+
az_spice = az_spice % 360
|
|
363
|
+
|
|
364
|
+
np.testing.assert_allclose(r, r_spice, atol=1e-5)
|
|
365
|
+
np.testing.assert_allclose(az, az_spice, atol=1e-5)
|
|
366
|
+
np.testing.assert_allclose(el, el_spice, atol=1e-5)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def test_spherical_to_cartesian():
|
|
370
|
+
"""Tests spherical_to_cartesian function."""
|
|
371
|
+
|
|
372
|
+
azimuth = np.linspace(0, 2 * np.pi, 50)
|
|
373
|
+
elevation = np.linspace(-np.pi / 2, np.pi / 2, 50)
|
|
374
|
+
theta, elev = np.meshgrid(azimuth, elevation)
|
|
375
|
+
r = 1.0
|
|
376
|
+
|
|
377
|
+
spherical_points = np.stack(
|
|
378
|
+
(r * np.ones_like(theta).ravel(), theta.ravel(), elev.ravel()), axis=-1
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Convert elevation to colatitude for SPICE
|
|
382
|
+
colat = np.pi / 2 - spherical_points[:, 2]
|
|
383
|
+
|
|
384
|
+
for i in range(len(colat)):
|
|
385
|
+
cartesian_coords = spherical_to_cartesian(np.array([spherical_points[i]]))
|
|
386
|
+
spice_coords = spice.sphrec(r, colat[i], spherical_points[i, 1])
|
|
387
|
+
|
|
388
|
+
np.testing.assert_allclose(cartesian_coords[0], spice_coords, atol=1e-5)
|
|
@@ -74,3 +74,36 @@ def l1a_validation_df():
|
|
|
74
74
|
# Fill NaNs with the previous value
|
|
75
75
|
df["shcoarse"] = df["shcoarse"].ffill()
|
|
76
76
|
return df
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.fixture(scope="session")
|
|
80
|
+
def l1b_validation_df():
|
|
81
|
+
"""Read validation data from file"""
|
|
82
|
+
l1_val_path = imap_module_directory / "tests/swe/l1_validation"
|
|
83
|
+
filename = "swe_l0_unpacked-data_20240510_v001_VALIDATION_L1B_v3.dat"
|
|
84
|
+
|
|
85
|
+
# Define column names for validation data
|
|
86
|
+
column_names = [
|
|
87
|
+
"shcoarse",
|
|
88
|
+
"cem_1",
|
|
89
|
+
"cem_2",
|
|
90
|
+
"cem_3",
|
|
91
|
+
"cem_4",
|
|
92
|
+
"cem_5",
|
|
93
|
+
"cem_6",
|
|
94
|
+
"cem_7",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
# Read the data, specifying na_values and delimiter
|
|
98
|
+
df = pd.read_csv(
|
|
99
|
+
l1_val_path / filename,
|
|
100
|
+
skiprows=12, # Skip the first 10 rows of comments
|
|
101
|
+
sep=r"\s*,\s*", # Regex to handle spaces and commas as delimiters
|
|
102
|
+
names=column_names,
|
|
103
|
+
na_values=["", " "], # Treat empty strings or spaces as NaN
|
|
104
|
+
engine="python",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Fill NaNs with the previous value
|
|
108
|
+
df["shcoarse"] = df["shcoarse"].ffill()
|
|
109
|
+
return df
|