From 0bf1bbd8899ba9b0466a1658a36bc7bc9d8a736f Mon Sep 17 00:00:00 2001
From: acpaquette <acpaquette@usgs.gov>
Date: Fri, 27 Mar 2020 09:53:53 -0700
Subject: [PATCH] LRO Direction Fix + Summing Mode Fix (#333)

* Updated spacecraft direction for lro

* Fixes the focal2pixel transform to account for the summing mode of the camera.

* Fixed lro tests
---
 ale/base/data_naif.py             |  4 ++-
 ale/drivers/lro_drivers.py        | 40 +++++++++++++++++++---------
 tests/pytests/test_lro_drivers.py | 43 +++++++++++++++++--------------
 3 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py
index 60c0abc..98d0780 100644
--- a/ale/base/data_naif.py
+++ b/ale/base/data_naif.py
@@ -411,7 +411,9 @@ class NaifSpice():
                 v_vec = rotated_velocities
 
                 velocity_axis = 2
-                trans_x = self.focal2pixel_lines
+                # Get the default line translation with no potential flipping
+                # from the driver
+                trans_x = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)))
 
                 if (trans_x[0] < trans_x[1]):
                     velocity_axis = 1
diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py
index 0ddc160..014c6a4 100644
--- a/ale/drivers/lro_drivers.py
+++ b/ale/drivers/lro_drivers.py
@@ -141,8 +141,11 @@ class LroLrocPds3LabelNaifSpiceDriver(LineScanner, NaifSpice, Pds3Label, Driver)
         : list<double>
           focal plane to detector lines
         """
-        focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)))
-        return focal2pixel_lines
+        focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) / self.sampling_factor
+        if self.spacecraft_direction < 0:
+            return -focal2pixel_lines
+        else:
+            return focal2pixel_lines
 
     @property
     def ephemeris_start_time(self):
@@ -259,10 +262,15 @@ class LroLrocPds3LabelNaifSpiceDriver(LineScanner, NaifSpice, Pds3Label, Driver)
         direction : double
                     X value of the first velocity relative to the sensor
         """
-        rotation = self.frame_chain.compute_rotation(self.target_frame_id, self.sensor_frame_id)
-        positions, velocities, times = self.sensor_position
-        velocity = rotation.rotate_velocity_at([positions[0]], [velocities[0]], [times[0]])[0]
-        return velocity[0]
+        frame_chain = self.frame_chain
+        lro_bus_id = spice.bods2c('LRO_SC_BUS')
+        time = self.ephemeris_start_time
+        state, _ = spice.spkezr(self.spacecraft_name, time, 'J2000', 'None', self.target_name)
+        position = state[:3]
+        velocity = state[3:]
+        rotation = frame_chain.compute_rotation(1, lro_bus_id)
+        rotated_velocity = spice.mxv(rotation._rots.as_dcm()[0], velocity)
+        return rotated_velocity[0]
 
 
 
@@ -398,8 +406,11 @@ class LroLrocIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver)
         : list<double>
           focal plane to detector lines
         """
-        focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)))
-        return focal2pixel_lines
+        focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) / self.sampling_factor
+        if self.spacecraft_direction < 0:
+            return -focal2pixel_lines
+        else:
+            return focal2pixel_lines
 
     @property
     def multiplicative_line_error(self):
@@ -485,7 +496,12 @@ class LroLrocIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver)
         direction : double
                     X value of the first velocity relative to the sensor
         """
