diff --git a/imap_processing/spice/geometry.py b/imap_processing/spice/geometry.py index 132560932..1d7b11988 100644 --- a/imap_processing/spice/geometry.py +++ b/imap_processing/spice/geometry.py @@ -18,6 +18,8 @@ import spiceypy from numpy.typing import NDArray +from imap_processing.mag import constants + logger = logging.getLogger(__name__) @@ -317,6 +319,14 @@ def frame_transform( # Multiple et/positions : (n, 3, 3),(n, 3, 1) -> (n, 3, 1) result = np.squeeze(rotate @ position[..., np.newaxis]) + # For every FILLVAL in the input position, ensure the output is also NaN or FILLVAL + if np.isnan(position).any() or (position == constants.FILLVAL).any(): + result = np.where( + np.isnan(position) | (position == constants.FILLVAL), + constants.FILLVAL, + result, + ) + return result diff --git a/imap_processing/tests/spice/test_geometry.py b/imap_processing/tests/spice/test_geometry.py index 8e0465ba0..19774e198 100644 --- a/imap_processing/tests/spice/test_geometry.py +++ b/imap_processing/tests/spice/test_geometry.py @@ -6,6 +6,7 @@ import pytest import spiceypy +from imap_processing.mag import constants from imap_processing.spice.geometry import ( SpiceBody, SpiceFrame, @@ -159,6 +160,19 @@ def test_get_spacecraft_to_instrument_spin_phase_offset( SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.IMAP_DPS, ), + # single et, single NaN/FILL_VAL vector + ( + ["2025-04-30T12:00:00.000"], + np.array( + [ + [0, 0, 0], + [constants.FILLVAL, constants.FILLVAL, constants.FILLVAL], + [np.nan, np.nan, np.nan], + ] + ), + SpiceFrame.IMAP_SPACECRAFT, + SpiceFrame.IMAP_DPS, + ), ], ) def test_frame_transform(et_strings, position, from_frame, to_frame, furnish_kernels): @@ -203,6 +217,12 @@ def test_frame_transform(et_strings, position, from_frame, to_frame, furnish_ker spice_result = spiceypy.mxv(rotation_matrix, spice_position) np.testing.assert_allclose(test_result, spice_result, atol=1e-12) + # Ensure that NaN/FILL_VAL inputs are preserved exactly as FILL_VAL outputs + # and not just really close to but not quite FILL_VAL + for input_vec, output_vec in zip(position, result, strict=False): + if np.isnan(input_vec).all() or (input_vec == constants.FILLVAL).all(): + assert (output_vec == constants.FILLVAL).all() + @pytest.mark.parametrize( "spice_frame",