Skip to content
Snippets Groups Projects
Unverified Commit 1b5a5969 authored by Amy Stamile's avatar Amy Stamile Committed by GitHub
Browse files

Initial MSL Mastcam Driver (#491)

* Initial MSL Mastcam Driver

* added docs

* added cahvor params and sensor frame id to driver.

* added unit tests

* added test data

* small updates to cahvor camera model function

* added focal2pixel functions

* fixes docs
parent beafc19a
No related branches found
No related tags found
No related merge requests found
...@@ -288,19 +288,23 @@ class Pds3Label(): ...@@ -288,19 +288,23 @@ class Pds3Label():
""" """
# The EXPOSURE_DURATION may either be stored as a (value, unit) or just a value # The EXPOSURE_DURATION may either be stored as a (value, unit) or just a value
if 'EXPOSURE_DURATION' in self.label: if 'EXPOSURE_DURATION' in self.label:
key = self.label['EXPOSURE_DURATION']
elif 'INSTRUMENT_STATE_PARMS' in self.label:
key = self.label['INSTRUMENT_STATE_PARMS']['EXPOSURE_DURATION']
else:
return self.line_exposure_duration
try: try:
unit = self.label['EXPOSURE_DURATION'].units unit = key.units
unit = unit.lower() unit = unit.lower()
if unit == "ms" or unit == "msec" or unit == "millisecond": if unit == "ms" or unit == "msec" or unit == "millisecond":
return self.label['EXPOSURE_DURATION'].value * 0.001 return key.value * 0.001
else: else:
return self.label['EXPOSURE_DURATION'].value return key.value
# With no units, assume milliseconds # With no units, assume milliseconds
except: except:
return self.label['EXPOSURE_DURATION'] * 0.001 return key * 0.001
else:
return self.line_exposure_duration
# Consider expanding this to handle units # Consider expanding this to handle units
......
import numpy as np
import spiceypy as spice
from ale.base.data_naif import NaifSpice
from ale.base.label_pds3 import Pds3Label
from ale.base.type_sensor import Framer
from ale.base.type_distortion import NoDistortion
from ale.base.base import Driver
class MslMastcamPds3NaifSpiceDriver(Framer, Pds3Label, NaifSpice, NoDistortion, Driver):
@property
def spacecraft_name(self):
"""
Spacecraft name used in various SPICE calls to acquire
ephemeris data. MSL Mastcam img PDS3 labels do not the have a SPACECRAFT_NAME keyword,
so we override it here to find INSTRUMENT_HOST_NAME in the label.
Returns
-------
: str
Spacecraft name
"""
return self.instrument_host_name
@property
def instrument_id(self):
"""
Returns an instrument id for uniquely identifying the instrument, but often
also used to be piped into Spice Kernels to acquire IKIDs. Therefore they
the same ID the Spice expects in bods2c calls.
Expects instrument_id to be defined in the Pds3Label mixin. This should
be a string of the form MAST_RIGHT or MAST_LEFT.
Returns
-------
: str
instrument id
"""
lookup = {
"MAST_RIGHT": 'MASTCAM_RIGHT',
"MAST_LEFT": 'MASTCAM_LEFT'
}
return self.instrument_host_id + "_" + lookup[super().instrument_id]
@property
def cahvor_camera_dict(self):
"""
Gets the PVL group that represents the CAHVOR camera model
for the site
Returns
-------
: dict
A dict of CAHVOR keys to use in other methods
"""
if not hasattr(self, '_cahvor_camera_params'):
camera_model_group = self.label.get('GEOMETRIC_CAMERA_MODEL_PARMS', None)
self._cahvor_camera_params = {}
self._cahvor_camera_params['C'] = np.array(camera_model_group["MODEL_COMPONENT_1"])
self._cahvor_camera_params['A'] = np.array(camera_model_group["MODEL_COMPONENT_2"])
self._cahvor_camera_params['H'] = np.array(camera_model_group["MODEL_COMPONENT_3"])
self._cahvor_camera_params['V'] = np.array(camera_model_group["MODEL_COMPONENT_4"])
if len(camera_model_group.get('MODEL_COMPONENT_ID', ['C', 'A', 'H', 'V'])) == 6:
self._cahvor_camera_params['O'] = np.array(camera_model_group["MODEL_COMPONENT_5"])
self._cahvor_camera_params['R'] = np.array(camera_model_group["MODEL_COMPONENT_6"])
return self._cahvor_camera_params
@property
def sensor_frame_id(self):
"""
Returns the Naif ID code for the site reference frame
Expects REFERENCE_COORD_SYSTEM_INDEX to be defined in the camera
PVL group.
Returns
-------
: int
Naif ID code for the sensor frame
"""
if not hasattr(self, "_site_frame_id"):
site_frame = "MSL_SITE_" + str(self.label["GEOMETRIC_CAMERA_MODEL_PARMS"]["REFERENCE_COORD_SYSTEM_INDEX"][0])
self._site_frame_id= spice.bods2c(site_frame)
return self._site_frame_id
@property
def focal2pixel_lines(self):
"""
Expects pixel_size to be defined.
Returns
-------
: list<double>
focal plane to detector lines
"""
return [0, 1/self.pixel_size, 0]
@property
def focal2pixel_samples(self):
"""
Expects pixel_size to be defined.
Returns
-------
: list<double>
focal plane to detector samples
"""
return [1/self.pixel_size, 0, 0]
@property
def sensor_model_version(self):
"""
Returns
-------
: int
ISIS sensor model version
"""
return 1
import numpy as np
import unittest
import ale
from ale.drivers.msl_drivers import MslMastcamPds3NaifSpiceDriver
from conftest import get_image_label
from unittest.mock import PropertyMock, patch
class test_mastcam_pds_naif(unittest.TestCase):
def setUp(self):
label = get_image_label("1664MR0086340000802438C00_DRCL", "pds3")
self.driver = MslMastcamPds3NaifSpiceDriver(label)
def test_instrument_id(self):
assert self.driver.instrument_id == "MSL_MASTCAM_RIGHT"
def test_spacecraft_name(self):
assert self.driver.spacecraft_name == "MARS SCIENCE LABORATORY"
def test_exposure_duration(self):
np.testing.assert_almost_equal(self.driver.exposure_duration, 0.0102)
def test_cahvor_camera_dict(self):
cahvor_camera_dict = self.driver.cahvor_camera_dict
assert len(cahvor_camera_dict) == 4
np.testing.assert_allclose(cahvor_camera_dict['C'], [6.831825e-01, 5.243722e-01, -1.955875e+00])
np.testing.assert_allclose(cahvor_camera_dict['A'], [-3.655151e-01, 5.396012e-01, 7.584387e-01])
np.testing.assert_allclose(cahvor_camera_dict['H'], [-1.156881e+04, -7.518712e+03, 6.618359e+02])
np.testing.assert_allclose(cahvor_camera_dict['V'], [5.843885e+03, -8.213856e+03, 9.438374e+03])
def test_sensor_frame_id(self):
with patch('ale.drivers.msl_drivers.spice.bods2c', return_value=-76562) as bods2c:
assert self.driver.sensor_frame_id == -76562
bods2c.assert_called_with("MSL_SITE_62")
# uncomment once cahvor mixin is merged
# def test_focal2pixel_lines(self):
# np.testing.assert_allclose(self.driver.focal2pixel_lines, [0, 137968.44341513602, 0])
# def test_focal2pixel_samples(self):
# np.testing.assert_allclose(self.driver.focal2pixel_samples, [137968.44341513602, 0, 0])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment