Loading ale/drivers/lro_drivers.py +156 −3 Original line number Diff line number Diff line Loading @@ -892,6 +892,44 @@ class LroLrocWacIsisLabelIsisSpiceDriver(PushFrame, IsisLabel, IsisSpice, Radial return 2 @property def filter_number(self): """ Return the filter number from the cub label Returns ------- : int The filter number """ try: return self.label['IsisCube']['BandBin']['FilterNumber'][0] except: return self.label['IsisCube']['BandBin']['FilterNumber'] @property def fikid(self): """ Naif ID code of the filter dependent instrument codes. Expects ikid to be defined. This should be the integer Naif ID code for the instrument. Returns ------- : int Naif ID code used in calculating focal length """ if self.instrument_id == "LRO_LROCWAC_UV": base = -85640 elif self.instrument_id == "LRO_LROCWAC_VIS": base = -85630 fikid = base - self.filter_number return fikid @property def odtk(self): """ Loading @@ -902,7 +940,9 @@ class LroLrocWacIsisLabelIsisSpiceDriver(PushFrame, IsisLabel, IsisSpice, Radial : list Radial distortion coefficients. """ return [self.naif_keywords.get('INS{}_OD_K'.format(self.ikid), None)] coeffs = self.naif_keywords.get('INS{}_OD_K'.format(self.fikid), None) coeffs = [x * -1 for x in coeffs] return coeffs @property Loading Loading @@ -989,6 +1029,12 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def sensor_name(self): """ Returns ------- : String The name of the spacecraft """ return self.label['IsisCube']['Instrument']['SpacecraftName'] Loading @@ -1002,7 +1048,9 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial : list Radial distortion coefficients. """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 3).tolist() coeffs = spice.gdpool('INS{}_OD_K'.format(self.fikid), 0, 3).tolist() coeffs = [x * -1 for x in coeffs] return coeffs @property Loading @@ -1028,7 +1076,13 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def framelets_flipped(self): return self.label['IsisCube']['Instrument']['SpacecraftName'] == "Yes" """ Returns ------- : boolean True if framelets are flipped, else false """ return self.label['IsisCube']['Instrument']['DataFlipped'] == "Yes" @property Loading @@ -1041,12 +1095,111 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def num_frames(self): """ Number of frames in the image Returns ------- : int Number of frames in the image """ return self.image_lines // (self.framelet_height // self.sampling_factor) @property def framelet_height(self): """ Return the number of lines in a framelet. Returns ------- : int The number of lines in a framelet """ if self.instrument_id == "LRO_LROCWAC_UV": return 16 elif self.instrument_id == "LRO_LROCWAC_VIS": return 14 @property def filter_number(self): """ Return the filter number from the cub label Returns ------- : int The filter number """ try: return self.label['IsisCube']['BandBin']['FilterNumber'][0] except: return self.label['IsisCube']['BandBin']['FilterNumber'] @property def fikid(self): """ Naif ID code of the filter dependent instrument codes. Expects ikid to be defined. This should be the integer Naif ID code for the instrument. Returns ------- : int Naif ID code used in calculating focal length """ if self.instrument_id == "LRO_LROCWAC_UV": base = -85640 elif self.instrument_id == "LRO_LROCWAC_VIS": base = -85630 fikid = base - self.filter_number return fikid @property def pixel2focal_x(self): """ Expects fikid to be defined. This must be the integer Naif id code of the filter Returns ------- : list<double> detector to focal plane x """ return list(spice.gdpool('INS{}_TRANSX'.format(self.fikid), 0, 3)) @property def pixel2focal_y(self): """ Expects fikid to be defined. This must be the integer Naif id code of the filter Returns ------- : list<double> detector to focal plane y """ return list(spice.gdpool('INS{}_TRANSY'.format(self.fikid), 0, 3)) @property def detector_start_line(self): """ Filter-specific starting line Returns ------- : int Zero based Detector line corresponding to the first image line """ offset = list(spice.gdpool('INS{}_FILTER_OFFSET'.format(self.fikid), 0, 3)) try: # If multiple items are present, use the first one offset = offset[0] except (IndexError, TypeError): pass return super().detector_start_line + offset tests/pytests/test_lro_drivers.py +34 −28 Original line number Diff line number Diff line Loading @@ -276,21 +276,17 @@ class test_wac_isis_naif(unittest.TestCase): label = get_image_label('wac0000a1c4.uv.even', 'isis3') self.driver = LroLrocWacIsisLabelNaifSpiceDriver(label) def test_short_mission_name(self): assert self.driver.short_mission_name == 'lro' def test_intrument_id(self): assert self.driver.instrument_id == 'LRO_LROCWAC_UV' def test_ephemeris_start_time(self): with patch('ale.drivers.lro_drivers.spice.scs2e', return_value=321) as scs2e: np.testing.assert_almost_equal(self.driver.ephemeris_start_time, 321) scs2e.assert_called_with(-85, '1/274692469:15073') def test_detector_center_sample(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: Loading @@ -298,7 +294,6 @@ class test_wac_isis_naif(unittest.TestCase): gdpool.assert_called_with('INS-12345_BORESIGHT_SAMPLE', 0, 1) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_detector_center_line(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: Loading @@ -306,51 +301,53 @@ class test_wac_isis_naif(unittest.TestCase): gdpool.assert_called_with('INS-12345_BORESIGHT_LINE', 0, 1) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_usgscsm_distortion_model(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: distortion_model = self.driver.usgscsm_distortion_model assert distortion_model['radial']['coefficients'] == [1.0] gdpool.assert_called_with('INS-12345_OD_K', 0, 3) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_odtk(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: assert self.driver.odtk == [1.0] gdpool.assert_called_with('INS-12345_OD_K', 0, 3) bods2c.assert_called_with('LRO_LROCWAC_UV') with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool: assert self.driver.odtk == [-1.0] gdpool.assert_called_with('INS-85641_OD_K', 0, 3) def test_light_time_correction(self): assert self.driver.light_time_correction == 'LT+S' def test_exposure_duration(self): np.testing.assert_almost_equal(self.driver.exposure_duration, 0.04) def test_sensor_name(self): assert self.driver.sensor_name == "LUNAR RECONNAISSANCE ORBITER" def test_framelets_flipped(self): assert self.driver.framelets_flipped == False def test_sampling_factor(self): assert self.driver.sampling_factor == 4 def test_num_frames(self): assert self.driver.num_frames == 260 def test_framelet_height(self): assert self.driver.framelet_height == 16 def test_filter_number(self): assert self.driver.filter_number == 1 def test_fikid(self): assert self.driver.fikid == -85641 def test_pixel2focal_x(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0, -0.009])) as gdpool: assert self.driver.pixel2focal_x == [0, 0, -0.009] gdpool.assert_called_with('INS-85641_TRANSX', 0, 3) def test_pixel2focal_y(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0.009, 0])) as gdpool: assert self.driver.pixel2focal_y == [0, 0.009, 0] gdpool.assert_called_with('INS-85641_TRANSY', 0, 3) def test_detector_start_line(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([244])) as gdpool: assert self.driver.detector_start_line == 244 gdpool.assert_called_with('INS-85641_FILTER_OFFSET', 0, 3) # ========= Test WAC isislabel and isis spice driver ========= class test_wac_isis_isis(unittest.TestCase): Loading @@ -368,4 +365,13 @@ class test_wac_isis_isis(unittest.TestCase): np.testing.assert_almost_equal(self.driver.exposure_duration, 0.04) def test_usgscsm_distortion_model(self): assert self.driver.usgscsm_distortion_model == {'radial': {'coefficients': [[-0.024, -0.0007]]}} assert self.driver.usgscsm_distortion_model == {'radial': {'coefficients': [-0.0258246, -4.66139e-05, -0.000144651]}} def test_filter_number(self): assert self.driver.filter_number == 1 def test_fikid(self): assert self.driver.fikid == -85641 def test_odtk(self): assert self.driver.odtk == [-0.0258246, -4.66139e-05, -0.000144651] Loading
ale/drivers/lro_drivers.py +156 −3 Original line number Diff line number Diff line Loading @@ -892,6 +892,44 @@ class LroLrocWacIsisLabelIsisSpiceDriver(PushFrame, IsisLabel, IsisSpice, Radial return 2 @property def filter_number(self): """ Return the filter number from the cub label Returns ------- : int The filter number """ try: return self.label['IsisCube']['BandBin']['FilterNumber'][0] except: return self.label['IsisCube']['BandBin']['FilterNumber'] @property def fikid(self): """ Naif ID code of the filter dependent instrument codes. Expects ikid to be defined. This should be the integer Naif ID code for the instrument. Returns ------- : int Naif ID code used in calculating focal length """ if self.instrument_id == "LRO_LROCWAC_UV": base = -85640 elif self.instrument_id == "LRO_LROCWAC_VIS": base = -85630 fikid = base - self.filter_number return fikid @property def odtk(self): """ Loading @@ -902,7 +940,9 @@ class LroLrocWacIsisLabelIsisSpiceDriver(PushFrame, IsisLabel, IsisSpice, Radial : list Radial distortion coefficients. """ return [self.naif_keywords.get('INS{}_OD_K'.format(self.ikid), None)] coeffs = self.naif_keywords.get('INS{}_OD_K'.format(self.fikid), None) coeffs = [x * -1 for x in coeffs] return coeffs @property Loading Loading @@ -989,6 +1029,12 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def sensor_name(self): """ Returns ------- : String The name of the spacecraft """ return self.label['IsisCube']['Instrument']['SpacecraftName'] Loading @@ -1002,7 +1048,9 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial : list Radial distortion coefficients. """ return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 3).tolist() coeffs = spice.gdpool('INS{}_OD_K'.format(self.fikid), 0, 3).tolist() coeffs = [x * -1 for x in coeffs] return coeffs @property Loading @@ -1028,7 +1076,13 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def framelets_flipped(self): return self.label['IsisCube']['Instrument']['SpacecraftName'] == "Yes" """ Returns ------- : boolean True if framelets are flipped, else false """ return self.label['IsisCube']['Instrument']['DataFlipped'] == "Yes" @property Loading @@ -1041,12 +1095,111 @@ class LroLrocWacIsisLabelNaifSpiceDriver(PushFrame, IsisLabel, NaifSpice, Radial @property def num_frames(self): """ Number of frames in the image Returns ------- : int Number of frames in the image """ return self.image_lines // (self.framelet_height // self.sampling_factor) @property def framelet_height(self): """ Return the number of lines in a framelet. Returns ------- : int The number of lines in a framelet """ if self.instrument_id == "LRO_LROCWAC_UV": return 16 elif self.instrument_id == "LRO_LROCWAC_VIS": return 14 @property def filter_number(self): """ Return the filter number from the cub label Returns ------- : int The filter number """ try: return self.label['IsisCube']['BandBin']['FilterNumber'][0] except: return self.label['IsisCube']['BandBin']['FilterNumber'] @property def fikid(self): """ Naif ID code of the filter dependent instrument codes. Expects ikid to be defined. This should be the integer Naif ID code for the instrument. Returns ------- : int Naif ID code used in calculating focal length """ if self.instrument_id == "LRO_LROCWAC_UV": base = -85640 elif self.instrument_id == "LRO_LROCWAC_VIS": base = -85630 fikid = base - self.filter_number return fikid @property def pixel2focal_x(self): """ Expects fikid to be defined. This must be the integer Naif id code of the filter Returns ------- : list<double> detector to focal plane x """ return list(spice.gdpool('INS{}_TRANSX'.format(self.fikid), 0, 3)) @property def pixel2focal_y(self): """ Expects fikid to be defined. This must be the integer Naif id code of the filter Returns ------- : list<double> detector to focal plane y """ return list(spice.gdpool('INS{}_TRANSY'.format(self.fikid), 0, 3)) @property def detector_start_line(self): """ Filter-specific starting line Returns ------- : int Zero based Detector line corresponding to the first image line """ offset = list(spice.gdpool('INS{}_FILTER_OFFSET'.format(self.fikid), 0, 3)) try: # If multiple items are present, use the first one offset = offset[0] except (IndexError, TypeError): pass return super().detector_start_line + offset
tests/pytests/test_lro_drivers.py +34 −28 Original line number Diff line number Diff line Loading @@ -276,21 +276,17 @@ class test_wac_isis_naif(unittest.TestCase): label = get_image_label('wac0000a1c4.uv.even', 'isis3') self.driver = LroLrocWacIsisLabelNaifSpiceDriver(label) def test_short_mission_name(self): assert self.driver.short_mission_name == 'lro' def test_intrument_id(self): assert self.driver.instrument_id == 'LRO_LROCWAC_UV' def test_ephemeris_start_time(self): with patch('ale.drivers.lro_drivers.spice.scs2e', return_value=321) as scs2e: np.testing.assert_almost_equal(self.driver.ephemeris_start_time, 321) scs2e.assert_called_with(-85, '1/274692469:15073') def test_detector_center_sample(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: Loading @@ -298,7 +294,6 @@ class test_wac_isis_naif(unittest.TestCase): gdpool.assert_called_with('INS-12345_BORESIGHT_SAMPLE', 0, 1) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_detector_center_line(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: Loading @@ -306,51 +301,53 @@ class test_wac_isis_naif(unittest.TestCase): gdpool.assert_called_with('INS-12345_BORESIGHT_LINE', 0, 1) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_usgscsm_distortion_model(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: distortion_model = self.driver.usgscsm_distortion_model assert distortion_model['radial']['coefficients'] == [1.0] gdpool.assert_called_with('INS-12345_OD_K', 0, 3) bods2c.assert_called_with('LRO_LROCWAC_UV') def test_odtk(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: assert self.driver.odtk == [1.0] gdpool.assert_called_with('INS-12345_OD_K', 0, 3) bods2c.assert_called_with('LRO_LROCWAC_UV') with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool: assert self.driver.odtk == [-1.0] gdpool.assert_called_with('INS-85641_OD_K', 0, 3) def test_light_time_correction(self): assert self.driver.light_time_correction == 'LT+S' def test_exposure_duration(self): np.testing.assert_almost_equal(self.driver.exposure_duration, 0.04) def test_sensor_name(self): assert self.driver.sensor_name == "LUNAR RECONNAISSANCE ORBITER" def test_framelets_flipped(self): assert self.driver.framelets_flipped == False def test_sampling_factor(self): assert self.driver.sampling_factor == 4 def test_num_frames(self): assert self.driver.num_frames == 260 def test_framelet_height(self): assert self.driver.framelet_height == 16 def test_filter_number(self): assert self.driver.filter_number == 1 def test_fikid(self): assert self.driver.fikid == -85641 def test_pixel2focal_x(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0, -0.009])) as gdpool: assert self.driver.pixel2focal_x == [0, 0, -0.009] gdpool.assert_called_with('INS-85641_TRANSX', 0, 3) def test_pixel2focal_y(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0.009, 0])) as gdpool: assert self.driver.pixel2focal_y == [0, 0.009, 0] gdpool.assert_called_with('INS-85641_TRANSY', 0, 3) def test_detector_start_line(self): with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([244])) as gdpool: assert self.driver.detector_start_line == 244 gdpool.assert_called_with('INS-85641_FILTER_OFFSET', 0, 3) # ========= Test WAC isislabel and isis spice driver ========= class test_wac_isis_isis(unittest.TestCase): Loading @@ -368,4 +365,13 @@ class test_wac_isis_isis(unittest.TestCase): np.testing.assert_almost_equal(self.driver.exposure_duration, 0.04) def test_usgscsm_distortion_model(self): assert self.driver.usgscsm_distortion_model == {'radial': {'coefficients': [[-0.024, -0.0007]]}} assert self.driver.usgscsm_distortion_model == {'radial': {'coefficients': [-0.0258246, -4.66139e-05, -0.000144651]}} def test_filter_number(self): assert self.driver.filter_number == 1 def test_fikid(self): assert self.driver.fikid == -85641 def test_odtk(self): assert self.driver.odtk == [-0.0258246, -4.66139e-05, -0.000144651]