From 9cc59a96059b946966b4b9de4291d831554ee5d3 Mon Sep 17 00:00:00 2001 From: Jesse Mapel Date: Thu, 6 Jun 2019 13:07:13 -0700 Subject: [PATCH] Clean up to get CTX driver working (#186) * Clean up to get CTX driver working * More CTX usgscsm clean up * Fixed test failures * Made PDS3 exposure duration fall back to Line Scan Rate --- ale/__init__.py | 1 + ale/base/data_naif.py | 21 +++++++++-------- ale/base/label_pds3.py | 26 +++++++++++---------- ale/base/type_sensor.py | 4 ++-- ale/drivers/__init__.py | 2 +- ale/drivers/mro_drivers.py | 5 ++-- ale/formatters/usgscsm_formatter.py | 20 ++++++++-------- tests/pytests/conftest.py | 2 ++ tests/pytests/test_mro_drivers.py | 4 ++++ tests/pytests/test_usgscsm_formatter.py | 31 +++++++++++++------------ 10 files changed, 64 insertions(+), 52 deletions(-) diff --git a/ale/__init__.py b/ale/__init__.py index b649ee8..5ca10dc 100644 --- a/ale/__init__.py +++ b/ale/__init__.py @@ -1,2 +1,3 @@ from . import drivers +from . import formatters from .drivers import load, loads diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 4db795a..d8af3b7 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -76,10 +76,8 @@ class NaifSpice(): @property def target_frame_id(self): - 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 + frame_info = spice.cidfrm(self.target_id) + return frame_info[0] @property def sensor_frame_id(self): @@ -132,7 +130,7 @@ class NaifSpice(): 'NONE', self.target_name) - return [sun_state[:4].tolist()], [sun_state[3:6].tolist()], self.center_ephemeris_time + return [sun_state[:4].tolist()], [sun_state[3:6].tolist()], [self.center_ephemeris_time] @property def sensor_position(self): @@ -180,16 +178,16 @@ class NaifSpice(): body_times = np.array(self.ephemeris_time) for i, time in enumerate(self.ephemeris_time): sensor2j2000 = spice.pxform( - self.sensor_frame_id, - j2000_id, + spice.frmnam(self.sensor_frame_id), + spice.frmnam(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, + spice.frmnam(self.target_frame_id), + spice.frmnam(j2000_id), time) q_body = spice.m2q(body2j2000) body_quats[i,:3] = q_body[1:] @@ -241,7 +239,10 @@ class NaifSpice(): @property def ephemeris_stop_time(self): - return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_stop_count) + if self.spacecraft_clock_stop_count: + return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_stop_count) + else: + return spice.str2et(self.utc_stop_time.strftime("%Y-%m-%d %H:%M:%S")) @property def center_ephemeris_time(self): diff --git a/ale/base/label_pds3.py b/ale/base/label_pds3.py index 0695f0a..024b6e0 100644 --- a/ale/base/label_pds3.py +++ b/ale/base/label_pds3.py @@ -230,18 +230,20 @@ class Pds3Label(): Returns the exposure duration in seconds from the PDS3 label. """ # The EXPOSURE_DURATION may either be stored as a (value, unit) or just a value - try: - unit = self.label['EXPOSURE_DURATION'].units - unit = unit.lower() - if unit == "ms" or unit == "msec": - return self.label['EXPOSURE_DURATION'].value * 0.001 - else: - return self.label['EXPOSURE_DURATION'].value - - # With no units, assume milliseconds - except: - # NOTE: If the key does not exist at all, this will cause an error about exception within an exception - return self.label['EXPOSURE_DURATION'] * 0.001 + if 'EXPOSURE_DURATION' in self.label: + try: + unit = self.label['EXPOSURE_DURATION'].units + unit = unit.lower() + if unit == "ms" or unit == "msec": + return self.label['EXPOSURE_DURATION'].value * 0.001 + else: + return self.label['EXPOSURE_DURATION'].value + + # With no units, assume milliseconds + except: + return self.label['EXPOSURE_DURATION'] * 0.001 + else: + return self.line_exposure_duration # Consider expanding this to handle units diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py index 2d074aa..0ca7ad0 100644 --- a/ale/base/type_sensor.py +++ b/ale/base/type_sensor.py @@ -24,11 +24,11 @@ class LineScanner(): 2d list of scan rates in the form: [[start_line, line_time, exposure_duration], ...] """ t0_ephemeris = self.ephemeris_start_time - self.center_ephemeris_time - return [[float(self.starting_detector_line)], [t0_ephemeris], [self._line_exposure_duration]] + return [[0.5], [t0_ephemeris], [self.exposure_duration]] @property def ephemeris_time(self): - return np.linspace(self.ephemeris_start_time, self.ephemeris_stop_time, self.image_lines) + return np.linspace(self.ephemeris_start_time, self.ephemeris_stop_time, self.image_lines / 64) class Framer(): @property diff --git a/ale/drivers/__init__.py b/ale/drivers/__init__.py index 5dc43ca..76f2bd4 100644 --- a/ale/drivers/__init__.py +++ b/ale/drivers/__init__.py @@ -16,7 +16,7 @@ from abc import ABC import datetime # dynamically load drivers -__all__ = [os.path.splitext(os.path.basename(d))[0] for d in glob(os.path.join(os.path.dirname(__file__), '*_driver.py'))] +__all__ = [os.path.splitext(os.path.basename(d))[0] for d in glob(os.path.join(os.path.dirname(__file__), '*_drivers.py'))] __driver_modules__ = [importlib.import_module('.'+m, package='ale.drivers') for m in __all__] drivers = dict(chain.from_iterable(inspect.getmembers(dmod, lambda x: inspect.isclass(x) and "_driver" in x.__module__) for dmod in __driver_modules__)) diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 71f3ed4..01a64ff 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -164,7 +164,8 @@ class MroCtxPds3LabelNaifSpiceDriver(Pds3Label, NaifSpice, LineScanner, RadialDi instrument id """ id_lookup = { - 'CONTEXT CAMERA':'MRO_CTX' + 'CONTEXT CAMERA':'MRO_CTX', + 'CTX':'MRO_CTX' } return id_lookup[super().instrument_id] @@ -174,7 +175,7 @@ class MroCtxPds3LabelNaifSpiceDriver(Pds3Label, NaifSpice, LineScanner, RadialDi """ Returns the spacecraft name used in various Spice calls to acquire ephemeris data. - + Returns ------- : str diff --git a/ale/formatters/usgscsm_formatter.py b/ale/formatters/usgscsm_formatter.py index dfc7b1e..703a61e 100644 --- a/ale/formatters/usgscsm_formatter.py +++ b/ale/formatters/usgscsm_formatter.py @@ -24,15 +24,15 @@ def to_usgscsm(driver): isd_data['radii'] = { 'semimajor' : body_radii[0], 'semiminor' : body_radii[1], - 'unit' : 'm' + 'unit' : 'km' } - positions, velocities, position_times = driver.positions + positions, velocities, position_times = driver.sensor_position isd_data['sensor_position'] = { 'positions' : positions, 'velocities' : velocities, 'unit' : 'm' } - sun_positions, sun_velocities, _ = driver.sun_positions + sun_positions, sun_velocities, _ = driver.sun_position isd_data['sun_position'] = { 'positions' : sun_positions, 'velocities' : sun_velocities, @@ -59,15 +59,15 @@ def to_usgscsm(driver): 'line' : driver.detector_center_line, 'sample' : driver.detector_center_sample } - isd_data['starting_detector_line'] = driver.starting_detector_line - isd_data['starting_detector_sample'] = driver.starting_detector_sample + isd_data['starting_detector_line'] = driver.detector_start_line + isd_data['starting_detector_sample'] = driver.detector_start_sample isd_data['focal2pixel_lines'] = driver.focal2pixel_lines isd_data['focal2pixel_samples'] = driver.focal2pixel_samples isd_data['optical_distortion'] = driver.usgscsm_distortion_model # general information - isd_data['image_lines'] = driver.line_count - isd_data['image_samples'] = driver.sample_count + isd_data['image_lines'] = driver.image_lines + isd_data['image_samples'] = driver.image_samples isd_data['name_platform'] = driver.platform_name isd_data['name_sensor'] = driver.sensor_name isd_data['reference_height'] = { @@ -81,9 +81,9 @@ def to_usgscsm(driver): isd_data['name_model'] = 'USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL' isd_data['interpolation_method'] = 'lagrange' start_lines, start_times, scan_rates = driver.line_scan_rate - center_time = (driver.stop_time + start_times[0]) / 2 - isd_data['line_scan_rate'] = [[line, time - center_time, rate] for line, time, rate in zip(start_lines, start_times, scan_rates)] - isd_data['starting_ephemeris_time'] = start_times[0] + center_time = (driver.ephemeris_stop_time + driver.ephemeris_start_time) / 2 + isd_data['line_scan_rate'] = [[line, time, rate] for line, time, rate in zip(start_lines, start_times, scan_rates)] + isd_data['starting_ephemeris_time'] = driver.ephemeris_start_time isd_data['center_ephemeris_time'] = center_time isd_data['t0_ephemeris'] = position_times[0] - center_time if len(position_times) > 1: diff --git a/tests/pytests/conftest.py b/tests/pytests/conftest.py index f799883..2ba8317 100644 --- a/tests/pytests/conftest.py +++ b/tests/pytests/conftest.py @@ -5,6 +5,8 @@ class SimpleSpice(): return 0.1 def bods2c(self, x): return -12345 + def frmnam(self, id): + return 'Test_Frame' def gdpool(self, key, x, length): return np.ones(length) def gipool(self, key, x, length): diff --git a/tests/pytests/test_mro_drivers.py b/tests/pytests/test_mro_drivers.py index 487b867..5f1ee8a 100644 --- a/tests/pytests/test_mro_drivers.py +++ b/tests/pytests/test_mro_drivers.py @@ -37,6 +37,10 @@ def test_instrument_id_pds3(Pds3NaifDriver): def test_spacecraft_name_pds3(Pds3NaifDriver): assert Pds3NaifDriver.spacecraft_name == 'MRO' +@patch('ale.base.label_pds3.Pds3Label.line_exposure_duration', 12.1) +def test_exposure_duration_pds3(Pds3NaifDriver): + assert Pds3NaifDriver.exposure_duration == 12.1 + def test_detector_start_line_pds3(Pds3NaifDriver): assert Pds3NaifDriver.detector_start_line == 1 diff --git a/tests/pytests/test_usgscsm_formatter.py b/tests/pytests/test_usgscsm_formatter.py index 35db9e0..ec31791 100644 --- a/tests/pytests/test_usgscsm_formatter.py +++ b/tests/pytests/test_usgscsm_formatter.py @@ -13,7 +13,7 @@ class TestLineScanner(LineScanner): """ @property def line_scan_rate(self): - return [[0.5], [800], [0.01]] + return [[0.5], [-50], [0.01]] @pytest.fixture @@ -37,12 +37,12 @@ def test_line_scan_driver(): sensor = FrameNode(1010, parent=spacecraft, rotation=sensor_rotation) driver = TestLineScanner() driver.target_body_radii = (1100, 1000) - driver.positions = ( + driver.sensor_position = ( [[0, 1, 2], [3, 4, 5]], [[0, -1, -2], [-3, -4, -5]], [800, 900] ) - driver.sun_positions = ( + driver.sun_position = ( [[0, 1, 2], [3, 4, 5]], [[0, -1, -2], [-3, -4, -5]], [800, 900] @@ -55,8 +55,8 @@ def test_line_scan_driver(): driver.focal_length = 500 driver.detector_center_line = 0.5 driver.detector_center_sample = 512 - driver.starting_detector_line = 0 - driver.starting_detector_sample = 8 + driver.detector_start_line = 0 + driver.detector_start_sample = 8 driver.focal2pixel_lines = [0.1, 0.2, 0.3] driver.focal2pixel_samples = [0.3, 0.2, 0.1] driver.usgscsm_distortion_model = { @@ -64,11 +64,12 @@ def test_line_scan_driver(): 'coefficients' : [0.0, 1.0, 0.1] } } - driver.line_count = 10000 - driver.sample_count = 1024 + driver.image_lines = 10000 + driver.image_samples = 1024 driver.platform_name = 'Test Platform' driver.sensor_name = 'Test Line Scan Sensor' - driver.stop_time = 900 + driver.ephemeris_stop_time = 900 + driver.ephemeris_start_time = 800 return driver @@ -94,12 +95,12 @@ def test_frame_driver(): sensor = FrameNode(1010, parent=spacecraft, rotation=sensor_rotation) driver = Framer() driver.target_body_radii = (1100, 1000) - driver.positions = ( + driver.sensor_position = ( [[0, 1, 2]], [[0, -1, -2]], [850] ) - driver.sun_positions = ( + driver.sun_position = ( [[0, 1, 2]], [[0, -1, -2]], [850] @@ -112,8 +113,8 @@ def test_frame_driver(): driver.focal_length = 500 driver.detector_center_line = 256 driver.detector_center_sample = 512 - driver.starting_detector_line = 0 - driver.starting_detector_sample = 8 + driver.detector_start_line = 0 + driver.detector_start_sample = 8 driver.focal2pixel_lines = [0.1, 0.2, 0.3] driver.focal2pixel_samples = [0.3, 0.2, 0.1] driver.usgscsm_distortion_model = { @@ -121,8 +122,8 @@ def test_frame_driver(): 'coefficients' : [0.0, 1.0, 0.1] } } - driver.line_count = 512 - driver.sample_count = 1024 + driver.image_lines = 512 + driver.image_samples = 1024 driver.platform_name = 'Test Platform' driver.sensor_name = 'Test Frame Sensor' @@ -184,7 +185,7 @@ def test_radii(test_frame_driver): radii_obj = isd['radii'] assert radii_obj['semimajor'] == 1100 assert radii_obj['semiminor'] == 1000 - assert radii_obj['unit'] == 'm' + assert radii_obj['unit'] == 'km' def test_reference_height(test_frame_driver): isd = json.loads(usgscsm_formatter.to_usgscsm(test_frame_driver)) -- GitLab