Loading ale/drivers/lro_drivers.py +126 −85 Original line number Diff line number Diff line Loading @@ -12,38 +12,36 @@ from ale.base.label_pds3 import Pds3Label from ale.base.type_sensor import LineScanner class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner): class LroLrocPds3LabelNaifSpiceDriver(NaifSpice, Pds3Label, LineScanner, Driver): """ Driver for reading Lroc NACL, NACR, WAC labels. Requires a Spice mixin to acquire addtional ephemeris and instrument data located exclusively in spice kernels. Driver for reading LROC NACL, NACR (not WAC, it is a push frame) labels. Requires a Spice mixin to acquire addtional ephemeris and instrument data located exclusively in SPICE kernels, A PDS3 label, and the LineScanner and Driver bases. """ @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 are the same ID that spice lib expects as input to bods2c calls. The short text name for the instrument Ignores Wide Angle for now Returns an instrument id uniquely identifying the instrument. Used to acquire instrument codes from Spice Lib bods2c routine. Returns ------- : str instrument id str The short text name for the instrument """ instrument = self.label.get("INSTRUMENT_ID") instrument = super().instrument_id # NACL, NACR, or WAC frame_id = self.label.get("FRAME_ID") if instrument == "LROC" and frame_id == "LEFT": return "LRO_LROCNACL" elif instrument == "LROC" and frame_id == "RIGHT": return "LRO_LROCNACR" # WAC not implemented yet @property def metakernel(self): Loading @@ -52,7 +50,7 @@ class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner) Returns ------- : string : str Path to latest metakernel file """ metakernel_dir = config.lro Loading @@ -69,35 +67,78 @@ class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner) def spacecraft_name(self): """ Spacecraft name used in various SPICE calls to acquire ephemeris data. ephemeris data. LROC NAC img PDS3 labels do not the have SPACECRAFT_NAME keyword, so we override it here to use the label_pds3 property for instrument_host_id Returns ------- : str Spacecraft name """ return "LRO" return self.instrument_host_id @property def sensor_model_version(self): """ Returns ISIS instrument sensor model version number Returns ------- : int sensor model version """ return 2 @property def odtk(self): def detector_start_sample(self): """ Returns the starting sample contained in the image Returns ------- : list Radial distortion coefficients : int Returns the starting sample """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist() return 1 @property def optical_distortion(self): def detector_start_line(self): """ Returns the starting line contained in the image Returns ------- : int Returns the starting line """ return 1 @property def usgscsm_distortion_model(self): """ The distortion model name with its coefficients LRO LROC NAC does not use the default distortion model so we need to overwrite the method packing the distortion model into the ISD. Returns ------- : dict Returns a dict with the model name : dict of the coefficients """ return { "lrolrocnac": { "coefficients": self.odtk, } } return {"lrolrocnac": {"coefficients": self.odtk}} @property def odtk(self): """ The coefficients for the distortion model Returns ------- : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist() tests/pytests/test_lro_drivers.py +48 −106 Original line number Diff line number Diff line from collections import namedtuple from unittest import mock import pytest # 'Mock' the spice module where it is imported from conftest import SimpleSpice, get_mockkernels from collections import namedtuple import ale from ale.drivers import lro_drivers from ale.base import data_naif from ale.base import label_pds3 from unittest.mock import PropertyMock, patch from ale.drivers.lro_drivers import LroLrocPds3LabelNaifSpiceDriver from ale import util # 'Mock' the spice module where it is imported from conftest import SimpleSpice, get_mockkernels from ale.drivers.lro_drivers import LroLrocPds3LabelNaifSpiceDriver simplespice = SimpleSpice() data_naif.spice = simplespice lro_drivers.spice = simplespice label_pds3.spice = simplespice LroLrocPds3LabelNaifSpiceDriver.metakernel = get_mockkernels @pytest.fixture def lro_lroclabel(): return """ PDS_VERSION_ID = PDS3 /*FILE CHARACTERISTICS*/ RECORD_TYPE = FIXED_LENGTH RECORD_BYTES = 5064 FILE_RECORDS = 13313 LABEL_RECORDS = 1 ^IMAGE = 2 /*DATA IDENTIFICATION*/ DATA_SET_ID = "LRO-L-LROC-2-EDR-V1.0" ORIGINAL_PRODUCT_ID = nacl0002fc60 PRODUCT_ID = M128963531LE MISSION_NAME = "LUNAR RECONNAISSANCE ORBITER" MISSION_PHASE_NAME = "NOMINAL MISSION" INSTRUMENT_HOST_NAME = "LUNAR RECONNAISSANCE ORBITER" INSTRUMENT_HOST_ID = LRO INSTRUMENT_NAME = "LUNAR RECONNAISSANCE ORBITER CAMERA" INSTRUMENT_ID = LROC LRO:PREROLL_TIME = 2010-05-20T02:57:44.373 START_TIME = 2010-05-20T02:57:44.720 STOP_TIME = 2010-05-20T02:57:49.235 LRO:SPACECRAFT_CLOCK_PREROLL_COUNT = "1/296017064:22937" SPACECRAFT_CLOCK_START_COUNT = "1/296017064:45694" SPACECRAFT_CLOCK_STOP_COUNT = "1/296017069:13866" ORBIT_NUMBER = 4138 PRODUCER_ID = LRO_LROC_TEAM PRODUCT_CREATION_TIME = 2013-09-16T19:57:12 PRODUCER_INSTITUTION_NAME = "ARIZONA STATE UNIVERSITY" PRODUCT_TYPE = EDR PRODUCT_VERSION_ID = "v1.8" UPLOAD_ID = "SC_2010140_0000_A_V01.txt" /*DATA DESCRIPTION*/ TARGET_NAME = "MOON" RATIONALE_DESC = "TARGET OF OPPORTUNITY" FRAME_ID = LEFT DATA_QUALITY_ID = "0" DATA_QUALITY_DESC = "The DATA_QUALITY_ID is set to an 8-bit value that encodes the following data quality information for the observation. For each bit a value of 0 means FALSE and a value of 1 means TRUE. More information about the data quality ID can be found in the LROC EDR/CDR SIS, section 3.3 'Label and Header Descriptions'. Bit 1: Temperature of focal plane array is out of bounds. Bit 2: Threshold for saturated pixels is reached. Bit 3: Threshold for under-saturated pixels is reached. Bit 4: Observation is missing telemetry packets. Bit 5: SPICE information is bad or missing. Bit 6: Observation or housekeeping information is bad or missing. Bit 7: Spare. Bit 8: Spare." /*ENVIRONMENT*/ LRO:TEMPERATURE_SCS = 4.51 <degC> LRO:TEMPERATURE_FPA = 17.88 <degC> LRO:TEMPERATURE_FPGA = -12.33 <degC> LRO:TEMPERATURE_TELESCOPE = 5.91 <degC> LRO:TEMPERATURE_SCS_RAW = 2740 LRO:TEMPERATURE_FPA_RAW = 2107 LRO:TEMPERATURE_FPGA_RAW = 3418 LRO:TEMPERATURE_TELESCOPE_RAW = 2675 /*IMAGING PARAMETERS*/ CROSSTRACK_SUMMING = 1 BANDWIDTH = 300 <nm> CENTER_FILTER_WAVELENGTH = 600 <nm> LINE_EXPOSURE_DURATION = 0.337600 <ms> LRO:LINE_EXPOSURE_CODE = 0 LRO:DAC_RESET_LEVEL = 198 LRO:CHANNEL_A_OFFSET = 60 LRO:CHANNEL_B_OFFSET = 123 LRO:COMPAND_CODE = 3 LRO:LINE_CODE = 13 LRO:BTERM = (0,16,69,103,128) LRO:MTERM = (0.5,0.25,0.125,0.0625,0.03125) LRO:XTERM = (0,64,424,536,800) LRO:COMPRESSION_FLAG = 1 LRO:MODE = 7 /*DATA OBJECT*/ OBJECT = IMAGE LINES = 13312 LINE_SAMPLES = 5064 SAMPLE_BITS = 8 SAMPLE_TYPE = LSB_INTEGER UNIT = "RAW_INSTRUMENT_COUNT" MD5_CHECKSUM = "0fe91f4b2e93083ee0093e7c8d05f3bc" END_OBJECT = IMAGE END """ def test_lro_creation(lro_lroclabel): #with LroLrocPds3LabelNaifSpiceDriver(lro_lroclabel) as m: # d = m.to_dict() # assert isinstance(d, dict) # Need to insert new tests here, one for each property unique to this driver assert True def driver(): return LroLrocPds3LabelNaifSpiceDriver("") @patch('ale.base.label_pds3.Pds3Label.instrument_id', 'LROC') def test_instrument_id_left(driver): with patch.dict(driver.label, {'FRAME_ID':'LEFT'}) as f: assert driver.instrument_id == 'LRO_LROCNACL' @patch('ale.base.label_pds3.Pds3Label.instrument_id', 'LROC') def test_instrument_id_right(driver): with patch.dict(driver.label, {'FRAME_ID':'RIGHT'}) as f: assert driver.instrument_id == 'LRO_LROCNACR' @patch('ale.base.label_pds3.Pds3Label.instrument_host_id', 'LRO') def test_spacecraft_name(driver): assert driver.spacecraft_name == 'LRO' def test_sensor_model_version(driver): assert driver.sensor_model_version == 2 def test_detector_start_sample(driver): assert driver.detector_start_sample == 1 def test_detector_start_line(driver): assert driver.detector_start_sample == 1 @patch('ale.base.data_naif.NaifSpice.ikid', 123) def test_odtk(driver): assert driver.odtk == [1.0] @patch('ale.base.data_naif.NaifSpice.ikid', 123) def test_usgscsm_distortion_model(driver): distortion_model = driver.usgscsm_distortion_model assert distortion_model['lrolrocnac']['coefficients'] == [1.0] Loading
ale/drivers/lro_drivers.py +126 −85 Original line number Diff line number Diff line Loading @@ -12,38 +12,36 @@ from ale.base.label_pds3 import Pds3Label from ale.base.type_sensor import LineScanner class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner): class LroLrocPds3LabelNaifSpiceDriver(NaifSpice, Pds3Label, LineScanner, Driver): """ Driver for reading Lroc NACL, NACR, WAC labels. Requires a Spice mixin to acquire addtional ephemeris and instrument data located exclusively in spice kernels. Driver for reading LROC NACL, NACR (not WAC, it is a push frame) labels. Requires a Spice mixin to acquire addtional ephemeris and instrument data located exclusively in SPICE kernels, A PDS3 label, and the LineScanner and Driver bases. """ @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 are the same ID that spice lib expects as input to bods2c calls. The short text name for the instrument Ignores Wide Angle for now Returns an instrument id uniquely identifying the instrument. Used to acquire instrument codes from Spice Lib bods2c routine. Returns ------- : str instrument id str The short text name for the instrument """ instrument = self.label.get("INSTRUMENT_ID") instrument = super().instrument_id # NACL, NACR, or WAC frame_id = self.label.get("FRAME_ID") if instrument == "LROC" and frame_id == "LEFT": return "LRO_LROCNACL" elif instrument == "LROC" and frame_id == "RIGHT": return "LRO_LROCNACR" # WAC not implemented yet @property def metakernel(self): Loading @@ -52,7 +50,7 @@ class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner) Returns ------- : string : str Path to latest metakernel file """ metakernel_dir = config.lro Loading @@ -69,35 +67,78 @@ class LroLrocPds3LabelNaifSpiceDriver(Driver, NaifSpice, Pds3Label, LineScanner) def spacecraft_name(self): """ Spacecraft name used in various SPICE calls to acquire ephemeris data. ephemeris data. LROC NAC img PDS3 labels do not the have SPACECRAFT_NAME keyword, so we override it here to use the label_pds3 property for instrument_host_id Returns ------- : str Spacecraft name """ return "LRO" return self.instrument_host_id @property def sensor_model_version(self): """ Returns ISIS instrument sensor model version number Returns ------- : int sensor model version """ return 2 @property def odtk(self): def detector_start_sample(self): """ Returns the starting sample contained in the image Returns ------- : list Radial distortion coefficients : int Returns the starting sample """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist() return 1 @property def optical_distortion(self): def detector_start_line(self): """ Returns the starting line contained in the image Returns ------- : int Returns the starting line """ return 1 @property def usgscsm_distortion_model(self): """ The distortion model name with its coefficients LRO LROC NAC does not use the default distortion model so we need to overwrite the method packing the distortion model into the ISD. Returns ------- : dict Returns a dict with the model name : dict of the coefficients """ return { "lrolrocnac": { "coefficients": self.odtk, } } return {"lrolrocnac": {"coefficients": self.odtk}} @property def odtk(self): """ The coefficients for the distortion model Returns ------- : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist()
tests/pytests/test_lro_drivers.py +48 −106 Original line number Diff line number Diff line from collections import namedtuple from unittest import mock import pytest # 'Mock' the spice module where it is imported from conftest import SimpleSpice, get_mockkernels from collections import namedtuple import ale from ale.drivers import lro_drivers from ale.base import data_naif from ale.base import label_pds3 from unittest.mock import PropertyMock, patch from ale.drivers.lro_drivers import LroLrocPds3LabelNaifSpiceDriver from ale import util # 'Mock' the spice module where it is imported from conftest import SimpleSpice, get_mockkernels from ale.drivers.lro_drivers import LroLrocPds3LabelNaifSpiceDriver simplespice = SimpleSpice() data_naif.spice = simplespice lro_drivers.spice = simplespice label_pds3.spice = simplespice LroLrocPds3LabelNaifSpiceDriver.metakernel = get_mockkernels @pytest.fixture def lro_lroclabel(): return """ PDS_VERSION_ID = PDS3 /*FILE CHARACTERISTICS*/ RECORD_TYPE = FIXED_LENGTH RECORD_BYTES = 5064 FILE_RECORDS = 13313 LABEL_RECORDS = 1 ^IMAGE = 2 /*DATA IDENTIFICATION*/ DATA_SET_ID = "LRO-L-LROC-2-EDR-V1.0" ORIGINAL_PRODUCT_ID = nacl0002fc60 PRODUCT_ID = M128963531LE MISSION_NAME = "LUNAR RECONNAISSANCE ORBITER" MISSION_PHASE_NAME = "NOMINAL MISSION" INSTRUMENT_HOST_NAME = "LUNAR RECONNAISSANCE ORBITER" INSTRUMENT_HOST_ID = LRO INSTRUMENT_NAME = "LUNAR RECONNAISSANCE ORBITER CAMERA" INSTRUMENT_ID = LROC LRO:PREROLL_TIME = 2010-05-20T02:57:44.373 START_TIME = 2010-05-20T02:57:44.720 STOP_TIME = 2010-05-20T02:57:49.235 LRO:SPACECRAFT_CLOCK_PREROLL_COUNT = "1/296017064:22937" SPACECRAFT_CLOCK_START_COUNT = "1/296017064:45694" SPACECRAFT_CLOCK_STOP_COUNT = "1/296017069:13866" ORBIT_NUMBER = 4138 PRODUCER_ID = LRO_LROC_TEAM PRODUCT_CREATION_TIME = 2013-09-16T19:57:12 PRODUCER_INSTITUTION_NAME = "ARIZONA STATE UNIVERSITY" PRODUCT_TYPE = EDR PRODUCT_VERSION_ID = "v1.8" UPLOAD_ID = "SC_2010140_0000_A_V01.txt" /*DATA DESCRIPTION*/ TARGET_NAME = "MOON" RATIONALE_DESC = "TARGET OF OPPORTUNITY" FRAME_ID = LEFT DATA_QUALITY_ID = "0" DATA_QUALITY_DESC = "The DATA_QUALITY_ID is set to an 8-bit value that encodes the following data quality information for the observation. For each bit a value of 0 means FALSE and a value of 1 means TRUE. More information about the data quality ID can be found in the LROC EDR/CDR SIS, section 3.3 'Label and Header Descriptions'. Bit 1: Temperature of focal plane array is out of bounds. Bit 2: Threshold for saturated pixels is reached. Bit 3: Threshold for under-saturated pixels is reached. Bit 4: Observation is missing telemetry packets. Bit 5: SPICE information is bad or missing. Bit 6: Observation or housekeeping information is bad or missing. Bit 7: Spare. Bit 8: Spare." /*ENVIRONMENT*/ LRO:TEMPERATURE_SCS = 4.51 <degC> LRO:TEMPERATURE_FPA = 17.88 <degC> LRO:TEMPERATURE_FPGA = -12.33 <degC> LRO:TEMPERATURE_TELESCOPE = 5.91 <degC> LRO:TEMPERATURE_SCS_RAW = 2740 LRO:TEMPERATURE_FPA_RAW = 2107 LRO:TEMPERATURE_FPGA_RAW = 3418 LRO:TEMPERATURE_TELESCOPE_RAW = 2675 /*IMAGING PARAMETERS*/ CROSSTRACK_SUMMING = 1 BANDWIDTH = 300 <nm> CENTER_FILTER_WAVELENGTH = 600 <nm> LINE_EXPOSURE_DURATION = 0.337600 <ms> LRO:LINE_EXPOSURE_CODE = 0 LRO:DAC_RESET_LEVEL = 198 LRO:CHANNEL_A_OFFSET = 60 LRO:CHANNEL_B_OFFSET = 123 LRO:COMPAND_CODE = 3 LRO:LINE_CODE = 13 LRO:BTERM = (0,16,69,103,128) LRO:MTERM = (0.5,0.25,0.125,0.0625,0.03125) LRO:XTERM = (0,64,424,536,800) LRO:COMPRESSION_FLAG = 1 LRO:MODE = 7 /*DATA OBJECT*/ OBJECT = IMAGE LINES = 13312 LINE_SAMPLES = 5064 SAMPLE_BITS = 8 SAMPLE_TYPE = LSB_INTEGER UNIT = "RAW_INSTRUMENT_COUNT" MD5_CHECKSUM = "0fe91f4b2e93083ee0093e7c8d05f3bc" END_OBJECT = IMAGE END """ def test_lro_creation(lro_lroclabel): #with LroLrocPds3LabelNaifSpiceDriver(lro_lroclabel) as m: # d = m.to_dict() # assert isinstance(d, dict) # Need to insert new tests here, one for each property unique to this driver assert True def driver(): return LroLrocPds3LabelNaifSpiceDriver("") @patch('ale.base.label_pds3.Pds3Label.instrument_id', 'LROC') def test_instrument_id_left(driver): with patch.dict(driver.label, {'FRAME_ID':'LEFT'}) as f: assert driver.instrument_id == 'LRO_LROCNACL' @patch('ale.base.label_pds3.Pds3Label.instrument_id', 'LROC') def test_instrument_id_right(driver): with patch.dict(driver.label, {'FRAME_ID':'RIGHT'}) as f: assert driver.instrument_id == 'LRO_LROCNACR' @patch('ale.base.label_pds3.Pds3Label.instrument_host_id', 'LRO') def test_spacecraft_name(driver): assert driver.spacecraft_name == 'LRO' def test_sensor_model_version(driver): assert driver.sensor_model_version == 2 def test_detector_start_sample(driver): assert driver.detector_start_sample == 1 def test_detector_start_line(driver): assert driver.detector_start_sample == 1 @patch('ale.base.data_naif.NaifSpice.ikid', 123) def test_odtk(driver): assert driver.odtk == [1.0] @patch('ale.base.data_naif.NaifSpice.ikid', 123) def test_usgscsm_distortion_model(driver): distortion_model = driver.usgscsm_distortion_model assert distortion_model['lrolrocnac']['coefficients'] == [1.0]