-        rotation = self.frame_chain.compute_rotation(self.target_frame_id, self.sensor_frame_id)
-        positions, velocities, times = self.sensor_position
-        velocity = rotation.rotate_velocity_at([positions[0]], [velocities[0]], [times[0]])[0]
-        return velocity[0]
+        frame_chain = self.frame_chain
+        lro_bus_id = spice.bods2c('LRO_SC_BUS')
+        time = self.ephemeris_start_time
+        state, _ = spice.spkezr(self.spacecraft_name, time, 'J2000', 'None', self.target_name)
+        position = state[:3]
+        velocity = state[3:]
+        rotation = frame_chain.compute_rotation(1, lro_bus_id)
+        rotated_velocity = spice.mxv(rotation._rots.as_dcm()[0], velocity)
+        return rotated_velocity[0]
diff --git a/tests/pytests/test_lro_drivers.py b/tests/pytests/test_lro_drivers.py
index 5328b53..326b0eb 100644
--- a/tests/pytests/test_lro_drivers.py
+++ b/tests/pytests/test_lro_drivers.py
@@ -271,17 +271,18 @@ class test_pds_naif(unittest.TestCase):
     def test_spacecraft_direction(self, compute_rotation, from_spice, frame_chain):
         with patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.target_frame_id', \
              new_callable=PropertyMock) as target_frame_id, \
-             patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.sensor_frame_id', \
-             new_callable=PropertyMock) as sensor_frame_id, \
              patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.ephemeris_start_time', \
              new_callable=PropertyMock) as ephemeris_start_time, \
-             patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.ephemeris_stop_time', \
-             new_callable=PropertyMock) as ephemeris_end_time, \
-             patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.sensor_position', \
-             new_callable=PropertyMock) as sensor_position:
-            sensor_position.return_value = [[np.array([50, 50, 50])], [np.array([1, 1, 1])], [0]]
-            assert self.driver.spacecraft_direction < 0
-            compute_rotation.assert_called_with(target_frame_id.return_value, sensor_frame_id.return_value)
+             patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c, \
+             patch('ale.drivers.lro_drivers.spice.spkezr', return_value=[[1, 1, 1, 1, 1, 1], 0]) as spkezr, \
+             patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv:
+            ephemeris_start_time.return_value = 0
+            assert self.driver.spacecraft_direction > 0
+            bods2c.assert_called_with('LRO_SC_BUS')
+            spkezr.assert_called_with(self.driver.spacecraft_name, 0, 'J2000', 'None', self.driver.target_name)
+            compute_rotation.assert_called_with(1, -12345)
+            np.testing.assert_array_equal(np.array([[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]), mxv.call_args[0][0])
+            np.testing.assert_array_equal(np.array([1, 1, 1]), mxv.call_args[0][1])
 
     def test_focal2pixel_lines(self):
         with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=[0, 1, 0]) as gdpool, \
@@ -290,7 +291,7 @@ class test_pds_naif(unittest.TestCase):
              patch('ale.drivers.lro_drivers.LroLrocPds3LabelNaifSpiceDriver.spacecraft_direction', \
              new_callable=PropertyMock) as spacecraft_direction:
             spacecraft_direction.return_value = -1
-            np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
+            np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0])
             spacecraft_direction.return_value = 1
             np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
 
@@ -362,17 +363,19 @@ class test_isis_naif(unittest.TestCase):
     def test_spacecraft_direction(self, compute_rotation, from_spice, frame_chain):
         with patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.target_frame_id', \
              new_callable=PropertyMock) as target_frame_id, \
-             patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.sensor_frame_id', \
-             new_callable=PropertyMock) as sensor_frame_id, \
              patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.ephemeris_start_time', \
              new_callable=PropertyMock) as ephemeris_start_time, \
-             patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.ephemeris_stop_time', \
-             new_callable=PropertyMock) as ephemeris_end_time, \
-             patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.sensor_position', \
-             new_callable=PropertyMock) as sensor_position:
-            sensor_position.return_value = [[np.array([50, 50, 50])], [np.array([1, 1, 1])], [0]]
-            assert self.driver.spacecraft_direction < 0
-            compute_rotation.assert_called_with(target_frame_id.return_value, sensor_frame_id.return_value)
+             patch('ale.drivers.lro_drivers.spice.cidfrm', return_value=[-12345]) as cidfrm, \
+             patch('ale.drivers.lro_drivers.spice.scs2e', return_value=0) as scs2e, \
+             patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c, \
+             patch('ale.drivers.lro_drivers.spice.spkezr', return_value=[[1, 1, 1, 1, 1, 1], 0]) as spkezr, \
+             patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv:
+            ephemeris_start_time.return_value = 0
+            assert self.driver.spacecraft_direction > 0
+            spkezr.assert_called_with(self.driver.spacecraft_name, 0, 'J2000', 'None', self.driver.target_name)
+            compute_rotation.assert_called_with(1, -12345)
+            np.testing.assert_array_equal(np.array([[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]), mxv.call_args[0][0])
+            np.testing.assert_array_equal(np.array([1, 1, 1]), mxv.call_args[0][1])
 
     def test_focal2pixel_lines(self):
         with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=[0, 1, 0]) as gdpool, \
@@ -381,6 +384,6 @@ class test_isis_naif(unittest.TestCase):
              patch('ale.drivers.lro_drivers.LroLrocIsisLabelNaifSpiceDriver.spacecraft_direction', \
              new_callable=PropertyMock) as spacecraft_direction:
             spacecraft_direction.return_value = -1
-            np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
+            np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0])
             spacecraft_direction.return_value = 1
             np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
-- 
GitLab