Commit 3dbad619 authored by Jesse Mapel's avatar Jesse Mapel Committed by GitHub
Browse files

Continuation of #176 data_naif frame chain implementation (#181)

* First pass at adding frame chain to NaifSpice class

* Tweaked data_naif frame_chain implementation

* Cleaned up reference frames in data naif
parent 51ba8b21
Loading
Loading
Loading
Loading
+69 −3
Original line number Diff line number Diff line
import spiceypy as spice
import numpy as np
from ale.base.type_sensor import Framer
from ale.transformation import FrameNode
from ale.rotation import TimeDependentRotation

class NaifSpice():
    def __enter__(self):
@@ -74,7 +76,10 @@ class NaifSpice():

    @property
    def target_frame_id(self):
        return spice.gipool('BODY_FRAME_CODE', 0, 1)
        frame_id, frame_name, found = spice.cidfrm(self.target_id)
        if not found:
            raise ValueError("No reference frame could be found for target ID {}.".format(self.target_id))
        return frame_id

    @property
    def sensor_frame_id(self):
@@ -150,10 +155,71 @@ class NaifSpice():

    @property
    def frame_chain(self):
        pass
        """
        Return the root node of the rotation frame tree/chain.

        The root node is the J2000 reference frame. The other nodes in the
        tree can be accessed via the methods in the FrameNode class.

        This property expects the ephemeris_time property/attribute to be defined.
        It should be a list of the ephemeris seconds past the J2000 epoch for each
        exposure in the image.

        Returns
        -------
        FrameNode
            The root node of the frame tree. This will always be the J2000 reference frame.
        """
        if not hasattr(self, '_root_frame'):
            j2000_id = 1 #J2000 is our root reference frame
            self._root_frame = FrameNode(j2000_id)

            sensor_quats = np.zeros((len(self.ephemeris_time), 4))
            sensor_times = np.array(self.ephemeris_time)
            body_quats = np.zeros((len(self.ephemeris_time), 4))
            body_times = np.array(self.ephemeris_time)
            for i, time in enumerate(self.ephemeris_time):
                sensor2j2000 = spice.pxform(
                    self.sensor_frame_id,
                    j2000_id,
                    time)
                q_sensor = spice.m2q(sensor2j2000)
                sensor_quats[i,:3] = q_sensor[1:]
                sensor_quats[i,3] = q_sensor[0]

                body2j2000 = spice.pxform(
                    self.target_frame_id,
                    j2000_id,
                    time)
                q_body = spice.m2q(body2j2000)
                body_quats[i,:3] = q_body[1:]
                body_quats[i,3] = q_body[0]

            sensor2j2000_rot = TimeDependentRotation(
                sensor_quats,
                sensor_times,
                self.sensor_frame_id,
                j2000_id
            )
            sensor_node = FrameNode(
                self.sensor_frame_id,
                parent=self._root_frame,
                rotation=sensor2j2000_rot)

            body2j2000_rot = TimeDependentRotation(
                body_quats,
                body_times,
                self.target_frame_id,
                j2000_id
            )
            body_node = FrameNode(
                self.target_frame_id,
                parent=self._root_frame,
                rotation=body2j2000_rot)
        return self._root_frame

    @property
    def _sensor_orientation(self):
    def sensor_orientation(self):
        if not hasattr(self, '_orientation'):
            ephem = self.ephemeris_time

+3 −1
Original line number Diff line number Diff line
@@ -20,13 +20,15 @@ class SimpleSpice():
    def unload(self, *args):
        return
    def pxform(self, *args):
        return
        return np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    def m2q(self, *args):
        return np.asarray([1,2,3,4])
    def bodn2c(self, *args):
        return "SPACE"
    def sct2e(self, *args):
        return 0.1
    def cidfrm(self, *args):
        return (2000, "Test_Body_Frame", True)

def get_mockkernels(self, *args):
    return "some_metakernel"
+15 −1
Original line number Diff line number Diff line
@@ -15,9 +15,20 @@ def test_naif_data():
    naif_data = data_naif.NaifSpice()
    naif_data.instrument_id = "INSTRUMENT"
    naif_data.target_name = "TARGET"
    naif_data.ephemeris_time = [0, 1]

    return naif_data

def test_frame_chain(test_naif_data):
    j2000 = test_naif_data.frame_chain
    assert j2000.parent == None
    assert j2000.id == 1
    assert len(j2000.children) == 2
    for child in j2000.children:
        assert child.parent == j2000
        np.testing.assert_equal(child.rotation.times, np.array([0, 1]))
        assert child.rotation.quats.shape == (2, 4)

def test_target_id(test_naif_data):
    assert test_naif_data.target_id == -12345

@@ -29,10 +40,13 @@ def test_radii(test_naif_data):

def test_naif_keywords(test_naif_data):
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['BODY-12345_RADII'], np.ones(3))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['BODY_FRAME_CODE'], np.arange(1))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['BODY_FRAME_CODE'], 2000)
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_PIXEL_SIZE'], (0.001))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_ITRANSL'], np.ones(3))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_ITRANSS'], np.ones(3))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_FOCAL_LENGTH'], np.ones(1))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_BORESIGHT_LINE'], np.ones(1))
    np.testing.assert_equal(test_naif_data.isis_naif_keywords['INS-12345_BORESIGHT_SAMPLE'], np.ones(1))

def test_target_frame_id(test_naif_data):
    assert test_naif_data.target_frame_id == 2000