Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

859 spice frame transform function #861

Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor geometry function signatures for consistency
  • Loading branch information
subagonsouth committed Sep 26, 2024
commit dd25e73f588598cf89d1915d70a79fd5d4f423ae
22 changes: 12 additions & 10 deletions imap_processing/spice/geometry.py
Original file line number Diff line number Diff line change
@@ -220,24 +220,24 @@ def get_spacecraft_spin_phase(
@typing.no_type_check
@ensure_spice
def frame_transform(
from_frame: SpiceFrame,
to_frame: SpiceFrame,
et: Union[float, npt.NDArray],
position: npt.NDArray,
from_frame: SpiceFrame,
to_frame: SpiceFrame,
) -> npt.NDArray:
"""
Transform an <x, y, z> vector between reference frames (rotation only).

Parameters
----------
from_frame : SpiceFrame
Reference frame of input vector(s).
to_frame : SpiceFrame
Reference frame of output vector(s).
et : float or npt.NDArray
Ephemeris time(s) corresponding to position(s).
position : npt.NDArray
<x, y, z> vector or array of vectors in reference frame `from_frame`.
from_frame : SpiceFrame
Reference frame of input vector(s).
to_frame : SpiceFrame
Reference frame of output vector(s).

Returns
-------
@@ -267,7 +267,7 @@ def frame_transform(

# rotate will have shape = (3, 3) or (n, 3, 3)
# position will have shape = (3,) or (n, 3)
rotate = get_rotation_matrix(from_frame, to_frame, et)
rotate = get_rotation_matrix(et, from_frame, to_frame)
# adding a dimension to position results in the following input and output
# shapes from matrix multiplication
# Single et/position: (3, 3),(3, 1) -> (3, 1)
@@ -278,7 +278,9 @@ def frame_transform(


def get_rotation_matrix(
Copy link
Contributor

@laspsandoval laspsandoval Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice way to use a numpy array w/ pxform

from_frame: SpiceFrame, to_frame: SpiceFrame, et: Union[float, npt.NDArray]
et: Union[float, npt.NDArray],
from_frame: SpiceFrame,
to_frame: SpiceFrame,
) -> npt.NDArray:
"""
Get the rotation matrix/matrices that can be used to transform between frames.
@@ -290,12 +292,12 @@ def get_rotation_matrix(

Parameters
----------
et : float or npt.NDArray
Ephemeris time(s) for which to get the rotation matrices.
from_frame : SpiceFrame
Reference frame to transform from.
to_frame : SpiceFrame
Reference frame to transform to.
et : float or npt.NDArray
Ephemeris time(s) for which to get the rotation matrices.

Returns
-------
25 changes: 11 additions & 14 deletions imap_processing/tests/spice/test_geometry.py
Original file line number Diff line number Diff line change
@@ -128,7 +128,7 @@ def test_frame_transform(furnish_kernels):
et_0 = spice.utc2et("2025-04-30T12:00:00.000")
position = np.arange(3) + 1
result_0 = frame_transform(
SpiceFrame.IMAP_ULTRA_45, SpiceFrame.IMAP_DPS, et_0, position
et_0, position, SpiceFrame.IMAP_ULTRA_45, SpiceFrame.IMAP_DPS
)
# compare against pure SPICE calculation
rotation_matrix = spice.pxform(
@@ -141,10 +141,7 @@ def test_frame_transform(furnish_kernels):
ets = np.array([et_0, et_0 + 10])
positions = np.array([[1, 1, 1], [1, 2, 3]])
vec_result = frame_transform(
SpiceFrame.IMAP_HI_90,
SpiceFrame.IMAP_DPS,
ets,
positions,
ets, positions, SpiceFrame.IMAP_HI_90, SpiceFrame.IMAP_DPS
)

assert vec_result.shape == (2, 3)
@@ -163,34 +160,34 @@ def test_frame_transform_exceptions():
ValueError, match="Position vectors with one dimension must have 3 elements."
):
frame_transform(
SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.IMAP_CODICE, 0, np.arange(4)
0, np.arange(4), SpiceFrame.IMAP_SPACECRAFT, SpiceFrame.IMAP_CODICE
)
with pytest.raises(
ValueError,
match="Ephemeris time must be float when single position vector is provided.",
):
frame_transform(
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
np.asarray(0),
np.array([1, 0, 0]),
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
)
with pytest.raises(ValueError, match="Invalid position shape: "):
frame_transform(
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
np.arange(2),
np.arange(4).reshape((2, 2)),
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
)
with pytest.raises(
ValueError,
match="Mismatch in number of position vectors and Ephemeris times provided.",
):
frame_transform(
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
np.arange(2),
np.arange(9).reshape((3, 3)),
SpiceFrame.ECLIPJ2000,
SpiceFrame.IMAP_HIT,
)


@@ -207,11 +204,11 @@ def test_get_rotation_matrix(furnish_kernels):
et = spice.utc2et("2025-09-30T12:00:00.000")
# test input of float
rotation = get_rotation_matrix(
SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT, et
et, SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT
)
assert rotation.shape == (3, 3)
# test array of et input
rotation = get_rotation_matrix(
SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT, np.arange(10) + et
np.arange(10) + et, SpiceFrame.IMAP_IDEX, SpiceFrame.IMAP_SPACECRAFT
)
assert rotation.shape == (10, 3, 3)